forked from Mirrors/openclonk
new animal: puka
Currently only walks around and randomly electrocutes you.shapetextures
parent
6fe58fd878
commit
619fc0b65a
|
@ -0,0 +1,15 @@
|
|||
Sounds by ala
|
||||
-------------
|
||||
CC Attribution 3.0 license (http://creativecommons.org/licenses/by/3.0/).
|
||||
|
||||
PukaGulp
|
||||
PukaHiss1-2
|
||||
PukaHurt1-3b
|
||||
|
||||
Other sounds
|
||||
-------------
|
||||
PukaTeleportIn/Out based on work by parnellij (CC0) - http://www.freesound.org/people/parnellij/sounds/74892/
|
||||
|
||||
Model
|
||||
-----
|
||||
Model, texture and most animations by pluto.
|
|
@ -0,0 +1,21 @@
|
|||
[DefCore]
|
||||
id=Puka
|
||||
Version=6,0
|
||||
Category=C4D_Living
|
||||
Width=15
|
||||
Height=10
|
||||
Offset=-7,-5
|
||||
Vertices=7
|
||||
VertexX= 0, 0,0,-3,3,-3, 3
|
||||
VertexY= 0,-3,4, 1,1,-1,-1
|
||||
VertexCNAT=0, 4,8, 1,2, 1, 2
|
||||
VertexFriction=300,300,100,300,300,300,300
|
||||
Mass=30
|
||||
ContactCalls=1
|
||||
NoGet=1
|
||||
Float=0
|
||||
BorderBound=1
|
||||
StretchGrowth=1
|
||||
IncompleteActivity=1
|
||||
Oversize=1
|
||||
Pathfinder=1
|
Binary file not shown.
|
@ -0,0 +1,43 @@
|
|||
material Puka
|
||||
{
|
||||
receive_shadows on
|
||||
technique
|
||||
{
|
||||
pass
|
||||
{
|
||||
ambient 1.0 1.0 1.0 1.0
|
||||
diffuse 1.0 1.0 1.0 1.0
|
||||
specular 0.0 0.0 0.0 1.0 12.5
|
||||
emissive 0.0 0.0 0.0 1.0
|
||||
|
||||
texture_unit
|
||||
{
|
||||
texture puka.png
|
||||
tex_address_mode wrap
|
||||
filtering trilinear
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
material Puka2
|
||||
{
|
||||
receive_shadows on
|
||||
technique
|
||||
{
|
||||
pass
|
||||
{
|
||||
ambient 1.0 1.0 1.0 1.0
|
||||
diffuse 1.0 1.0 1.0 1.0
|
||||
specular 0.0 0.0 0.0 1.0 12.5
|
||||
emissive 0.0 0.0 0.0 1.0
|
||||
|
||||
texture_unit
|
||||
{
|
||||
texture puka2.png
|
||||
tex_address_mode wrap
|
||||
filtering trilinear
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,904 @@
|
|||
/**
|
||||
Puka
|
||||
Cute little electronically active creature.
|
||||
*/
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
|
||||
// For the teleport trajectory.
|
||||
local current_high_x, current_high_y;
|
||||
local current_ground_x, current_ground_y;
|
||||
|
||||
// Animations.
|
||||
local turn_angle;
|
||||
|
||||
// The closest enemy that has been found.
|
||||
local enemy;
|
||||
// Some positions near water that might be good teleport targets.
|
||||
local water_positions;
|
||||
local water_cycle;
|
||||
|
||||
public func Place(int amount, proplist rectangle, proplist settings)
|
||||
{
|
||||
var max_tries = 3 * amount;
|
||||
var loc_area = nil;
|
||||
if (rectangle) loc_area = Loc_InArea(rectangle);
|
||||
var animal;
|
||||
|
||||
while ((amount > 0) && (--max_tries > 0))
|
||||
{
|
||||
// Try to find walkable ground near water.
|
||||
var water_spot = FindLocation(Loc_Material("Water"));
|
||||
var ground_spot = nil;
|
||||
if (water_spot)
|
||||
{
|
||||
var water_rectangle = Shape->Rectangle(water_spot.x - 200, water_spot.y - 200, 400, 400);
|
||||
// Make sure the position is inside the required target rectangle.
|
||||
water_rectangle = Shape->Intersect(water_rectangle, rectangle)->GetBoundingRectangle();
|
||||
ground_spot = FindLocation(Loc_Wall(CNAT_Bottom), Loc_Or(Loc_Sky(), Loc_Tunnel()), Loc_Space(20, CNAT_Top), Loc_InArea(water_rectangle));
|
||||
}
|
||||
|
||||
// If no hip and cool spot found, just get some generic spot.
|
||||
if (!ground_spot)
|
||||
ground_spot = FindLocation(Loc_Wall(CNAT_Bottom), Loc_Or(Loc_Sky(), Loc_Tunnel()), Loc_Space(20, CNAT_Top), loc_area);
|
||||
if (!ground_spot) continue;
|
||||
|
||||
animal = CreateObjectAbove(this, ground_spot.x, ground_spot.y, NO_OWNER);
|
||||
if (!animal) continue;
|
||||
|
||||
if (animal->Stuck())
|
||||
{
|
||||
animal->RemoveObject();
|
||||
continue;
|
||||
}
|
||||
--amount;
|
||||
}
|
||||
return animal;
|
||||
}
|
||||
|
||||
public func Construction()
|
||||
{
|
||||
turn_angle = 0;
|
||||
water_positions = [];
|
||||
water_cycle = 0;
|
||||
|
||||
AddTimer("ExecuteActivity", 10);
|
||||
AddTimer("UpdateEnemy", 30);
|
||||
AddTimer("CheckTurn", 10);
|
||||
SetAction("Walk");
|
||||
SetComDir(COMD_Stop);
|
||||
if (Random(2)) SetDir(DIR_Left);
|
||||
else SetDir(DIR_Right);
|
||||
|
||||
SetCreatureControlled();
|
||||
|
||||
// A rare blue Puka?
|
||||
if (!Random(5))
|
||||
SetMeshMaterial("Puka2");
|
||||
return true;
|
||||
}
|
||||
|
||||
public func CatchBlow(int damage, object from)
|
||||
{
|
||||
Schedule(this, "Sound(\"PukaHurt*\")", RandomX(5, 20));
|
||||
}
|
||||
|
||||
private func CheckStuck()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private func StartSwim()
|
||||
{
|
||||
this.Activity = this.ActivitySwimming;
|
||||
}
|
||||
|
||||
private func ClearActivity()
|
||||
{
|
||||
this.Activity = nil;
|
||||
}
|
||||
|
||||
private func StartSleep()
|
||||
{
|
||||
this.Activity = this.ActivitySleeping;
|
||||
}
|
||||
|
||||
private func StopSwim()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private func EndSwim()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private func StartJump()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private func EndJump()
|
||||
{
|
||||
RemoveEffect("JumpCheck", this);
|
||||
}
|
||||
|
||||
private func StopWalk()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private func StartScale()
|
||||
{
|
||||
this.Activity = this.ActivityScaling;
|
||||
}
|
||||
|
||||
private func StopScale()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private func StartHangle()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private func StopHangle()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public func Death()
|
||||
{
|
||||
AddEffect("IntDeathSparks", this, 1, 1, this);
|
||||
SoundAt("PukaDie");
|
||||
}
|
||||
|
||||
private func FxIntDeathSparksStart(object target, effect fx, temp)
|
||||
{
|
||||
if (temp) return;
|
||||
|
||||
fx.particles =
|
||||
{
|
||||
Prototype = Particles_ElectroSpark1(),
|
||||
G = 150, B = 150, Alpha = PV_Linear(255, 0),
|
||||
Stretch = 2000,
|
||||
DampingX = 999, DampingY = 999,
|
||||
ForceY = -GetGravity()
|
||||
};
|
||||
}
|
||||
|
||||
private func FxIntDeathSparksTimer(object target, effect fx, int time)
|
||||
{
|
||||
CreateParticle("ElectroSpark", PV_Random(-5, 5), PV_Random(-5, 5),
|
||||
PV_Random(-20, 20), PV_Random(-5, 10),
|
||||
PV_Random(2, 10), fx.particles, 20);
|
||||
if (time > this.ActMap.Dead.Length) return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
private func FxIntDeathSparksStop(object target, effect fx, int reason, temp)
|
||||
{
|
||||
if (temp) return;
|
||||
fx.particles.Stretch *= 2;
|
||||
CreateParticle("ElectroSpark", PV_Random(-5, 5), PV_Random(-5, 5),
|
||||
PV_Random(-60, 60), PV_Random(-60, 60),
|
||||
PV_Random(2, 10), fx.particles, 800);
|
||||
if (this) RemoveObject();
|
||||
return 1;
|
||||
}
|
||||
|
||||
private func Jump()
|
||||
{
|
||||
SetAction("Jump");
|
||||
SetSpeed(GetXDir(), -10 - GetXDir());
|
||||
}
|
||||
|
||||
private func StartWalk()
|
||||
{
|
||||
// Coming from a swim? Remember this location.
|
||||
if (this.Activity == this.ActivitySwimming)
|
||||
{
|
||||
SetComDir(COMD_Stop);
|
||||
|
||||
water_positions[water_cycle] = [GetX(), GetY()];
|
||||
water_cycle = (water_cycle + 1) % 5;
|
||||
}
|
||||
|
||||
this.Activity = this.ActivityWalking;
|
||||
}
|
||||
|
||||
private func ActivityScaling()
|
||||
{
|
||||
if (!Random(10)) return TryStartTeleport();
|
||||
|
||||
if (!Random(2))
|
||||
{
|
||||
if (Random(3)) SetComDir(COMD_Up);
|
||||
else SetComDir(COMD_Down);
|
||||
}
|
||||
}
|
||||
|
||||
private func ActivitySwimming()
|
||||
{
|
||||
if (!Random(6))
|
||||
{
|
||||
Turn(nil, true);
|
||||
|
||||
if (GetComDir() == COMD_Left) SetComDir(COMD_UpLeft);
|
||||
else if (GetComDir() == COMD_Right) SetComDir(COMD_UpRight);
|
||||
}
|
||||
|
||||
if (!Random(20)) TryStartTeleport();
|
||||
}
|
||||
|
||||
private func ActivityWalking()
|
||||
{
|
||||
var comd = GetComDir();
|
||||
|
||||
if (enemy)
|
||||
{
|
||||
if (enemy->GBackLiquid())
|
||||
{
|
||||
if (ShockWater()) return;
|
||||
}
|
||||
|
||||
if (!Random(10)) SetComDir(COMD_Stop);
|
||||
var distance = ObjectDistance(this, enemy);
|
||||
|
||||
if (distance < 50 && Random(2))
|
||||
return TryStartTeleport();
|
||||
}
|
||||
|
||||
// If not walking, randomly sleep.
|
||||
if (comd == COMD_Stop)
|
||||
{
|
||||
if (!enemy)
|
||||
{
|
||||
if (!Random(15)) return SetAction("Sleep");
|
||||
if (!Random(15)) // Idle?
|
||||
{
|
||||
if (Random(3))
|
||||
{
|
||||
Schedule(this, "Sound(\"PukaGulp\")", 40);
|
||||
return SetAction("LookAround");
|
||||
}
|
||||
return SetAction("ScratchFace");
|
||||
}
|
||||
}
|
||||
|
||||
if (!Random(5))
|
||||
{
|
||||
if (Random(2)) SetComDir(COMD_Left);
|
||||
else SetComDir(COMD_Right);
|
||||
return;
|
||||
}
|
||||
if (!Random(20))
|
||||
TryStartTeleport();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Random(5))
|
||||
{
|
||||
SetComDir(COMD_Stop);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Random(5))
|
||||
{
|
||||
Turn();
|
||||
return;
|
||||
}
|
||||
|
||||
// Anticipate holes in the landscape while walking.
|
||||
|
||||
}
|
||||
|
||||
private func ActivitySleeping()
|
||||
{
|
||||
if (!Random(20))
|
||||
SetAction("Walk");
|
||||
if (!Random(5))
|
||||
AddEffect("IntDream", this, 1, 1, this);
|
||||
}
|
||||
|
||||
private func FxIntDreamStart(object target, effect fx, temp)
|
||||
{
|
||||
if (temp) return;
|
||||
fx.x = GetX();
|
||||
fx.y = GetY() - 5;
|
||||
|
||||
fx.particles =
|
||||
{
|
||||
Prototype = Particles_ElectroSpark2(),
|
||||
Size = PV_Linear(PV_Random(0, 1), PV_Random(1, 2)),
|
||||
Rotation = PV_Random(360)
|
||||
};
|
||||
}
|
||||
|
||||
private func FxIntDreamTimer(object target, effect fx, int time)
|
||||
{
|
||||
if (time > RandomX(30, 200)) return -1;
|
||||
fx.x += RandomX(-1, 1);
|
||||
fx.y += RandomX(-1, 1);
|
||||
CreateParticle("ElectroSpark", fx.x - GetX(), fx.y - GetY(), 0, 0, PV_Random(5, 20), fx.particles, 2);
|
||||
}
|
||||
|
||||
private func ExecuteActivity()
|
||||
{
|
||||
if (this.Activity) this->Activity();
|
||||
}
|
||||
|
||||
private func UpdateEnemy()
|
||||
{
|
||||
// Already disposed of the last one?
|
||||
if (enemy && !enemy->GetAlive()) enemy = nil;
|
||||
// Last one too far away now?
|
||||
if (enemy && ObjectDistance(this, enemy) > 150) enemy = nil;
|
||||
|
||||
var x = GetX();
|
||||
var y = GetY();
|
||||
for (var obj in FindObjects(Find_Distance(100), Find_OCF(OCF_Alive), Find_Hostile(GetOwner()), Sort_Distance()))
|
||||
{
|
||||
if (!PathFree(x, y, obj->GetX(), obj->GetY())) continue;
|
||||
enemy = obj;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private func DoElectroCircle()
|
||||
{
|
||||
for (var angle = 0; angle < 360; angle += 10)
|
||||
{
|
||||
var speed_x = Cos(angle, 15);
|
||||
var speed_y = -Sin(angle, 15);
|
||||
CreateParticle("ElectroSpark", PV_Random(-5, 5), PV_Random(-5, 5),
|
||||
PV_Random(speed_x - 10, speed_x + 10), PV_Random(speed_y - 10, speed_y + 10),
|
||||
PV_Random(5, 10),
|
||||
Particles_ElectroSpark2(),
|
||||
10);
|
||||
}
|
||||
|
||||
var particles =
|
||||
{
|
||||
Prototype = Particles_ElectroSpark1(),
|
||||
Stretch = 6000,
|
||||
DampingX = 999, DampingY = 999
|
||||
};
|
||||
|
||||
// Punish all close enemies (not allied animals, though).
|
||||
for (var obj in FindObjects(Find_Distance(30), Find_OCF(OCF_Alive), Find_Hostile(GetOwner()), Find_Exclude(this)))
|
||||
{
|
||||
var delta_x = 3 * (obj->GetX() - GetX());
|
||||
var delta_y = 3 * (obj->GetY() - GetY());
|
||||
|
||||
obj->DoEnergy(-15, false, FX_Call_EngGetPunched, GetOwner());
|
||||
|
||||
CreateParticle("ElectroSpark", 0, 0,
|
||||
PV_Random(delta_x - 10, delta_x + 10), PV_Random(delta_y - 10, delta_y + 10),
|
||||
PV_Random(1, 5),
|
||||
particles,
|
||||
40);
|
||||
}
|
||||
}
|
||||
|
||||
private func FxIntTeleportStart(object target, effect fx, temp)
|
||||
{
|
||||
if (temp) return;
|
||||
DoElectroCircle();
|
||||
fx.start_x = GetX();
|
||||
fx.start_y = GetY();
|
||||
this.Visibility = VIS_None;
|
||||
|
||||
fx.particles =
|
||||
{
|
||||
Prototype = Particles_ElectroSpark1(),
|
||||
Stretch = 6000,
|
||||
DampingX = 999, DampingY = 999
|
||||
};
|
||||
|
||||
var xdir, ydir;
|
||||
if (current_high_x != nil)
|
||||
{
|
||||
xdir = current_high_x - fx.start_x;
|
||||
ydir = current_high_y - fx.start_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
xdir = 0;
|
||||
ydir = -30;
|
||||
}
|
||||
CreateParticle("ElectroSpark", PV_Random(-5, 5), PV_Random(-5, 5),
|
||||
PV_Random(xdir - 5, xdir + 5), PV_Random(ydir - 5, ydir + 5),
|
||||
PV_Random(1, 5), fx.particles, 200);
|
||||
|
||||
SoundAt("PukaTeleportOut");
|
||||
}
|
||||
|
||||
private func FxIntTeleportTimer(object target, effect fx, int time)
|
||||
{
|
||||
// Instant teleport if no midpoint set.
|
||||
if (current_high_x == nil)
|
||||
{
|
||||
var old_x = GetX();
|
||||
var old_y = GetY();
|
||||
// Try target position if not stuck.
|
||||
SetPosition(current_ground_x, current_ground_y);
|
||||
var counter = 3;
|
||||
while (Stuck() && counter > 0)
|
||||
{
|
||||
SetPosition(GetX(), GetY() - 5);
|
||||
}
|
||||
// Otherwise abort!
|
||||
if (Stuck())
|
||||
SetPosition(old_x, old_y);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Actually fly the way if in "normal" mode.
|
||||
time *= 40;
|
||||
if (time >= 1000) return -1;
|
||||
var half_time = 500;
|
||||
var w0 = Max(0, half_time - time);
|
||||
var w1 = half_time - Abs(time - half_time);
|
||||
var w2 = Max(0, time - half_time);
|
||||
|
||||
var point_x = fx.start_x * w0 + current_high_x * w1 + current_ground_x * w2;
|
||||
var point_y = fx.start_y * w0 + current_high_y * w1 + current_ground_y * w2;
|
||||
point_x /= w0 + w1 + w2;
|
||||
point_y /= w0 + w1 + w2;
|
||||
|
||||
var old_stuck = Stuck();
|
||||
var x = GetX();
|
||||
var y = GetY();
|
||||
SetPosition(point_x, point_y);
|
||||
if (Stuck() && !old_stuck)
|
||||
SetPosition(x, y);
|
||||
SetSpeed(0, 0);
|
||||
}
|
||||
|
||||
private func FxIntTeleportStop(object target, effect fx, int reason, temp)
|
||||
{
|
||||
if (temp || !this) return;
|
||||
this.Visibility = VIS_All;
|
||||
SetAction("Jump");
|
||||
DoElectroCircle();
|
||||
|
||||
var xdir, ydir;
|
||||
if (current_high_x != nil)
|
||||
{
|
||||
xdir = GetX() - current_high_x;
|
||||
ydir = GetY() - current_high_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
xdir = 0;
|
||||
ydir = 30;
|
||||
}
|
||||
|
||||
var start_x = -xdir/2;
|
||||
var start_y = -ydir/2;
|
||||
CreateParticle("ElectroSpark", PV_Random(start_x - 5, start_x + 5), PV_Random(start_y - 5, start_y + 5),
|
||||
PV_Random(xdir - 5, xdir + 5), PV_Random(ydir - 5, ydir + 5),
|
||||
PV_Random(1, 5), fx.particles, 200);
|
||||
|
||||
SoundAt("PukaTeleportIn");
|
||||
}
|
||||
|
||||
public func TryStartTeleport()
|
||||
{
|
||||
// Already teleporting?
|
||||
if (GetAction() == "Teleport" || GetEffect("IntTeleport", this)) return;
|
||||
|
||||
// Go to the most distant water?
|
||||
var teleport_ok = false;
|
||||
|
||||
if (!Random(3))
|
||||
{
|
||||
var best_position = nil, best_distance = nil;
|
||||
var x = GetX(), y = GetY();
|
||||
for (var position in water_positions)
|
||||
{
|
||||
if (GBackSolid(AbsX(position[0]), AbsY(position[1]))) continue;
|
||||
|
||||
var distance = Distance(x, y, position[0], position[1]);
|
||||
if (best_position == nil || distance > best_distance)
|
||||
{
|
||||
best_position = position;
|
||||
best_distance = distance;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_position != nil)
|
||||
{
|
||||
current_ground_x = best_position[0];
|
||||
current_ground_y = best_position[1];
|
||||
current_high_x = nil;
|
||||
current_high_y = nil;
|
||||
teleport_ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
teleport_ok = teleport_ok || GetTeleportPosition();
|
||||
|
||||
// Go to a new random position?
|
||||
if (teleport_ok)
|
||||
{
|
||||
SetComDir(COMD_Stop);
|
||||
if (GetAction() == "Walk")
|
||||
SetAction("Teleport");
|
||||
else EndTeleport();
|
||||
}
|
||||
}
|
||||
|
||||
private func StartTeleport()
|
||||
{
|
||||
this.Activity = nil;
|
||||
}
|
||||
|
||||
// When the teleport action has played.
|
||||
private func EndTeleport()
|
||||
{
|
||||
AddEffect("IntTeleport", this, 1, 1, this);
|
||||
}
|
||||
|
||||
private func GetTeleportPosition()
|
||||
{
|
||||
// Allow multiple tries to increase the chance of a good position.
|
||||
for (var try = 0; try < 2; ++try)
|
||||
{
|
||||
// Project a line upwards and from the collision point (if any) project downwards at an angle.
|
||||
var upwards_angle = RandomX(-45, 45);
|
||||
|
||||
if (GetAction() == "Scale")
|
||||
{
|
||||
if (GetDir() == DIR_Left) upwards_angle += 90;
|
||||
else upwards_angle -= 90;
|
||||
}
|
||||
var upwards_length = 100;
|
||||
var upwards_target_x = GetX() + Sin(upwards_angle, upwards_length);
|
||||
var upwards_target_y = GetY() - Cos(upwards_angle, upwards_length);
|
||||
var point = PathFree2(GetX(), GetY(), upwards_target_x, upwards_target_y);
|
||||
|
||||
var high_x, high_y;
|
||||
if (point)
|
||||
{
|
||||
high_x = point[0];
|
||||
high_y = point[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
high_x = upwards_target_x;
|
||||
high_y = upwards_target_y;
|
||||
}
|
||||
high_x = 2 * high_x / 3;
|
||||
high_y = 2 * high_y / 3;
|
||||
|
||||
// Now project down again.
|
||||
var downwards_angle = RandomX(135, 160);
|
||||
if (Random(2)) downwards_angle *= -1;
|
||||
|
||||
var down_target_x = high_x + Sin(downwards_angle, 75 + upwards_length);
|
||||
var down_target_y = high_y - Cos(downwards_angle, 75 + upwards_length);
|
||||
point = PathFree2(high_x, high_y, down_target_x, down_target_y);
|
||||
if (!point) continue;
|
||||
|
||||
// Don't stay at the same position..
|
||||
if (Distance(GetX(), GetY(), point[0], point[1]) < 50) continue;
|
||||
|
||||
current_high_x = high_x;
|
||||
current_high_y = high_y;
|
||||
current_ground_x = point[0];
|
||||
current_ground_y = point[1];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private func ShockWater()
|
||||
{
|
||||
// Already shocking? Most splendid.
|
||||
if (GetAction() == "ShockWater") return true;
|
||||
|
||||
// Still reloading?
|
||||
if (GetEffect("IntShockWaterCooldown", this)) return false;
|
||||
|
||||
// On which side is the water?
|
||||
var dir = nil;
|
||||
if (GBackLiquid(-15, 15)) dir = DIR_Right;
|
||||
else if (GBackLiquid(+15, 15)) dir = DIR_Left;
|
||||
|
||||
// No water?
|
||||
if (dir == nil)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Turn to the right direction.
|
||||
if (GetDir() != dir)
|
||||
Turn(dir, false);
|
||||
|
||||
SetComDir(COMD_Stop);
|
||||
this.Activity = nil;
|
||||
SetAction("ShockWater");
|
||||
|
||||
AddEffect("Sparkle", this, 1, 1, this);
|
||||
|
||||
Sound("PukaHiss*");
|
||||
return true;
|
||||
}
|
||||
|
||||
private func EndShockWater()
|
||||
{
|
||||
// Randomly sample some points and - if water - fire lightning.
|
||||
var x = 15;
|
||||
if (GetDir() == DIR_Right) x *= -1;
|
||||
var y = 15;
|
||||
|
||||
for (var obj in FindObjects(Find_Distance(120), Find_OCF(OCF_Alive), Find_Hostile(this->GetOwner())))
|
||||
{
|
||||
if (!obj->GBackLiquid()) continue;
|
||||
var angle = Angle(GetX(), GetY(), obj->GetX(), obj->GetY());
|
||||
var xdir = +Sin(angle, 5);
|
||||
var ydir = -Cos(angle, 5);
|
||||
LaunchLightning(GetX() + x, GetY() + y, RandomX(50, 70), xdir, ydir, 10, 10, false);
|
||||
}
|
||||
|
||||
// And some particles on the tail.
|
||||
var particles =
|
||||
{
|
||||
Prototype = Particles_ElectroSpark1(),
|
||||
Stretch = 2000,
|
||||
DampingX = 950, DampingY = 950
|
||||
};
|
||||
CreateParticle("ElectroSpark", x, y, PV_Random(-30, 30), PV_Random(-30, 30), PV_Random(1, 5), particles, 30);
|
||||
|
||||
// Don't do that again immediately.
|
||||
AddEffect("IntShockWaterCooldown", this, 1, 30);
|
||||
}
|
||||
|
||||
private func FxSparkleStart(object target, effect fx, temp)
|
||||
{
|
||||
if (temp) return;
|
||||
fx.particles =
|
||||
{
|
||||
Prototype = Particles_ElectroSpark2(),
|
||||
Stretch = 1000,
|
||||
DampingX = 999, DampingY = 999
|
||||
};
|
||||
}
|
||||
|
||||
private func FxSparkleTimer(object target, effect fx, int time)
|
||||
{
|
||||
if (time > 30) return -1;
|
||||
var angle = RandomX(-90, 90);
|
||||
var xdir = Sin(angle, 20);
|
||||
var ydir = -Cos(angle, 20);
|
||||
CreateParticle("ElectroSpark", xdir, ydir, xdir, ydir, 5, fx.particles, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
private func CheckTurn()
|
||||
{
|
||||
if(GetXDir() < 0) if(GetDir() != DIR_Left) SetDir(DIR_Left);
|
||||
else if(GetXDir() > 0) if(GetDir() != DIR_Right) SetDir(DIR_Right);
|
||||
|
||||
var t = false;
|
||||
if(turn_angle == 0 && GetDir() == DIR_Left) t = true;
|
||||
else if(turn_angle == 180 && GetDir() == DIR_Right) t = true;
|
||||
|
||||
if(t)
|
||||
{
|
||||
if(!GetEffect("IntTurning", this))
|
||||
AddEffect("IntTurning", this, 1, 1, this);
|
||||
}
|
||||
}
|
||||
|
||||
private func Turn(int dir, bool move)
|
||||
{
|
||||
if (dir == nil)
|
||||
{
|
||||
if (GetDir() == DIR_Left)
|
||||
dir = DIR_Right;
|
||||
else
|
||||
dir = DIR_Left;
|
||||
}
|
||||
|
||||
if(move)
|
||||
{
|
||||
if(dir == DIR_Left) SetComDir(COMD_Left);
|
||||
else SetComDir(COMD_Right);
|
||||
}
|
||||
if(GetDir() == dir) return;
|
||||
SetXDir(0);
|
||||
SetDir(dir);
|
||||
CheckTurn();
|
||||
}
|
||||
|
||||
private func FxIntTurningStart(object target, effect fx, temp)
|
||||
{
|
||||
if(temp)
|
||||
return true;
|
||||
}
|
||||
|
||||
private func FxIntTurningTimer(object target, effect fx, int time)
|
||||
{
|
||||
if(GetDir() == DIR_Left)
|
||||
turn_angle += 15;
|
||||
else turn_angle -= 15;
|
||||
|
||||
if(turn_angle < 0 || turn_angle > 180)
|
||||
{
|
||||
turn_angle = BoundBy(turn_angle, 0, 180);
|
||||
this.MeshTransformation = Trans_Rotate(turn_angle + 180 + 30,0,1,0);
|
||||
return -1;
|
||||
}
|
||||
this.MeshTransformation = Trans_Rotate(turn_angle + 180 + 30,0,1,0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Immune to lightning.
|
||||
public func LightningStrike() { return true; }
|
||||
|
||||
local MaxEnergy = 30000;
|
||||
local MaxBreath = 10000;
|
||||
local NoBurnDecay = 1;
|
||||
|
||||
local ActMap = {
|
||||
Walk = {
|
||||
Prototype = Action,
|
||||
Name = "Walk",
|
||||
Procedure = DFA_WALK,
|
||||
Accel = 4,
|
||||
Decel = 22,
|
||||
Speed = 100,
|
||||
Directions = 2,
|
||||
FlipDir = 0,
|
||||
Length = 70,
|
||||
Delay = 1,
|
||||
Animation = "Walk",
|
||||
StartCall = "StartWalk",
|
||||
AbortCall = "StopWalk",
|
||||
EndCall = "StopWalk",
|
||||
InLiquidAction = "Swim",
|
||||
},
|
||||
Swim = {
|
||||
Prototype = Action,
|
||||
Name = "Swim",
|
||||
Procedure = DFA_SWIM,
|
||||
Accel = 16,
|
||||
Decel = 22,
|
||||
Speed = 100,
|
||||
Directions = 2,
|
||||
FlipDir = 0,
|
||||
Length = 70,
|
||||
Delay = 1,
|
||||
Animation = "Swim",
|
||||
StartCall = "StartSwim",
|
||||
AbortCall = "StopSwim",
|
||||
EndCall = "EndSwim",
|
||||
},
|
||||
Scale = {
|
||||
Prototype = Action,
|
||||
Name = "Scale",
|
||||
Procedure = DFA_SCALE,
|
||||
Accel = 16,
|
||||
Decel = 22,
|
||||
Speed = 50,
|
||||
Directions = 2,
|
||||
FlipDir = 0,
|
||||
Length = 70,
|
||||
Delay = 2,
|
||||
Animation = "Scale",
|
||||
StartCall = "StartScale",
|
||||
AbortCall = "StopScale",
|
||||
EndCall = "StopScale",
|
||||
},
|
||||
Jump = {
|
||||
Prototype = Action,
|
||||
Name = "Jump",
|
||||
Procedure = DFA_FLIGHT,
|
||||
Speed = 200,
|
||||
Accel = 14,
|
||||
Directions = 2,
|
||||
FlipDir = 0,
|
||||
Length = 20,
|
||||
Delay = 2,
|
||||
Animation = "RunJump",
|
||||
NextAction = "Hold",
|
||||
PhaseCall = "CheckStuck",
|
||||
StartCall = "StartJump",
|
||||
EndCall = "EndJump",
|
||||
AbortCall = "EndJump",
|
||||
InLiquidAction = "Swim",
|
||||
},
|
||||
Dead = {
|
||||
Prototype = Action,
|
||||
Name = "Dead",
|
||||
Directions = 2,
|
||||
FlipDir = 0,
|
||||
Length = 30,
|
||||
Delay = 1,
|
||||
Animation = "Teleport",
|
||||
NextAction = "Hold",
|
||||
NoOtherAction = 1,
|
||||
ObjectDisabled = 1
|
||||
},
|
||||
Teleport = {
|
||||
Prototype = Action,
|
||||
Name = "Teleport",
|
||||
Procedure = DFA_THROW,
|
||||
Directions = 2,
|
||||
FlipDir = 0,
|
||||
Length = 10,
|
||||
Delay = 3,
|
||||
Animation = "Teleport",
|
||||
NextAction = "Fly",
|
||||
StartCall = "StartTeleport",
|
||||
EndCall = "EndTeleport",
|
||||
},
|
||||
Sleep = {
|
||||
Prototype = Action,
|
||||
Name = "Sleep",
|
||||
Procedure = DFA_THROW,
|
||||
Directions = 2,
|
||||
FlipDir = 0,
|
||||
Length = 30,
|
||||
Delay = 1,
|
||||
Animation = "RollSleep",
|
||||
NextAction = "Hold",
|
||||
StartCall = "StartSleep"
|
||||
},
|
||||
LookAround = {
|
||||
Prototype = Action,
|
||||
Name = "LookAround",
|
||||
Procedure = DFA_THROW,
|
||||
Directions = 2,
|
||||
FlipDir = 0,
|
||||
Length = 90,
|
||||
Delay = 1,
|
||||
Animation = "Idle",
|
||||
NextAction = "Walk",
|
||||
StartCall = "ClearActivity"
|
||||
},
|
||||
ScratchFace = {
|
||||
Prototype = Action,
|
||||
Name = "ScratchFace",
|
||||
Procedure = DFA_THROW,
|
||||
Directions = 2,
|
||||
FlipDir = 0,
|
||||
Length = 30,
|
||||
Delay = 1,
|
||||
Animation = "IdleHand",
|
||||
NextAction = "Walk",
|
||||
StartCall = "ClearActivity"
|
||||
},
|
||||
ShockWater = {
|
||||
Prototype = Action,
|
||||
Name = "ShockWater",
|
||||
Procedure = DFA_THROW,
|
||||
Directions = 2,
|
||||
FlipDir = 0,
|
||||
Length = 10,
|
||||
Delay = 3,
|
||||
Animation = "ShockWater",
|
||||
NextAction = "Walk",
|
||||
EndCall = "EndShockWater",
|
||||
},
|
||||
Fly = {
|
||||
Prototype = Action,
|
||||
Name = "Fly",
|
||||
Procedure = DFA_FLOAT,
|
||||
Speed = 200,
|
||||
Accel = 14,
|
||||
Directions = 2,
|
||||
FlipDir = 0,
|
||||
Length = 20,
|
||||
Delay = 2,
|
||||
Animation = "RunJump",
|
||||
NextAction = "Hold",
|
||||
InLiquidAction = "Swim",
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Name=Puka
|
||||
Description=Süße kleine Kreatur. In der Nähe von Wasser extrem gefährlich.
|
|
@ -0,0 +1,2 @@
|
|||
Name=Puka
|
||||
Description=Cute little creature but extremely dangerous near water.
|
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
Loading…
Reference in New Issue