forked from Mirrors/openclonk
224 lines
5.0 KiB
C
224 lines
5.0 KiB
C
/*
|
|
Butterfly
|
|
Author: Randrian, Ringwaul, Clonkonaut
|
|
|
|
A small fluttering being.
|
|
*/
|
|
|
|
#include Library_Insect
|
|
|
|
local fly_anim, fly_anim_len;
|
|
|
|
public func Construction(...)
|
|
{
|
|
StartGrowth(15);
|
|
fly_anim_len = GetAnimationLength("Fly");
|
|
fly_anim = PlayAnimation("Fly", 1, Anim_Linear(0,0, fly_anim_len, 10, ANIM_Loop));
|
|
this.MeshTransformation = Trans_Rotate(270,1,1,1);
|
|
SetAction("Fly");
|
|
|
|
// Make butterflies a bit more colorful.
|
|
SetClrModulation(HSL(Random(256), 255, 100 + Random(60)));
|
|
|
|
lib_insect_max_dist = 300;
|
|
lib_insect_shy = true;
|
|
return _inherited(...);
|
|
}
|
|
|
|
/* Insect library */
|
|
|
|
local attraction;
|
|
|
|
private func GetAttraction(proplist coordinates)
|
|
{
|
|
// Sometimes I don't want to fly to a plant
|
|
if (!Random(7)) return false;
|
|
for (var plant in FindObjects(Find_Distance(150), Find_Or(Find_Func("IsPlant"), Find_ID(Grass)), Sort_Distance()))
|
|
{
|
|
if (!Random(4))
|
|
continue;
|
|
if (ObjectDistance(plant) < 20) // Too close
|
|
continue;
|
|
if (plant->GetCon() < 30) // Too small
|
|
continue;
|
|
if (plant->GBackSemiSolid()) // Under water or covered with solid material
|
|
continue;
|
|
var width = plant->GetObjWidth();
|
|
var height = plant->GetObjHeight();
|
|
coordinates.x = plant->GetX() + Random(width) - width / 2;
|
|
// The butterfly assumes that the main part of a plant is in the upper half (below could just be the trunk)
|
|
coordinates.y = plant->GetY() - Random(height)/2;
|
|
attraction = plant;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private func MissionComplete()
|
|
{
|
|
if (!attraction) return _inherited(...);
|
|
var wait = 20 + Random(80);
|
|
// Slow animation speed
|
|
fly_anim = PlayAnimation("Fly", 1, Anim_Linear(GetAnimationPosition(fly_anim), 0, fly_anim_len, 20, ANIM_Loop));
|
|
ScheduleCall(this, "RegularSpeed", wait);
|
|
SetCommand("Wait", nil,nil,nil,nil, wait);
|
|
}
|
|
|
|
private func MissionCompleteFailed()
|
|
{
|
|
attraction = nil;
|
|
}
|
|
|
|
private func RegularSpeed()
|
|
{
|
|
fly_anim = PlayAnimation("Fly", 1, Anim_Linear(GetAnimationPosition(fly_anim), 0, fly_anim_len, 10, ANIM_Loop));
|
|
}
|
|
|
|
// Hold the animation
|
|
private func SleepComplete()
|
|
{
|
|
fly_anim = PlayAnimation("Fly", 1, Anim_Linear(GetAnimationPosition(fly_anim), 0, fly_anim_len/2, 10, ANIM_Hold));
|
|
_inherited(...);
|
|
}
|
|
|
|
// Restart the animation
|
|
private func WakeUp()
|
|
{
|
|
fly_anim = PlayAnimation("Fly", 1, Anim_Linear(GetAnimationPosition(fly_anim), 0, fly_anim_len, 10, ANIM_Loop));
|
|
_inherited(...);
|
|
}
|
|
|
|
private func GetRestingPlace(proplist coordinates)
|
|
{
|
|
// Try to rest in nearby grass
|
|
for (var grass in FindObjects(Find_Distance(150), Find_ID(Grass), Sort_Distance()))
|
|
{
|
|
if (!Random(2))
|
|
{
|
|
coordinates.x = grass->GetX() + Random(4) - 2;
|
|
coordinates.y = grass->GetY() + 2;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private func Death(...)
|
|
{
|
|
_inherited(...);
|
|
fly_anim = PlayAnimation("Fly", 1, Anim_Linear(GetAnimationPosition(fly_anim), 0, fly_anim_len/2, 10, ANIM_Hold));
|
|
SetAction("Dead");
|
|
}
|
|
|
|
/* Movement */
|
|
|
|
private func CheckTurn()
|
|
{
|
|
if (GetEffect("Turning", this)) return;
|
|
if (GetDir() == DIR_Left && GetXDir() > 0)
|
|
AddEffect("Turning", this, 100, 1, this);
|
|
if (GetDir() == DIR_Right && GetXDir() < 0)
|
|
AddEffect("Turning", this, 100, 1, this);
|
|
}
|
|
|
|
private func FxTurningStart(object target, proplist effect, int temp)
|
|
{
|
|
if (temp) return;
|
|
effect.turn = 15;
|
|
effect.step = 0;
|
|
if (GetDir() == DIR_Right)
|
|
{
|
|
effect.turn = -15;
|
|
effect.step = 360;
|
|
}
|
|
SetAction("SlowFly");
|
|
}
|
|
|
|
private func FxTurningTimer(object target, proplist effect)
|
|
{
|
|
effect.step += effect.turn;
|
|
if (effect.step == 0 || effect.step == 360) return FX_Execute_Kill;
|
|
if (effect.step == 90)
|
|
{
|
|
effect.step = 285;
|
|
SetDir(DIR_Right);
|
|
}
|
|
if (effect.step == 270)
|
|
{
|
|
effect.step = 75;
|
|
SetDir(DIR_Left);
|
|
}
|
|
this.MeshTransformation = Trans_Mul(Trans_Rotate(270,1,1,1), Trans_Rotate(effect.step,0,0,1));
|
|
return FX_OK;
|
|
}
|
|
|
|
private func FxTurningStop(object target, proplist effect, int reason, bool temp)
|
|
{
|
|
if (temp) return;
|
|
this.MeshTransformation = Trans_Rotate(270,1,1,1);
|
|
SetAction("Fly");
|
|
}
|
|
|
|
/* Definition */
|
|
|
|
func SaveScenarioObject(props)
|
|
{
|
|
if (!inherited(props, ...)) return false;
|
|
props->Remove("ClrModulation"); // randomized in Initialize
|
|
SaveScenarioObjectAction(props);
|
|
return true;
|
|
}
|
|
|
|
local ActMap = {
|
|
Fly = {
|
|
Prototype = Action,
|
|
Name = "Fly",
|
|
Procedure = DFA_FLOAT,
|
|
Speed = 100,
|
|
Accel = 16,
|
|
Decel = 16,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 1,
|
|
Delay = 1,
|
|
NextAction = "Fly",
|
|
StartCall = "CheckTurn",
|
|
},
|
|
SlowFly = {
|
|
Prototype = Action,
|
|
Name = "SlowFly",
|
|
Procedure = DFA_FLOAT,
|
|
Speed = 30,
|
|
Accel = 6,
|
|
Decel = 6,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 1,
|
|
Delay = 1,
|
|
NextAction = "SlowFly",
|
|
},
|
|
Dead = {
|
|
Prototype = Action,
|
|
Name = "Dead",
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 1,
|
|
Delay = 1,
|
|
NoOtherAction = 1,
|
|
},
|
|
};
|
|
|
|
local Name = "Butterfly";
|
|
local MaxEnergy = 40000;
|
|
local MaxBreath = 125;
|
|
local Placement = 2;
|
|
local NoBurnDecay = true;
|
|
local BorderBound = C4D_Border_Sides | C4D_Border_Top | C4D_Border_Bottom;
|
|
local ContactCalls = true;
|
|
|
|
public func Definition(proplist def)
|
|
{
|
|
def.PictureTransformation = Trans_Mul(Trans_Translate(400, 600, 0), Trans_Scale(1400), Trans_Rotate(20, 1, 0, 0), Trans_Rotate(40, 0, 1, 0));
|
|
}
|
|
|