openclonk/planet/Objects.ocd/Animals.ocd/Wipf.ocd/Script.c

742 lines
14 KiB
C

/**
Wipf
A furry creature which is the clonk's biggest friend.
@author Maikel
*/
// Wipfs can be carried by the clonk.
#include Library_CarryHeavy
public func Initialize()
{
// Add an effect to control the wipf's activities.
AddEffect("IntActivity", this, 1, 10, this);
return;
}
public func Place(int amount, proplist area)
{
if (this != Wipf)
return;
if (!area)
area = Shape->LandscapeRectangle();
var wipfs = [];
for (var i = 0 ; i < amount ; i++)
{
var position = FindLocation(Loc_InArea(area), Loc_Wall(CNAT_Bottom), Loc_Or(Loc_Sky(), Loc_Tunnel()));
if (position)
{
var wipf = CreateObjectAbove(Wipf, position.x, position.y, NO_OWNER);
if (wipf->Stuck())
wipf->RemoveObject();
if (wipf)
PushBack(wipfs, wipf);
}
}
return wipfs;
}
/*-- Activity --*/
public func FxIntActivityStart(object target, proplist effect, int temp)
{
if (temp)
return FX_OK;
// Set the correct interval.
effect.Interval = 10;
// Set action and a face a random direction.
SetAction("Stand");
SetDir([DIR_Left, DIR_Right][Random(2)]);
return FX_OK;
}
public func FxIntActivityTimer(object target, proplist effect, int time)
{
// Don't do anything if contained.
if (Contained())
return FX_OK;
// Actions when standing.
if (IsStanding())
{
// Start digging if above diggable material.
var mat = GetMaterial(0, 8);
if (!Random(100) && GetMaterialVal("DigFree", "Material", mat))
{
SetAction("Dig");
SetDigDirection(Random(2) * 2 - 1, 1);
return FX_OK;
}
// Start walking from time to time.
if (!Random(10))
{
SetAction("Walk");
SetComDir([COMD_Left, COMD_Right][Random(2)]);
return FX_OK;
}
return FX_OK;
}
// Actions on walking.
if (IsWalking())
{
// Change direction of walking from time to time.
if (!Random(5))
{
SetComDir([COMD_Left, COMD_Right][Random(2)]);
return FX_OK;
}
// Do some random jumps.
if (!Random(20))
{
Jump();
return FX_OK;
}
// Stop walking from time to time.
if (!Random(20) && GetComDir() != COMD_Stop)
{
SetComDir(COMD_Stop);
return FX_OK;
}
// Start standing when com dir is stop and speed is zero.
if (GetComDir() == COMD_Stop && GetYDir() == 0)
{
SetAction("Stand");
return FX_OK;
}
return FX_OK;
}
// Actions on digging.
if (IsDigging())
{
// Change digging direction.
if (!Random(3))
{
var dir = GetDigDirection();
if (!dir)
return FX_OK;
var xdir = dir.x + RandomX(-this.ActMap.Dig.Speed, this.ActMap.Dig.Speed) / 3;
var ydir = dir.y + RandomX(-this.ActMap.Dig.Speed, this.ActMap.Dig.Speed) / 3;
ydir = BoundBy(ydir, -Abs(xdir), Abs(xdir));
SetDigDirection(xdir, ydir);
return FX_OK;
}
// Stop digging from time to time.
if (!Random(3) && GetComDir() != COMD_Stop)
{
SetComDir(COMD_Stop);
return FX_OK;
}
// Start standing when com dir is stop and speed is zero.
if (GetComDir() == COMD_Stop && GetYDir() == 0)
{
SetAction("Stand");
return FX_OK;
}
return FX_OK;
}
// Actions on swimming.
if (IsSwimming())
{
// Swim up if under water.
if (GBackLiquid(0, -4))
{
SetComDir(COMD_Up);
return FX_OK;
}
// Change direction of walking from time to time.
if (!Random(5))
{
SetComDir([COMD_Left, COMD_Right][Random(2)]);
return FX_OK;
}
// If at an edge do jump out of the liquid.
if (!GBackLiquid(0, -6))
{
if (((GBackSolid(16, 2) || GBackSolid(24, 2)) && PathFree(GetX(), GetY(), GetX() + 16, GetY() - 16) && GetDir() == DIR_Right) ||
((GBackSolid(-16, 2) || GBackSolid(-24, 2)) && PathFree(GetX(), GetY(), GetX() - 16, GetY() - 16) && GetDir() == DIR_Left))
{
SetPosition(GetX(), GetY() - 2);
Jump();
}
return FX_OK;
}
}
return FX_OK;
}
/*-- Standing --*/
public func IsStanding()
{
return GetAction() == "Stand";
}
public func StartStand()
{
if (!GetEffect("IntStanding", this))
AddEffect("IntStanding", this, 1, 1, this);
return;
}
public func StopStand()
{
if (!IsStanding())
RemoveEffect("IntStanding", this);
return;
}
public func FxIntStandingStart(object target, proplist effect, int temp)
{
if (temp)
return FX_OK;
SetComDir(COMD_Stop);
effect.standing_anim = ["Idle", "Idle2"][Random(2)];
effect.anim_number = PlayAnimation(effect.standing_anim, 5, Anim_Linear(0, 0, GetAnimationLength(effect.standing_anim), 35, ANIM_Hold), Anim_Const(1000));
return FX_OK;
}
public func FxIntStandingTimer(object target, proplist effect, int time)
{
return FX_OK;
}
public func FxIntStandingStop(object target, proplist effect, int reason, bool temp)
{
if (temp)
return FX_OK;
StopAnimation(effect.anim_number);
return FX_OK;
}
/*-- Walking --*/
public func IsWalking()
{
return GetAction() == "Walk";
}
public func StartWalk()
{
if (!GetEffect("IntWalking", this))
AddEffect("IntWalking", this, 1, 1, this);
return;
}
public func StopWalk()
{
if (!IsWalking())
RemoveEffect("IntWalking", this);
return;
}
public func FxIntWalkingStart(object target, proplist effect, int temp)
{
if (temp)
return FX_OK;
var dir = -1;
if (GetComDir() == COMD_Right)
dir = +1;
effect.anim_number = PlayAnimation("Hop", 5, Anim_X(0, 0, GetAnimationLength("Hop"), 50 * dir), Anim_Const(1000));
return FX_OK;
}
public func FxIntWalkingTimer(object target, proplist effect, int time)
{
if ((time % 6) == 0)
Footstep();
return FX_OK;
}
public func FxIntWalkingStop(object target, proplist effect, int reason, bool temp)
{
if (temp)
return FX_OK;
StopAnimation(effect.anim_number);
return FX_OK;
}
private func Footstep()
{
if (GetMaterialVal("DigFree", "Material", GetMaterial(0, 7)) == 0)
return;
var dir = Sign(GetXDir());
var clr = GetAverageTextureColor(GetTexture(0, 7));
var particles =
{
Prototype = Particles_Dust(),
Size = PV_KeyFrames(0, 0, 3, 100, 7, 1000, 5),
R = (clr >> 16) & 0xff,
G = (clr >> 8) & 0xff,
B = clr & 0xff,
};
CreateParticle("Dust", PV_Random(dir * -2, dir * -1), 5, PV_Random(dir * 2, dir * 1), PV_Random(-2, -3), PV_Random(12, 24), particles, 5);
return;
}
/*-- Swimming --*/
public func IsSwimming()
{
return GetAction() == "Swim";
}
public func StartSwim()
{
if (!GetEffect("IntSwimming", this))
AddEffect("IntSwimming", this, 1, 1, this);
return;
}
public func StopSwim()
{
if (!IsSwimming())
RemoveEffect("IntSwimming", this);
return;
}
public func FxIntSwimmingStart(object target, proplist effect, int temp)
{
if (temp)
return FX_OK;
var dir = -1;
if (GetComDir() == COMD_Right)
dir = +1;
effect.anim_number = PlayAnimation("Swim", 5, Anim_X(0, 0, GetAnimationLength("Swim"), 40 * dir), Anim_Const(1000));
return FX_OK;
}
public func FxIntSwimmingTimer(object target, proplist effect, int time)
{
return FX_OK;
}
public func FxIntSwimmingStop(object target, proplist effect, int reason, bool temp)
{
if (temp)
return FX_OK;
StopAnimation(effect.anim_number);
return FX_OK;
}
/*-- Jumping --*/
public func IsJumping()
{
return GetAction() == "Jump";
}
public func StartJump()
{
if (!GetEffect("IntJumping", this))
AddEffect("IntJumping", this, 1, 1, this);
return;
}
public func StopJump()
{
if (!IsJumping())
RemoveEffect("IntJumping", this);
return;
}
public func FxIntJumpingStart(object target, proplist effect, int temp)
{
if (temp)
return FX_OK;
var dir = -1;
if (GetDir() == DIR_Right)
dir = +1;
effect.anim_number = PlayAnimation("Hop", 5, Anim_X(0, 0, GetAnimationLength("Hop"), 50 * dir), Anim_Const(1000));
return FX_OK;
}
public func FxIntJumpingTimer(object target, proplist effect, int time)
{
return FX_OK;
}
public func FxIntJumpingStop(object target, proplist effect, int reason, bool temp)
{
if (temp)
return FX_OK;
StopAnimation(effect.anim_number);
return FX_OK;
}
public func Jump(int xdir, int ydir)
{
SetAction("Jump");
if (xdir == nil)
xdir = 10;
if (GetDir() == DIR_Left)
xdir *= -1;
if (ydir == nil)
ydir = -20;
SetSpeed(GetXDir() + xdir, ydir - GetXDir() / 2);
if (GetMaterialVal("DigFree", "Material", GetMaterial(0, 7)) != 0)
{
for (var c = 0; c < 5; ++c)
{
var dir = Sign(GetXDir());
var clr = GetAverageTextureColor(GetTexture(0, 7));
var particles =
{
Prototype = Particles_Dust(),
R = (clr >> 16) & 0xff,
G = (clr >> 8) & 0xff,
B = clr & 0xff,
};
CreateParticle("Dust", PV_Random(dir * -2, dir * -1), 5, PV_Random(dir * 2, dir * 1), PV_Random(-2, -3), PV_Random(36, 2 * 36), particles, 5);
}
}
return;
}
/*-- Digging --*/
public func IsDigging()
{
return GetAction() == "Dig";
}
public func StartDig()
{
SetComDir(COMD_None);
if (!GetEffect("IntDigging", this))
AddEffect("IntDigging", this, 1, 1, this);
return;
}
public func StopDig()
{
if (!IsDigging())
RemoveEffect("IntDigging", this);
return;
}
public func SetDigDirection(int x, int y)
{
var effect = GetEffect("IntDigging", this);
if (effect)
{
effect.dig_x = x;
effect.dig_y = y;
}
return;
}
public func GetDigDirection()
{
var effect = GetEffect("IntDigging", this);
if (effect)
{
return { x = effect.x_dir, y = effect.y_dir };
}
return;
}
public func FxIntDiggingStart(object target, proplist effect, int temp)
{
if (temp)
return FX_OK;
var dir = -1;
if (GetDir() == DIR_Right)
dir = +1;
effect.anim_number = PlayAnimation("Dig", 5, Anim_X(0, 0, GetAnimationLength("Dig"), 50 * dir), Anim_Const(1000));
effect.x_dir = 0;
effect.y_dir = 0;
return FX_OK;
}
public func FxIntDiggingTimer(object target, proplist effect, int time)
{
if (GetComDir() == COMD_Stop)
{
SetXDir(0);
SetYDir(0);
return FX_OK;
}
var xdir = effect.dig_x * this.ActMap.Dig.Speed;
var ydir = effect.dig_y * this.ActMap.Dig.Speed;
var speed = Max(1, Distance(xdir, ydir));
xdir = xdir * this.ActMap.Dig.Speed / speed;
ydir = ydir * this.ActMap.Dig.Speed / speed;
if (xdir != effect.x_dir || ydir != effect.y_dir)
{
effect.x_dir = xdir;
effect.y_dir = ydir;
SetXDir(xdir, 100);
SetYDir(ydir, 100);
}
return FX_OK;
}
public func FxIntDiggingStop(object target, proplist effect, int reason, bool temp)
{
if (temp)
return FX_OK;
StopAnimation(effect.anim_number);
return FX_OK;
}
public func DigOutObject(object obj)
{
// Wipf's do not dig out bucket materials like earth.
if (obj->~IsBucketMaterial())
return obj->RemoveObject();
return;
}
/*-- Eating --*/
public func IsEating()
{
return GetAction() == "Eat";
}
public func Eat(object food)
{
if (IsWalking() || IsStanding())
{
DoEnergy(food->~NutritionalValue());
food->RemoveObject();
Sound("Clonk::Action::Munch?");
SetAction("Eat");
}
return;
}
public func StartEat()
{
PlayAnimation("Nibble", 5, Anim_Linear(0, 0, GetAnimationLength("Nibble"), 36, ANIM_Remove), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
return;
}
/*-- Dead --*/
public func IsDead()
{
return GetAction() == "Dead";
}
protected func Death(int killed_by)
{
Sound("Animals::Wipf::Aroof");
return;
}
public func StartDead()
{
PlayAnimation("Dead", 5, Anim_Linear(0, 0, GetAnimationLength("Dead"), 16, ANIM_Hold), Anim_Const(1000));
return;
}
/*-- Being Carried --*/
public func Entrance()
{
SetAction("Stand");
return;
}
public func Departure()
{
SetAction("Jump");
return;
}
/*-- Other Actions --*/
protected func CatchBlow()
{
if (IsDead())
return;
Sound("Animals::Wipf::Weep?");
return;
}
/*-- Carry Heavy --*/
public func GetCarryTransform(clonk)
{
if (GetCarrySpecial(clonk))
return Trans_Mul(Trans_Scale(1300), Trans_Rotate(180, 0, 1, 0), Trans_Rotate(180, 1, 0, 0), Trans_Rotate(20, 0, 0, 1), Trans_Translate(0, -5000, 0));
return Trans_Mul(Trans_Scale(1300), Trans_Rotate(90, 1, 0, 0), Trans_Rotate(160, 0, 0, 1));
}
public func GetCarryPhase() { return 450; }
public func GetCarryBone() { return "spine lower"; }
/*-- DefCore --*/
local Name = "$Name$";
local Description = "$Description$";
local MaxEnergy = 50000;
local MaxBreath = 720;
local NoBurnDecay = true;
local Collectible = true;
local ContactIncinerate = 10;
protected func Definition(proplist def)
{
def.MeshTransformation = Trans_Mul(Trans_Scale(1300), Trans_Translate(0, 2500, 0));
def.PictureTransformation = Trans_Mul(Trans_Rotate(65, 0, 1, 0), Trans_Rotate(-20, 0, 0, 1));
return _inherited(def, ...);
}
/*-- ActMap --*/
local ActMap = {
Walk = {
Prototype = Action,
Name = "Walk",
Procedure = DFA_WALK,
Accel = 16,
Decel = 24,
Speed = 200,
Directions = 2,
FlipDir = 1,
Length = 1,
Delay = 0,
X = 0,
Y = 0,
Wdt = 14,
Hgt = 14,
StartCall = "StartWalk",
AbortCall = "StopWalk",
EndCall = "StopWalk",
InLiquidAction = "Swim",
},
Stand = {
Prototype = Action,
Name = "Stand",
Procedure = DFA_THROW,
Directions = 2,
FlipDir = 1,
Length = 1,
Delay = 0,
X = 0,
Y = 0,
Wdt = 14,
Hgt = 14,
StartCall = "StartStand",
AbortCall = "StopStand",
EndCall = "StopStand",
InLiquidAction = "Swim",
},
Dig = {
Prototype = Action,
Name = "Dig",
Procedure = DFA_DIG,
Accel = 10,
Decel = 10,
Speed = 80,
Directions = 2,
FlipDir = 1,
Length = 28,
Delay = 1,
X = 0,
Y = 0,
Wdt = 14,
Hgt = 14,
DigFree = 8,
NextAction = "Dig",
StartCall = "StartDig",
AbortCall = "StopDig",
InLiquidAction = "Swim",
},
Swim = {
Prototype = Action,
Name = "Swim",
Procedure = DFA_SWIM,
Speed = 80,
Accel = 8,
Decel = 12,
Directions = 2,
FlipDir = 1,
Length = 1,
Delay = 0,
X = 0,
Y = 0,
Wdt = 14,
Hgt = 14,
StartCall = "StartSwim",
AbortCall = "StopSwim",
EndCall = "StopSwim",
},
Jump = {
Prototype = Action,
Name = "Jump",
Procedure = DFA_FLIGHT,
Speed = 240,
Accel = 14,
Directions = 2,
FlipDir = 1,
Length = 1,
Delay = 0,
X = 0,
Y = 0,
Wdt = 14,
Hgt = 14,
PhaseCall = "CheckStuck",
StartCall = "StartJump",
EndCall = "StopJump",
AbortCall = "StopJump",
InLiquidAction = "Swim",
},
Dead = {
Prototype = Action,
Name = "Dead",
Directions = 2,
X = 0,
Y = 0,
Wdt = 14,
Hgt = 14,
Length = 1,
Delay = 0,
NextAction = "Hold",
StartCall = "StartDead",
NoOtherAction = 1,
ObjectDisabled = 1,
},
Eat = {
Prototype = Action,
Name = "Eat",
Procedure = DFA_THROW,
Directions = 2,
Length = 1,
Delay = 36,
X = 0,
Y = 0,
Wdt = 14,
Hgt = 14,
StartCall = "StartEat",
NextAction = "Walk",
InLiquidAction = "Swim",
},
};