Added Insect Library.

Basic behaviour for insects!
Controls
Clonkonaut 2015-07-23 13:30:35 +02:00
parent cdb4a1b153
commit ffe1090da0
2 changed files with 252 additions and 0 deletions

View File

@ -0,0 +1,4 @@
[DefCore]
id=Library_Insect
Version=6,1
Category=C4D_StaticBack

View File

@ -0,0 +1,248 @@
/**
Insect Library
Some standard behaviour to flying insects. Action with DFA_FLOAT required.
If at any time you want to block insect behaviour, set a "Wait" command (but beware of in liquid check still be made).
@author Clonkonaut
--*/
/** Maximum travelling distance for one 'mission' (random target point).
0 = a random point of the whole landscape
*/
local lib_insect_max_dist = 0;
/** Set true if the insect does its business at night.
If there's no day/night cycle (Time object), all insects never sleep.
*/
local lib_insect_nocturnal = false;
/** If true, the insect will flee from clonks.
*/
local lib_insect_shy = false;
/** Overload to define any kind of 'sitting' state for the insect (e.g. a certain action).
Must resolve itself otherwise the insect will cease to do anything.
*/
private func IsSitting() {}
/** Return true when the insect is asleep.
*/
public func IsSleeping()
{
// Already returns true when the insect is still searching for a resting place.
return lib_insect_going2sleep || lib_insect_sleeping;
}
/** What to do when arrived at a random target point.
Overload as necessary.
*/
private func MissionComplete()
{
// Set a dummy command. After it finishes, regular Activity() behaviour will kick in.
SetCommand("Wait", nil,nil,nil,nil, 20 + Random(80));
}
/** Overload to define any kind of interesting spot for the insect. Return true if spot was found.
coordinates.x and coordinates.y will be coordinates to fly to.
*/
private func GetAttraction(proplist coordinates) { return false; }
/** Default sleeping behaviour: Move to a sleeping place and stay there.
Overload as necessary.
*/
private func Sleep()
{
if (CheckDanger()) return;
// Sleeping phase just begun
if (!lib_insect_going2sleep)
{
// Cancel current mission.
SetCommand("None");
lib_insect_going2sleep = true;
}
// As place to sleep is needed
if (!GetCommand() && !lib_insect_sleeping)
{
var coordinates = {x = 0, y = 0};
// Priority is always to move to a resting place
if (!GetRestingPlace(coordinates))
{
// Default place is just at ground level
coordinates.x = BoundBy(GetX() + Random(10) - 5, 10, LandscapeWidth()-10);
coordinates.y = GetHorizonHeight(coordinates.x);
}
SetCommand("MoveTo", nil, coordinates.x, coordinates.y, nil, true);
AppendCommand("Call", this, nil,nil,nil,nil, "SleepComplete");
}
}
/** What to do when arrived at a resting place.
Overload as necessary but be sure to set lib_insect_sleeping true.
*/
private func SleepComplete()
{
SetCommand("None");
SetComDir(COMD_None);
SetXDir(0);
SetYDir(0);
lib_insect_sleeping = true;
}
/** Overload to define any kind of resting place for the insect. Return true if place was found.
coordinates.x and coordinates.y will be coordinates to fly to.
*/
private func GetRestingPlace(proplist coordinates) { return false; }
/** Called once when the insect just wakes up.
*/
private func WakeUp()
{
SetCommand("None");
lib_insect_going2sleep = false;
lib_insect_sleeping = false;
}
// Moves towards a resting place
local lib_insect_going2sleep = false;
// Arrived at resting place and sleeps
local lib_insect_sleeping = false;
// Is fleeing from a danger (interrupts sleep)
local lib_insect_escape = false;
/* Contact calls */
/** Overloaded as necessary. As well as other directions.
Beware of the special characteristic of ContactBottom.
*/
private func ContactBottom()
{
if (lib_insect_going2sleep) return SleepComplete();
SetCommand("None");
SetComDir(COMD_Up);
}
private func ContactTop()
{
if (lib_insect_sleeping) return;
SetCommand("None");
SetComDir(COMD_Down);
}
private func ContactLeft()
{
if (lib_insect_sleeping) return;
SetCommand("None");
SetComDir(COMD_Right);
}
private func ContactRight()
{
if (lib_insect_sleeping) return;
SetCommand("None");
SetComDir(COMD_Left);
}
/* Internal stuff */
private func Initialize()
{
AddTimer("Activity");
SetComDir(COMD_None);
MoveToTarget();
}
private func Activity()
{
if (Contained()) return;
// It's assumed being underwater is bad for insects
if (InLiquid())
{
if (GetCommand()) SetCommand("None");
return SetComDir(COMD_Up);
}
// Sitting? Wait.
if (IsSitting()) return;
// Go somewhere if no mission
if (!GetCommand())
{
// Escape ended
if (lib_insect_escape) lib_insect_escape = false;
// Go to sleep?
if (HasDayNightCycle())
{
if (!lib_insect_nocturnal && IsNight())
return Sleep();
if (lib_insect_nocturnal && IsDay())
return Sleep();
if (IsSleeping())
WakeUp();
}
if (!CheckDanger()) MoveToTarget();
}
}
// Set a new mission
private func MoveToTarget()
{
var coordinates = {x = 0, y = 0};
// Priority is always to move to an interesting spot
if (!GetAttraction(coordinates))
{
if (!lib_insect_max_dist)
coordinates.x = Random(LandscapeWidth());
else
{
coordinates.x = GetX();
// Prevent insect from flying around at borders too much
if (GetX() < lib_insect_max_dist/2) coordinates.x += lib_insect_max_dist/2;
if (GetX() > LandscapeWidth() - lib_insect_max_dist/2) coordinates.x -= lib_insect_max_dist/2;
coordinates.x = BoundBy(coordinates.x + Random(lib_insect_max_dist) - lib_insect_max_dist/2, 10, LandscapeWidth()-10);
}
coordinates.y = GetHorizonHeight(coordinates.x)- 30 - Random(60);
}
SetCommand("MoveTo", nil, coordinates.x, coordinates.y, nil, true);
AppendCommand("Call", this, nil,nil,nil,nil, "MissionComplete");
}
private func GetHorizonHeight(int x)
{
var height;
while (height < LandscapeHeight() && !GBackSemiSolid(AbsX(x), AbsY(height)))
height += 10;
return height;
}
private func CheckDanger()
{
if (!lib_insect_shy) return false;
// Just flee from the first found clonk
var danger_zone = 40;
if (IsSleeping()) danger_zone /= 2;
var clonk = FindObject(Find_Distance(danger_zone), Find_OCF(OCF_CrewMember), Find_OCF(OCF_Alive), Find_NoContainer());
if (clonk)
{
Flee(clonk);
return true;
}
return false;
}
private func Flee(object from)
{
if (!from) return;
if (IsSleeping()) WakeUp();
// Find a point that's somewhere up and away from the object
var x,y;
y = GetY() - 50 + Random(20);
if (GetX() < from->GetX())
x = GetX() + 50 - Random(20);
else
x = GetX() - 50 + Random(20);
x = BoundBy(x, 10, LandscapeWidth()-10);
y = BoundBy(y, 10, LandscapeHeight()-10);
SetCommand("MoveTo", nil, x, y, nil, true);
lib_insect_escape = true;
}