openclonk/planet/Objects.ocd/Clonk.ocd/Script.c

2055 lines
48 KiB
C

/*
Clonk
Author: Randrian
The protoganist of the game. Witty and nimble if skillfully controled ;-)
*/
// selectable by HUD and some performance optimizations for the HUD updates
#include Library_HUDAdapter
// standard controls
#include Library_ClonkControl
// manager for aiming
#include Library_AimManager
// un-comment them as soon as the new controls work with context menus etc.^
// Context menu
//#include Library_ContextMenu
// Auto production
//#include Library_AutoProduction
// ladder climbing
#include Library_CanClimbLadder
local pInventory;
/* Initialization */
protected func Construction()
{
_inherited(...);
SetAction("Walk");
SetDir(Random(2));
// Broadcast for rules
GameCallEx("OnClonkCreation", this);
AddEffect("IntTurn", this, 1, 1, this);
AddEffect("IntEyes", this, 1, 35+Random(4), this);
AttachBackpack();
}
/* When adding to the crew of a player */
protected func Recruitment(int iPlr)
{
//The clonk's appearance
var skin = GetCrewExtraData("Skin");
if(skin) SetSkin(skin);
// Broadcast for crew
GameCallEx("OnClonkRecruitment", this, iPlr);
return _inherited(iPlr,...);
}
protected func DeRecruitment(int iPlr) {
// Broadcast for crew
GameCallEx("OnClonkDeRecruitment", this, iPlr);
return _inherited(iPlr,...);
}
protected func ControlCommand(szCommand, pTarget, iTx, iTy, pTarget2, Data)
{
// RejectConstruction Callback for building via Drag'n'Drop form a building menu
// TODO: Check if we still need this with the new system
if(szCommand == "Construct")
{
if(Data->~RejectConstruction(iTx - GetX(), iTy - GetY(), this) )
{
return 1;
}
}
// No overloaded command
return 0;
}
/* Transformation */
public func Redefine(idTo)
{
// save data of activity
var phs=GetPhase(),act=GetAction();
// Transform
ChangeDef(idTo);
// restore action
var chg=SetAction(act);
if (!chg) SetAction("Walk");
if (chg) SetPhase(phs);
// Done
return 1;
}
/* Events */
protected func CatchBlow()
{
if (GetAction() == "Dead") return;
if (!Random(5)) Hurt();
}
protected func Hurt()
{
if(gender == 0)
Sound("Hurt*");
else
Sound("FHurt*"); //female 'ouch' sounds TODO :/
}
protected func Grab(object pTarget, bool fGrab)
{
Sound("Grab");
}
protected func Get()
{
Sound("Grab");
}
protected func Put()
{
Sound("Grab");
}
protected func Death(int killed_by)
{
// this must be done first, before any goals do funny stuff with the clonk
_inherited(killed_by,...);
// Info-broadcasts for dying clonks.
GameCallEx("OnClonkDeath", this, killed_by);
// The broadcast could have revived the clonk.
if (GetAlive())
return;
if(gender == 0)
Sound("Die");
else
Sound("FDie");
DeathAnnounce();
return;
}
protected func Destruction()
{
_inherited(...);
// If the clonk wasn't dead yet, he will be now.
if (GetAlive())
GameCallEx("OnClonkDeath", this, GetKiller());
// If this is the last crewmember, do broadcast.
if (GetCrew(GetOwner()) == this)
if (GetCrewCount(GetOwner()) == 1)
// Only if the player is still alive and not yet elimnated.
if (GetPlayerName(GetOwner()))
GameCallEx("RelaunchPlayer", GetOwner(), GetKiller());
return;
}
protected func DeepBreath()
{
Sound("Breath");
}
protected func CheckStuck()
{
// Prevents getting stuck on middle vertex
if(!GetXDir()) if(Abs(GetYDir()) < 5)
if(GBackSolid(0, 3))
SetPosition(GetX(), GetY() + 1);
}
/* Status */
// TODO: Make this more sophisticated, readd turn animation and other
// adaptions
public func IsClonk() { return true; }
public func IsJumping(){return GetProcedure() == "FLIGHT";}
public func IsWalking(){return GetProcedure() == "WALK";}
/* Carry items on the clonk */
local iHandMesh;
local fHandAction;
local fBothHanded;
func OnSelectionChanged(int oldslot, int newslot, bool secondaryslot)
{
AttachHandItem(secondaryslot);
return _inherited(oldslot, newslot, secondaryslot);
}
func OnSlotEmpty(int slot)
{
AttachHandItem(slot);
return _inherited(slot);
}
func OnSlotFull(int slot)
{
AttachHandItem(slot);
return _inherited(slot);
}
public func DetachObject(object obj)
{
if(GetItem(0) == obj)
DetachHandItem(0);
if(GetItem(1) == obj)
DetachHandItem(1);
}
func DetachHandItem(bool secondary)
{
if(iHandMesh[secondary])
DetachMesh(iHandMesh[secondary]);
iHandMesh[secondary] = 0;
}
func AttachHandItem(bool secondary)
{
if(!iHandMesh) iHandMesh = [0,0];
DetachHandItem(secondary);
UpdateAttach();
}
func UpdateAttach()
{
StopAnimation(GetRootAnimation(6));
DoUpdateAttach(0);
DoUpdateAttach(1);
}
func DoUpdateAttach(bool sec)
{
var obj = GetItem(sec);
var other_obj = GetItem(!sec);
if(!obj) return;
var iAttachMode = obj->~GetCarryMode(this);
if(iAttachMode == CARRY_None) return;
if(iHandMesh[sec])
{
DetachMesh(iHandMesh[sec]);
iHandMesh[sec] = 0;
}
var bone = "main";
var bone2;
if(obj->~GetCarryBone()) bone = obj->~GetCarryBone(this);
if(obj->~GetCarryBone2()) bone2 = obj->~GetCarryBone2(this);
else bone2 = bone;
var nohand = 0;
if(!HasHandAction(sec, 1)) nohand = 1;
var trans = obj->~GetCarryTransform(this, sec, nohand);
var pos_hand = "pos_hand2";
if(sec) pos_hand = "pos_hand1";
var pos_back = "pos_back1";
if(sec) pos_back = "pos_back2";
var closehand = "Close2Hand";
if(sec) closehand = "Close1Hand";
if(!sec) fBothHanded = 0;
var special = obj->~GetCarrySpecial(this);
var special_other;
if(other_obj) special_other = other_obj->~GetCarrySpecial(this);
if(special)
{
iHandMesh[sec] = AttachMesh(obj, special, bone, trans);
iAttachMode = 0;
}
if(iAttachMode == CARRY_Hand)
{
if(HasHandAction(sec, 1))
{
iHandMesh[sec] = AttachMesh(obj, pos_hand, bone, trans);
PlayAnimation(closehand, 6, Anim_Const(GetAnimationLength(closehand)), Anim_Const(1000));
}
else
; // Don't display
}
else if(iAttachMode == CARRY_HandBack)
{
if(HasHandAction(sec, 1))
{
iHandMesh[sec] = AttachMesh(obj, pos_hand, bone, trans);
PlayAnimation(closehand, 6, Anim_Const(GetAnimationLength(closehand)), Anim_Const(1000));
}
else
iHandMesh[sec] = AttachMesh(obj, pos_back, bone2, trans);
}
else if(iAttachMode == CARRY_HandAlways)
{
iHandMesh[sec] = AttachMesh(obj, pos_hand, bone, trans);
PlayAnimation(closehand, 6, Anim_Const(GetAnimationLength(closehand)), Anim_Const(1000));
}
else if(iAttachMode == CARRY_Back)
{
iHandMesh[sec] = AttachMesh(obj, pos_back, bone2, trans);
}
else if(iAttachMode == CARRY_BothHands)
{
if(sec) return;
if(HasHandAction(sec, 1) && !sec && !special_other)
{
iHandMesh[sec] = AttachMesh(obj, "pos_tool1", bone, trans);
PlayAnimation("CarryArms", 6, Anim_Const(obj->~GetCarryPhase(this)), Anim_Const(1000));
fBothHanded = 1;
}
else
; // Don't display
}
else if(iAttachMode == CARRY_Spear)
{
if(HasHandAction(sec, 1) && !sec)
{
PlayAnimation("CarrySpear", 6, Anim_Const(0), Anim_Const(1000));
}
else
iHandMesh[sec] = AttachMesh(obj, pos_back, bone2, trans);
}
else if(iAttachMode == CARRY_Musket)
{
if(HasHandAction(sec, 1) && !sec)
{
iHandMesh[sec] = AttachMesh(obj, "pos_hand2", bone, trans);
PlayAnimation("CarryMusket", 6, Anim_Const(0), Anim_Const(1000));
fBothHanded = 1;
}
else
iHandMesh[sec] = AttachMesh(obj, pos_back, bone2, trans);
}
else if(iAttachMode == CARRY_Grappler)
{
if(HasHandAction(sec, 1) && !sec)
{
iHandMesh[sec] = AttachMesh(obj, "pos_hand2", bone, trans);
PlayAnimation("CarryCrossbow", 6, Anim_Const(0), Anim_Const(1000));
fBothHanded = 1;
}
else
iHandMesh[sec] = AttachMesh(obj, pos_back, bone2, trans);
}
}//AttachMesh(DynamiteBox, "pos_tool1", "main", Trans_Translate(0,0,0));
public func GetHandMesh(object obj)
{
if(GetItem(0) == obj)
return iHandMesh[0];
if(GetItem(1) == obj)
return iHandMesh[1];
}
static const CARRY_None = 0;
static const CARRY_Hand = 1;
static const CARRY_HandBack = 2;
static const CARRY_HandAlways = 3;
static const CARRY_Back = 4;
static const CARRY_BothHands = 5;
static const CARRY_Spear = 6;
static const CARRY_Musket = 7;
static const CARRY_Grappler = 8;
func HasHandAction(sec, just_wear)
{
if(sec && fBothHanded)
return false;
if(just_wear)
{
if( HasActionProcedure() && !fHandAction ) // For wear purpose fHandAction==-1 also blocks
return true;
}
else
{
if( HasActionProcedure() && (!fHandAction || fHandAction == -1) )
return true;
}
return false;
}
func HasActionProcedure()
{
if(GetAction() == "Walk" || GetAction() == "Jump" || GetAction() == "Kneel" || GetAction() == "Ride")
return true;
return false;
}
public func ReadyToAction(fNoArmCheck)
{
if(!fNoArmCheck)
return HasActionProcedure();
return HasHandAction(0);
}
public func SetHandAction(bool fNewValue)
{
if(fNewValue > 0)
fHandAction = 1; // 1 means can't use items and doesn't draw items in hand
else if(fNewValue < 0)
fHandAction = -1; // just don't draw items in hand can still use them
else
fHandAction = 0;
UpdateAttach();
}
public func GetHandAction()
{
if(fHandAction == 1)
return true;
return false;
}
/* Mesh transformations */
local mesh_transformation_list;
func SetMeshTransformation(array transformation, int layer)
{
if(!mesh_transformation_list) mesh_transformation_list = [];
if(GetLength(mesh_transformation_list) < layer)
SetLength(mesh_transformation_list, layer+1);
mesh_transformation_list[layer] = transformation;
var all_transformations = 0;
for(var trans in mesh_transformation_list)
{
if(!trans) continue;
if(all_transformations)
all_transformations = Trans_Mul(trans, all_transformations);
else
all_transformations = trans;
}
SetProperty("MeshTransformation", all_transformations);
}
/* Backpack */
local backpack;
func AttachBackpack()
{
//Places a backpack onto the clonk
backpack = AttachMesh(BackpackGraphic, "skeleton_body", "main",
Trans_Mul(Trans_Rotate(180,0,1,0), Trans_Scale(700,700,400), Trans_Translate(0,4000,1000)));
}
func RemoveBackpack()
{
if(backpack)
{
DetachMesh(backpack);
backpack = nil;
}
else return false;
}
/* Turn */
local iTurnAction;
local iTurnAction2;
local iTurnAction3;
local iTurnKnot1;
local iTurnKnot2;
local iLastTurn;
local iTurnSpecial;
local turn_forced;
static const CLONK_TurnTime = 10;
func SetTurnForced(int dir)
{
turn_forced = dir+1;
}
func FxIntTurnStart(pTarget, effect, fTmp)
{
if(fTmp) return;
effect.dir = GetDirection();
var iTurnPos = 0;
if(effect.dir == COMD_Right) iTurnPos = 1;
effect.curr_rot = 24;
effect.var1 = 0;
effect.rot = 25;
effect.var5 = -1;
SetTurnType(0);
}
func FxIntTurnTimer(pTarget, effect, iTime)
{
// Check wether the clonk wants to turn (Not when he wants to stop)
var iRot = effect.rot;
if( (effect.dir != GetDirection() || effect.var5 != iLastTurn) && GetAction() != "Jump")
{
effect.dir = GetDirection();
if(effect.dir == COMD_Right)
{
if(iLastTurn == 0)
iRot = 180-25;
if(iLastTurn == 1)
iRot = 180;
}
else
{
if(iLastTurn == 0)
iRot = 25;
if(iLastTurn == 1)
iRot = 0;
}
// Save new ComDir
effect.dir = GetDirection();
effect.var5 = iLastTurn;
// Notify effects
// ResetAnimationEffects();
}
if(iRot != effect.curr_rot)
{
effect.curr_rot += BoundBy(iRot-effect.curr_rot, -18, 18);
SetMeshTransformation(Trans_Rotate(effect.curr_rot, 0, 1, 0), 0);
// SetProperty("MeshTransformation", Trans_Rotate(iNumber.curr_rot, 0, 1, 0));
}
effect.rot = iRot;
return;
}
public func GetTurnPhase()
{
var iEff = GetEffect("IntTurn", this);
var iRot = iEff.curr_rot;
if(iLastTurn == 0)
return (iRot-25)*100/130;
if(iLastTurn == 1)
return iRot*100/180;
return GetAnimationPosition(iTurnAction)*100/GetAnimationLength("TurnRoot120");
}
local iLastTurn;
local iTurnSpecial;
func SetTurnType(iIndex, iSpecial)
{
if(iSpecial != nil && iSpecial != 0)
{
if(iSpecial == 1) // Start a turn that is forced to the clonk and overwrites the normal action's turntype
iTurnSpecial = 1;
if(iSpecial == -1) // Reset special turn (here the iIndex is ignored)
{
iTurnSpecial = 0;
SetTurnType(iLastTurn);
return;
}
}
else
{
// Standart turn? Save and do nothing if we are blocked
iLastTurn = iIndex;
if(iTurnSpecial) return;
}
return;
}
// For test purpose
public func TurnFront()
{
SetAnimationPosition(iTurnAction, Anim_Const(500));
}
func GetDirection()
{
// Are we forced to a special direction?
if(turn_forced)
{
if(turn_forced == 1) return COMD_Left;
if(turn_forced == 2) return COMD_Right;
}
// Get direction from ComDir
if(GetAction() != "Scale")
{
if(ComDirLike(GetComDir(), COMD_Right)) return COMD_Right;
else if(ComDirLike(GetComDir(), COMD_Left)) return COMD_Left;
}
// if ComDir hasn't a direction, use GetDir
if(GetDir()==DIR_Right) return COMD_Right;
else return COMD_Left;
}
/* Animation Manager */
local PropAnimations;
public func ReplaceAction(string action, byaction)
{
if(PropAnimations == nil) PropAnimations = CreatePropList();
if(byaction == nil || byaction == 0)
{
SetProperty(action, nil, PropAnimations);
ResetAnimationEffects();
return true;
}
/* if(GetAnimationLength(byaction) == nil)
{
Log("ERROR: No animation %s in Definition %s", byaction, GetID()->GetName());
return false;
}*/
if(GetType(byaction) == C4V_Array)
{
var old = GetProperty(action, PropAnimations);
SetProperty(action, byaction, PropAnimations);
if(GetType(old) == C4V_Array)
{
if(ActualReplace == nil) return true;
if(old[0] == byaction[0] && old[1] == byaction[1])
{
var i = 0;
for (test in ActualReplace)
{
if(test && test[0] == action)
break;
i++;
}
if(i < GetLength(ActualReplace))
SetAnimationWeight(ActualReplace[i][1], Anim_Const(byaction[2]));
return true;
}
}
}
SetProperty(action, byaction, PropAnimations);
// if(ActualReplace != nil)
// SetAnimationWeight(ActualReplace, Anim_Const(byaction[2]));
ResetAnimationEffects();
return true;
}
public func ResetAnimationEffects()
{
if(GetEffect("IntWalk", this))
EffectCall(this, GetEffect("IntWalk", this), "Reset");
if(GetAction() == "Jump")
StartJump();
}
local ActualReplace;
public func PlayAnimation(string animation, int index, array position, array weight, int sibling)
{
if(!ActualReplace) ActualReplace = [];
ActualReplace[index] = nil;
if(PropAnimations != nil)
if(GetProperty(animation, PropAnimations) != nil)
{
var replacement = GetProperty(animation, PropAnimations);
if(GetType(replacement) == C4V_Array)
{
var animation1 = inherited(replacement[0], index, position, weight);
var animation2 = inherited(replacement[1], index, position, Anim_Const(500), animation1);
var animationKnot = animation2 + 1;
ActualReplace[index] = [animation, animationKnot];
SetAnimationWeight(animationKnot, Anim_Const(replacement[2]));
return animation1;
}
else
animation = GetProperty(animation, PropAnimations);
}
return inherited(animation, index, position, weight, sibling, ...);
}
public func GetAnimationLength(string animation)
{
var replacement;
if(PropAnimations != nil)
if(replacement = GetProperty(animation, PropAnimations))
{
if(GetType(replacement) == C4V_Array)
animation = replacement[0];
else
animation = replacement;
}
return inherited(animation, ...);
}
/* Eyes */
func FxIntEyesTimer(target, effect, time)
{
if(!Random(4))
AddEffect("IntEyesClosed", this, 10, 6, this);
}
func FxIntEyesClosedStart(target, effect, tmp)
{
CloseEyes(1);
}
func FxIntEyesClosedStop(target, effect, reason, tmp)
{
CloseEyes(-1);
}
local closed_eyes;
func CloseEyes(iCounter)
{
StopAnimation(GetRootAnimation(3));
// PlayAnimation("CloseEyes", 6, Anim_Linear(0, 0, GetAnimationLength("CloseEyes")/2, 3, ANIM_Hold), Anim_Const(1000));
closed_eyes += iCounter;
if(closed_eyes >= 1)
PlayAnimation("CloseEyes" , 3, Anim_Linear(0, 0, GetAnimationLength("CloseEyes")/2, 3, ANIM_Hold), Anim_Const(1000));
// SetMeshMaterial("Clonk_Body_EyesClosed");
else
PlayAnimation("CloseEyes" , 3, Anim_Linear(GetAnimationLength("CloseEyes")/2, GetAnimationLength("CloseEyes")/2, GetAnimationLength("CloseEyes"), 3, ANIM_Remove), Anim_Const(1000));
// SetMeshMaterial("Clonk_Body");
}
/* Walking backwards */
func SetBackwardsSpeed(int value)
{
BackwardsSpeed = value;
UpdateBackwardsSpeed();
}
local BackwardsSpeed;
local Backwards;
func UpdateBackwardsSpeed()
{
if(GetComDir() != GetDirection() && Backwards != 1 && BackwardsSpeed != nil)
{
AddEffect("IntWalkBack", this, 1, 0, this, 0, BackwardsSpeed);
Backwards = 1;
}
if( (GetComDir() == GetDirection() && Backwards == 1) || BackwardsSpeed == nil)
{
RemoveEffect("IntWalkBack", this);
Backwards = nil;
}
}
func FxIntWalkBackStart(pTarget, effect, fTmp, iValue)
{
if(iValue == nil) iValue = 84;
pTarget->PushActionSpeed("Walk", iValue);
}
func FxIntWalkBackStop(pTarget, effect)
{
pTarget->PopActionSpeed("Walk");
}
/* Walk */
static const Clonk_WalkInside = "Inside";
static const Clonk_WalkStand = "Stand";
static const Clonk_WalkWalk = "Walk";
static const Clonk_WalkRun = "Run";
static Clonk_IdleActions;
func StartWalk()
{
if(Clonk_IdleActions == nil)
Clonk_IdleActions = [["IdleLookAround", 60], ["IdleHandwatch", 100], ["IdleScratch", 70], ["IdleStrech", 100], ["IdleShoe", 120], ["IdleShoeSole", 200], ["IdleHandstrech", 100]];
if(!GetEffect("IntWalk", this))
AddEffect("IntWalk", this, 1, 1, this);
}
func StopWalk()
{
if(GetAction() != "Walk") RemoveEffect("IntWalk", this);
}
func GetCurrentWalkAnimation()
{
if(Contained())
{
if(Contained()->GetCategory() & C4D_Structure)
{
return Clonk_WalkInside;
}
return;
}
else SetProperty("PictureTransformation", Trans_Mul(Trans_Translate(0,1000,5000), Trans_Rotate(70,0,1,0)), this);
var velocity = Distance(0,0,GetXDir(),GetYDir());
if(velocity < 1) return Clonk_WalkStand;
if(velocity < 10) return Clonk_WalkWalk;
return Clonk_WalkRun;
}
func GetWalkAnimationPosition(string anim, int pos)
{
var dir = -1;
if(GetDirection() == COMD_Right) dir = +1;
if(PropAnimations != nil)
if(GetProperty(Format("%s_Position", anim), PropAnimations))
{
var length = GetAnimationLength(anim);
if(GetProperty(anim, PropAnimations)) length = GetAnimationLength(GetProperty(anim, PropAnimations));
return Anim_X(pos, 0, length, GetProperty(Format("%s_Position", anim), PropAnimations)*dir);
}
// TODO: Choose proper starting positions, depending on the current
// animation and its position: For Stand->Walk or Stand->Run, start
// with a frame where one of the clonk's feets is on the ground and
// the other one is in the air. For Walk->Run and Run->Walk, fade to
// a state where its feets are at a similar position (just taking
// over previous animation's position might work, using
// GetAnimationPosition()). Walk->Stand is arbitrary I guess.
// First parameter of Anim_Linear/Anim_AbsX is initial position.
// Movement synchronization might also be tweaked somewhat as well.
if(anim == Clonk_WalkInside)
return Anim_Const(0);
if(anim == Clonk_WalkStand)
return Anim_Linear(pos, 0, GetAnimationLength(anim), 35, ANIM_Loop);
else if(anim == Clonk_WalkWalk)
return Anim_X(pos, 0, GetAnimationLength(anim), 20*dir);
else if(anim == Clonk_WalkRun)
return Anim_X(pos, 0, GetAnimationLength(anim), 50*dir);
}
func FxIntWalkStart(pTarget, effect, fTmp)
{
if(fTmp) return;
// Always start in Stand for now... should maybe fade properly from previous animation instead
var anim = "Stand"; //GetCurrentWalkAnimation();
effect.animation_name = anim;
effect.animation_id = PlayAnimation(anim, 5, GetWalkAnimationPosition(anim), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
effect.idle_animation_time = 0;
effect.idle_time = 0; // Idle counter
effect.idle_offset = Random(300); // Random offset for idle time
// Update carried items
UpdateAttach();
// Set proper turn
SetTurnType(0);
}
func FxIntWalkTimer(pTarget, effect)
{
// Test Waterlevel
if(GBackLiquid(0, -5) && !Contained())
{
SetAction("Swim");
if(GetComDir() == COMD_Left)
SetComDir(COMD_UpLeft);
else if(GetComDir() == COMD_Right)
SetComDir(COMD_UpRight);
else if(GetComDir() != COMD_Down && GetComDir() != COMD_DownLeft && GetComDir() != COMD_DownRight)
SetComDir(COMD_Up);
return;
}
if(BackwardsSpeed != nil)
UpdateBackwardsSpeed();
if(effect.idle_animation_time)
{
effect.idle_animation_time--;
if(effect.idle_animation_time == 0)
effect.animation_name = nil;
}
var anim = GetCurrentWalkAnimation();
if(anim != effect.animation_name && !effect.var4)
{
effect.animation_name = anim;
effect.idle_time = 0;
effect.animation_id = PlayAnimation(anim, 5, GetWalkAnimationPosition(anim, 0), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
}
// The clonk has to stand, not making a pause animation yet and not doing other actions with the hands (e.g. loading the bow)
else if(anim == Clonk_WalkStand && !GetHandAction())
{
if(!effect.idle_animation_time)
{
effect.idle_time++;
if(effect.idle_time > 300+effect.idle_offset)
{
effect.idle_time = 0;
effect.idle_offset = Random(300);
var rand = Random(GetLength(Clonk_IdleActions));
PlayAnimation(Clonk_IdleActions[rand][0], 5, Anim_Linear(0, 0, GetAnimationLength(Clonk_IdleActions[rand][0]), Clonk_IdleActions[rand][1], ANIM_Remove), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
effect.idle_animation_time = Clonk_IdleActions[rand][1]-5;
}
}
}
else
{
effect.idle_time = 0;
if(effect.idle_animation_time)
{
effect.animation_name = nil;
effect.idle_animation_time = 0;
}
}
}
func FxIntWalkReset(pTarget, effect)
{
effect.animation_name = nil;
}
func StartStand()
{
PlayAnimation(Clonk_WalkStand, 5, GetWalkAnimationPosition(Clonk_WalkStand), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
// Update carried items
UpdateAttach();
// Set proper turn type
SetTurnType(0);
}
/* Scale */
func StartScale()
{
if(!GetEffect("IntScale", this))
AddEffect("IntScale", this, 1, 1, this);
// Set proper turn type
SetTurnType(1);
// Update carried items
UpdateAttach();
}
func StopScale()
{
if(GetAction() != "Scale") RemoveEffect("IntScale", this);
}
func CheckPosition(int off_x, int off_y)
{
var free = 1;
SetPosition(GetX()+off_x, GetY()+off_y);
if(Stuck()) free = 0;
SetPosition(GetX()-off_x, GetY()-off_y);
return free;
}
func CheckScaleTop()
{
// Test whether the clonk has reached a top corner
if(GBackSolid(-8+16*GetDir(),-8)) return false;
if(!CheckPosition(-7*(-1+2*GetDir()),-17)) return false;
return true;
}
func FxIntScaleStart(target, effect, tmp)
{
if(tmp) return;
effect.animation_id = PlayAnimation("Scale", 5, Anim_Y(0, GetAnimationLength("Scale"), 0, 15), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
effect.animation_mode = 0;
}
func FxIntScaleTimer(target, number, time)
{
if(GetAction() != "Scale") return;
// When the clonk reaches the top play an extra animation
if(CheckScaleTop())
{
// If the animation is not already set
var dist = 0;
while(!GBackSolid(-8+16*GetDir(),dist-8) && dist < 10) dist++;
dist *= 100;
dist += GetY(100)-GetY()*100;
if(number.animation_mode != 1)
{
number.animation_id = PlayAnimation("ScaleTop", 5, Anim_Const(GetAnimationLength("ScaleTop")*dist/1000), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
number.animation_mode = 1;
number.var2 = COMD_Up;
}
this.dist = dist;
SetAnimationPosition(number.animation_id, Anim_Const(GetAnimationLength("ScaleTop")*dist/1000));
// The animation's graphics has to be shifet a bit to adjust to the clonk movement
var pos = GetAnimationPosition(number.animation_id);
//var percent = pos*1000/GetAnimationLength("ScaleTop");
var offset_list = [[0,0], [0,-1], [-1,-2], [-2,-3], [-2,-5], [-2,-7], [-4,-8], [-6,-10], [-7,-9], [-8,-8]];
var offset = offset_list[dist/100-1];
var rot = 0;
if(dist/100-1 > 5) rot = 5*dist/100-25;
SetScaleRotation(0, -offset[0]*(-1+2*GetDir())*1000, offset[1]*1000, -rot*(-1+2*GetDir()), 0, 1);
}
else if(!GBackSolid(-10+20*GetDir(), 8))
{
if(number.animation_mode != 2)
{
var pos = GetAnimationPosition(number.animation_id);
number.animation_id = PlayAnimation("ScaleHands" , 5, Anim_Y(pos, GetAnimationLength("ScaleHands"), 0, 15), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
number.animation_id2 = PlayAnimation("ScaleHands2", 5, Anim_Y(pos, GetAnimationLength("ScaleHands2"), 0, 15), Anim_Const(1000), number.animation_id);
number.animation_id2++;
number.animation_mode = 2;
}
SetAnimationWeight(number.animation_id2, Anim_Const(Cos(time*2, 500)+500));
SetScaleRotation(0);
}
// If not play the normal scale animation
else if(number.animation_mode != 0)
{
if(number.var3)
{
SetComDir(COMD_Stop);
number.var3 = 0;
}
var pos = 0;
if(number.animation_mode == 2) pos = GetAnimationPosition(number.animation_id);
number.animation_id = PlayAnimation("Scale", 5, Anim_Y(0, GetAnimationLength("Scale"), 0, 15), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
number.animation_mode = 0;
SetScaleRotation(0);
}
if(number.animation_mode == 0)
{
var x, x2;
var y = -7, y2 = 8;
var dir = -1+2*GetDir();
for(x = 0; x < 10; x++)
if(GBackSolid(x*dir, y)) break;
for(x2 = 0; x2 < 10; x2++)
if(GBackSolid(x2*dir, y2)) break;
var angle = Angle(x2, y2, x, y)*dir;
var mid = (x+x2)*1000/2 - 5000 - this.Off;
this.TestAngle = angle;
this.TestMid = mid;
SetScaleRotation(angle, mid*dir);
}
}
func FxIntScaleRotTimer(target, eff, time)
{
eff.oldR += BoundBy(eff.r-eff.oldR, -3, 3);
eff.oldX += BoundBy(eff.xoff-eff.oldX, -500, 500);
eff.oldY += BoundBy(eff.yoff-eff.oldY, -500, 500);
var turnx = -1000;
var turny = 10000;
SetMeshTransformation(Trans_Mul(Trans_Translate(eff.oldX-turnx, eff.oldY-turny), Trans_Rotate(eff.oldR,0,0,1), Trans_Translate(turnx, turny)), 1);
}
func SetScaleRotation (int r, int xoff, int yoff, int rotZ, int turny, int instant) {
if(r < -180) r += 360;
if(r > 180) r -= 360;
// set matrix values
var turnx = -1000;
var turny = 10000;
if(instant)
{
RemoveEffect("IntScaleRot", this);
SetMeshTransformation(Trans_Mul(Trans_Translate(xoff-turnx, yoff-turny), Trans_Rotate(r,0,0,1), Trans_Translate(turnx, turny), Trans_Rotate(rotZ, 0, 1, 0)), 1);
}
else
{
var eff = GetEffect("IntScaleRot", this);
if(!eff)
eff = AddEffect("IntScaleRot", this, 1, 1, this);
eff.r = r;
eff.xoff = xoff;
eff.yoff = yoff;
}
}
func FxIntScaleStop(target, number, reason, tmp)
{
if(tmp) return;
// Set the animation to stand without blending! That's cause the animation of Scale moves the clonkmesh wich would result in a stange blend moving the clonk around while blending
/* if(number.animation_mode == 1) PlayAnimation(Clonk_WalkStand, 5, GetWalkAnimationPosition(Clonk_WalkStand), Anim_Const(1000));
// Finally stop if the user has scheduled a stop
if(number.var3) SetComDir(COMD_Stop);*/
// and reset the transform
SetScaleRotation(0);
// SetObjDrawTransform(1000, 0, 0, 0, 1000, 0);
}
/* Jump */
func StartJump()
{
//which leg to kick off with?
var side = "R";
if(Random(2)) side = "L";
//Normal forward jump
if(Abs(GetXDir()) >= 1)
PlayAnimation(Format("Jump.%s",side), 5, Anim_Linear(0, 0, GetAnimationLength("Jump.L"), 8*5, ANIM_Hold), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
//Walk kick jump
if(GetEffect("WallKick",this))
{
SetAction("WallJump");
var side = "L";
if(GetDir() == DIR_Left) side = "R";
PlayAnimation(Format("JumpWall.%s", side), 5, Anim_Linear(0, 0, GetAnimationLength("JumpWall.L"), 8*5, ANIM_Hold), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
}
//Upwards jump
else if(GetXDir() == 0)
{
PlayAnimation(Format("JumpUp.%s", side), 5, Anim_Linear(0, 0, GetAnimationLength("JumpUp.L"), 8*5, ANIM_Hold), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
}
// Update carried items
UpdateAttach();
// Set proper turn type
SetTurnType(0);
//Dive jump
var flight = SimFlight(AbsX(GetX()), AbsY(GetY()), GetXDir()*2, GetYDir()*2, 25); //I have no clue why the dirs must be doubled... but it seems to fix it
if(GBackLiquid(flight[0] - GetX(), flight[1] - GetY()) && GBackLiquid(flight[0] - GetX(), flight[1] + GetDefHeight() / 2 - GetY()))
{
PlayAnimation("JumpDive", 5, Anim_Linear(0, 0, GetAnimationLength("JumpDive"), 60, ANIM_Hold), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
return 1;
}
if(!GetEffect("Fall", this))
AddEffect("Fall",this,1,1,this);
RemoveEffect("WallKick",this);
}
func FxFallEffect(string new_name, object target)
{
// reject more than one fall effects.
if(new_name == "Fall") return -1;
}
func FxFallTimer(object target, effect, int timer)
{
//falling off ledges without jumping results in fall animation
if(timer == 2 && GetYDir() > 1)
{
PlayAnimation("FallShort", 5, Anim_Linear(0, 0, GetAnimationLength("FallShort"), 8*3, ANIM_Hold), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
}
if(timer == 2 && GetYDir() < 1)
{
Sound("Rustle*.ogg");
}
if(GetYDir() > 55 && GetAction() == "Jump")
{
PlayAnimation("FallLong", 5, Anim_Linear(0, 0, GetAnimationLength("FallLong"), 8*3, ANIM_Hold), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
return -1;
}
if(GetAction() != "Jump")
return -1;
}
/* Hangle */
/* Replaces the named action by an instance with a different speed */
func PushActionSpeed(string action, int n)
{
if (ActMap == this.Prototype.ActMap)
ActMap = { Prototype = this.Prototype.ActMap };
ActMap[action] = { Prototype = ActMap[action], Speed = n };
if (this.Action == ActMap[action].Prototype)
this.Action = ActMap[action];
}
/* Resets the named action to the previous one */
func PopActionSpeed(string action, int n) {
// FIXME: This only works if PushActionSpeed and PopActionSpeed are the only functions manipulating the ActMap
if (this.Action == ActMap[action])
this.Action = ActMap[action].Prototype;
ActMap[action] = ActMap[action].Prototype;
}
func StartHangle()
{
/* if(Clonk_HangleStates == nil)
Clonk_HangleStates = ["HangleStand", "Hangle"];*/
if(!GetEffect("IntHangle", this))
AddEffect("IntHangle", this, 1, 1, this);
// Set proper turn type
SetTurnType(1);
// Update carried items
UpdateAttach();
}
func StopHangle()
{
if(GetAction() != "Hangle") RemoveEffect("IntHangle", this);
}
func FxIntHangleStart(pTarget, effect, fTmp)
{
effect.hangle_speed = ActMap.Hangle.Speed;
PushActionSpeed("Hangle", effect.hangle_speed);
if(fTmp) return;
// is_moving: whether the clonk is currently moving or not (<=> current animation is Hangle or HangleStand)
// request_stop: Player requested the clonk to stop
// facing_front: Whether the HangleStand animation is shown front-facing or back-facing
effect.animation_id = PlayAnimation("HangleStand", 5, Anim_Linear(0, 0, 2000, 100, ANIM_Loop), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
}
func FxIntHangleStop(pTarget, effect, iReasonm, fTmp)
{
PopActionSpeed("Hangle");
if(fTmp) return;
}
func FxIntHangleTimer(pTarget, effect, iTime)
{
// (TODO: Instead of effect.is_moving we should be able
// to query the current animation... maybe via a to-be-implemented
// GetAnimationName() engine function.
// If we are currently moving
if(effect.is_moving)
{
// Use a cosine-shaped movement speed (the clonk only moves when he makes a "stroke")
var iSpeed = 50-Cos(GetAnimationPosition(effect.animation_id)/10*360*2/1000, 50);
ActMap.Hangle.Speed = effect.hangle_speed*iSpeed/50;
// Exec movement animation (TODO: Use Anim_Linear?)
var position = GetAnimationPosition(effect.animation_id);
position += (effect.hangle_speed*5/48*1000/(14*2));
SetAnimationPosition(effect.animation_id, Anim_Const(position % GetAnimationLength("Hangle")));
// Continue movement, if the clonk still has momentum
if(GetComDir() == COMD_Stop && iSpeed>10)
{
// Make it stop after the current movement
effect.request_stop = 1;
if(GetDir())
SetComDir(COMD_Right);
else
SetComDir(COMD_Left);
}
// Stop movement if the clonk has lost his momentum
else if(iSpeed <= 10 && (GetComDir() == COMD_Stop || effect.request_stop))
{
effect.request_stop = 0;
SetComDir(COMD_Stop);
// and remeber the pose (front or back)
if(GetAnimationPosition(effect.animation_id) > 2500 && GetAnimationPosition(effect.animation_id) < 7500)
effect.facing_front = 1;
else
effect.facing_front = 0;
// Change to HangleStand animation
var begin = 4000*effect.facing_front;
var end = 2000+begin;
effect.animation_id = PlayAnimation("HangleStand", 5, Anim_Linear(begin, begin, end, 100, ANIM_Loop), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
effect.is_moving = 0;
}
}
else
{
// We are currently not moving
if(GetComDir() != COMD_Stop)
{
// Switch to move
effect.is_moving = 1;
// start with frame 100 or from the back hanging pose frame 600
var begin = 10*(100 + 500*effect.facing_front);
effect.animation_id = PlayAnimation("Hangle", 5, Anim_Const(begin), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
}
}
}
/* Swim */
func StartSwim()
{
/* if(Clonk_SwimStates == nil)
Clonk_SwimStates = ["SwimStand", "Swim", "SwimDive", "SwimTurn", "SwimDiveTurn", "SwimDiveUp", "SwimDiveDown"];*/
if(!GetEffect("IntSwim", this))
AddEffect("IntSwim", this, 1, 1, this);
SetVertex(1,VTX_Y,-4,2);
}
func StopSwim()
{
if(GetAction() != "Swim") RemoveEffect("IntSwim", this);
SetVertex(1,VTX_Y,-7,2);
}
func FxIntSwimStart(pTarget, effect, fTmp)
{
if(fTmp) return;
effect.animation_name = "SwimStand";
effect.animation = PlayAnimation("SwimStand", 5, Anim_Linear(0, 0, GetAnimationLength("SwimStand"), 20, ANIM_Loop), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
// Set proper turn type
SetTurnType(0);
// Update carried items
UpdateAttach();
SetAnimationWeight(iTurnKnot2, Anim_Const(1000));
}
func FxIntSwimTimer(pTarget, effect, iTime)
{
var iSpeed = Distance(0,0,GetXDir(),GetYDir());
// TODO: Smaller transition time between dive<->swim, keep 15 for swimstand<->swim/swimstand<->dive
// Play stand animation when not moving
if(Abs(GetXDir()) < 1 && !GBackSemiSolid(0, -5))
{
if (GetContact(-1) & CNAT_Bottom)
{
SetAction("Walk");
return -1;
}
if(effect.animation_name != "SwimStand")
{
effect.animation_name = "SwimStand";
effect.animation = PlayAnimation("SwimStand", 5, Anim_Linear(0, 0, GetAnimationLength("SwimStand"), 20, ANIM_Loop), Anim_Linear(0, 0, 1000, 15, ANIM_Remove));
}
SetAnimationWeight(iTurnKnot1, Anim_Const(0));
}
// Swimming
else if(!GBackSemiSolid(0, -5))
{
var percent = GetAnimationPosition(GetRootAnimation(5))*200/GetAnimationLength("Swim");
percent = (percent%100);
if( percent < 40 )
{
for(var i = 0; i < 2; i++)
CreateParticle("Splash", (-1+2*GetDir())*7+RandomX(-5,5), -4, (RandomX(-5,5)-(-1+2*GetDir())*4)/4, -2, RandomX(30,50), RGB(240+Random(10),240+Random(10),255));
if(iTime%5 == 0)
{
var particle_name = "WaveLeft";
if( GetDir() == 1 ) particle_name = "WaveRight";
var color = GetAverageTextureColor(GetTexture(0, 0));
CreateParticle(particle_name, (0), -4, (RandomX(-5,5)-(-1+2*GetDir())*4)/4, 0, 100, color, this, 1);
}
Sound("Splash*");
}
// Animation speed by X
if(effect.animation_name != "Swim")
{
effect.animation_name = "Swim";
// TODO: Determine starting position from previous animation
PlayAnimation("Swim", 5, Anim_AbsX(0, 0, GetAnimationLength("Swim"), 25), Anim_Linear(0, 0, 1000, 15, ANIM_Remove));
}
SetAnimationWeight(iTurnKnot1, Anim_Const(0));
}
// Diving
else
{
if(effect.animation_name != "SwimDive")
{
effect.animation_name = "SwimDive";
// TODO: Determine starting position from previous animation
effect.animation2 = PlayAnimation("SwimDiveUp", 5, Anim_Linear(0, 0, GetAnimationLength("SwimDiveUp"), 40, ANIM_Loop), Anim_Linear(0, 0, 1000, 15, ANIM_Remove));
effect.animation3 = PlayAnimation("SwimDiveDown", 5, Anim_Linear(0, 0, GetAnimationLength("SwimDiveDown"), 40, ANIM_Loop), Anim_Const(500), effect.animation2);
effect.animation = effect.animation3 + 1;
// TODO: This should depend on which animation we come from
// Guess for SwimStand we should fade from 0, otherwise from 90.
effect.rot = 90;
}
if(iSpeed)
{
var iRot = Angle(-Abs(GetXDir()), GetYDir());
effect.rot += BoundBy(iRot - effect.rot, -4, 4);
}
// TODO: Shouldn't weight go by sin^2 or cos^2 instead of linear in angle?
var weight = 1000*effect.rot/180;
SetAnimationWeight(effect.animation, Anim_Const(1000 - weight));
SetAnimationWeight(iTurnKnot1, Anim_Const(1000 - weight));
}
}
func GetSwimRotation()
{
var effect = GetEffect("IntSwim", this);
if(!effect) return 0;
return effect.rot*(-1+2*(GetDirection()==COMD_Right));
}
func Hit(int iXSpeed, int iYSpeed)
{
if(iYSpeed < 450) return;
if(GetAction() != "Walk") return;
//Roll :D
if(GetComDir() == COMD_Right && GetDir() == 1 || GetComDir() == COMD_Left && GetDir() == 0)
{
if(Abs(iXSpeed) > 130 && iYSpeed <= 80 * 10)
SetAction("Roll");
else
DoKneel();
}
else
{
DoKneel();
}
}
func DoKneel()
{
var iKneelDownSpeed = 18;
SetXDir(0);
SetAction("Kneel");
Sound("RustleLand.ogg");
PlayAnimation("KneelDown", 5, Anim_Linear(0, 0, GetAnimationLength("KneelDown"), iKneelDownSpeed, ANIM_Remove), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
ScheduleCall(this, "EndKneel", iKneelDownSpeed, 1);
return 1;
}
func EndKneel()
{
if(GetAction() != "Roll") SetAction("Walk");
}
local rolllength;
local rolldir;
//rollp
func StartRoll()
{
Sound("Roll.ogg");
if(GetDir() == 1) rolldir = 1;
else
rolldir = -1;
rolllength = 22;
PlayAnimation("KneelRoll", 5, Anim_Linear(0, 0, 1500, rolllength, ANIM_Remove), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
AddEffect("Rolling", this, 1, 1, this);
}
func FxRollingTimer(object target, int num, int timer)
{
if(GetContact(-1)) SetXDir(23 * rolldir);
//Hacky fun
var i = 3;
while(GBackSolid(rolldir, 9) && i != 0)
{
SetPosition(GetX(),GetY() - 1);
i--;
}
if(timer > rolllength)
{
SetAction("Walk");
rolldir = nil;
return -1;
}
}
func StartDigging()
{
if(!GetEffect("IntDig", this))
AddEffect("IntDig", this, 1, 1, this);
}
func StopDigging()
{
if(GetAction() != "Dig") RemoveEffect("IntDig", this);
}
func FxIntDigStart(pTarget, effect, fTmp)
{
if(fTmp) return;
effect.var1 = PlayAnimation("Dig", 5, Anim_Linear(0, 0, GetAnimationLength("Dig"), 36, ANIM_Loop), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
// Update carried items
UpdateAttach();
// Sound
Sound("Dig*");
// Set proper turn type
SetTurnType(0);
}
func FxIntDigTimer(pTarget, effect, iTime)
{
if(iTime % 36 == 0)
{
Sound("Dig*");
}
if( (iTime-18) % 36 == 0 || iTime > 35)
{
var noDig = 1;
for(var pShovel in FindObjects(Find_ID(Shovel), Find_Container(this)))
if(pShovel->IsDigging()) noDig = 0;
if(noDig)
{
SetAction("Walk");
SetComDir(COMD_Stop);
return -1;
}
}
}
// custom throw
public func ControlThrow(object target, int x, int y)
{
// standard throw after all
if (!x && !y) return false;
if (!target) return false;
var throwAngle = Angle(0,0,x,y);
// walking (later with animation: flight, scale, hangle?) and hands free
if ( (GetProcedure() == "WALK" || GetAction() == "Jump" || GetAction() == "Dive")
&& this->~HasHandAction())
{
if (throwAngle < 180) SetDir(DIR_Right);
else SetDir(DIR_Left);
//SetAction("Throw");
this->~SetHandAction(1); // Set hands ocupied
AddEffect("IntThrow", this, 1, 1, this, 0, target, throwAngle);
return true;
}
// attached
if (GetProcedure() == "ATTACH")
{
//SetAction("RideThrow");
return DoThrow(target,throwAngle);
}
return false;
}
func FxIntThrowStart(target, effect, tmp, targetobj, throwAngle)
{
var iThrowTime = 16;
if(tmp) return;
PlayAnimation("ThrowArms", 10, Anim_Linear(0, 0, GetAnimationLength("ThrowArms"), iThrowTime), Anim_Const(1000));
effect.targetobj = targetobj;
effect.angle = throwAngle;
}
func FxIntThrowTimer(target, effect, time)
{
// cancel throw if object does not exist anymore
if(!effect.targetobj)
return -1;
var iThrowTime = 16;
if(time == iThrowTime*8/15)
DoThrow(effect.targetobj, effect.angle);
if(time >= iThrowTime)
return -1;
}
func FxIntThrowStop(target, effect, reason, tmp)
{
if(tmp) return;
StopAnimation(GetRootAnimation(10));
this->~SetHandAction(0);
}
func StartDead()
{
PlayAnimation("Dead", 5, Anim_Linear(0, 0, GetAnimationLength("Dead"), 20, ANIM_Hold), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
// Update carried items
UpdateAttach();
// Set proper turn type
SetTurnType(1);
}
func StartTumble()
{
if(GetEffect("IntTumble", this)) return;
// Close eyes
CloseEyes(1);
PlayAnimation("Tumble", 5, Anim_Linear(0, 0, GetAnimationLength("Tumble"), 20, ANIM_Loop), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
// Update carried items
UpdateAttach();
// Set proper turn type
SetTurnType(0);
AddEffect("IntTumble", this, 1, 0);
}
func StopTumble()
{
if(GetAction() != "Tumble")
{
RemoveEffect("IntTumble", this);
CloseEyes(-1);
}
}
/* Riding */
public func StartRiding()
{
if(!GetEffect("IntRiding", this))
AddEffect("IntRiding", this, 1, 0, this);
}
public func AttachTargetLost()
{
if(GetEffect("IntRiding", this))
RemoveEffect("IntRiding", this);
}
public func StopRiding()
{
if(GetEffect("IntRiding", this))
RemoveEffect("IntRiding", this);
}
func FxIntRidingStart(pTarget, effect, fTmp)
{
if(fTmp) return;
var pMount = GetActionTarget();
if(!pMount) return -1;
if(pMount->~OnMount(this)) // Notifiy the mount, that the clonk is mounted (it should take care, that the clonk get's attached!
{
// if mount has returned true we should be attached
// So make the clonk object invisible
effect.vis = GetProperty("Visibility");
SetProperty("Visibility", VIS_None);
}
else effect.vis = -1;
effect.mount = pMount;
}
func FxIntRidingStop(pTarget, effect, fTmp)
{
if(fTmp) return;
if(effect.vis != -1)
SetProperty("Visibility", effect.vis);
var pMount = effect.mount;
if(pMount)
pMount->~OnUnmount(this);
}
// calback from engine
func OnMaterialChanged(int new, int old)
{
if(!GetAlive()) return;
var newdens = GetMaterialVal("Density","Material",new);
var olddens = GetMaterialVal("Density","Material",old);
var newliquid = (newdens >= C4M_Liquid) && (newdens < C4M_Solid);
var oldliquid = (olddens >= C4M_Liquid) && (olddens < C4M_Solid);
// into water
if(newliquid && !oldliquid)
AddEffect("Bubble", this, 1, 52, this);
// out of water
else if(!newliquid && oldliquid)
RemoveEffect("Bubble", this);
}
func FxBubbleTimer(pTarget, effect, iTime)
{
if(GBackLiquid(0,-5))
{
var iRot = GetSwimRotation();
Bubble(1, +Sin(iRot, 9), Cos(iRot, 9));
}
}
func StartPushing()
{
// if(GetEffect("IntTumble", this)) return;
// Close eyes
PlayAnimation("Push", 5, Anim_AbsX(0, 0, GetAnimationLength("Push"), 20), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
// Update carried items
UpdateAttach();
// Set proper turn type
SetTurnType(1);
// AddEffect("IntTumble", this, 1, 0);
}
protected func StopPushing()
{
return _inherited(...);
}
func StartHangOnto()
{
// if(GetEffect("IntTumble", this)) return;
// Close eyes
PlayAnimation("OnRope", 5, Anim_Linear(0, 0, GetAnimationLength("OnRope"), 20, ANIM_Loop), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
// Update carried items
UpdateAttach();
// Set proper turn type
SetTurnType(1);
// AddEffect("IntTumble", this, 1, 0);
}
protected func AbortHangOnto()
{
if (GetActionTarget(0))
GetActionTarget(0)->~HangOntoLost(this);
return;
}
func QueryCatchBlow(object obj)
{
var r=0;
var e=0;
var i=0;
while(e=GetEffect("*Control*", this, i++))
{
if(EffectCall(this, e, "QueryCatchBlow", obj))
{
r=true;
break;
}
}
if(r) return r;
return _inherited(obj, ...);
}
local gender;
func SetSkin(int skin)
{
//Save to player's crew-member file which skin they are using
SetCrewExtraData("Skin", skin);
//Adventurer
if(skin == 0)
{ SetGraphics();
gender = 0; }
//Steampunk
if(skin == 1)
{ SetGraphics(nil, Skin_Steampunk);
gender = 1; }
//Alchemist
if(skin == 2)
{ SetGraphics(nil, Skin_Alchemist);
gender = 0; }
RemoveBackpack(); //add a backpack
AttachBackpack();
SetAction("Jump"); //refreshes animation
return skin;
}
/* Act Map */
local ActMap = {
Walk = {
Prototype = Action,
Name = "Walk",
Procedure = DFA_WALK,
Accel = 16,
Decel = 22,
Speed = 200,
Directions = 2,
FlipDir = 0,
Length = 1,
Delay = 0,
X = 0,
Y = 0,
Wdt = 8,
Hgt = 20,
StartCall = "StartWalk",
AbortCall = "StopWalk",
// InLiquidAction = "Swim",
},
Stand = {
Prototype = Action,
Name = "Stand",
Procedure = DFA_THROW,
Directions = 2,
FlipDir = 0,
Length = 1,
Delay = 0,
X = 0,
Y = 0,
Wdt = 8,
Hgt = 20,
StartCall = "StartStand",
InLiquidAction = "Swim",
},
Kneel = {
Prototype = Action,
Name = "Kneel",
Procedure = DFA_KNEEL,
Directions = 2,
FlipDir = 0,
Length = 1,
Delay = 0,
X = 0,
Y = 0,
Wdt = 8,
Hgt = 20,
// StartCall = "StartKneel",
InLiquidAction = "Swim",
},
Roll = {
Prototype = Action,
Name = "Roll",
Procedure = DFA_NONE,
Directions = 2,
FlipDir = 0,
Length = 1,
Delay = 0,
X = 0,
Y = 0,
Wdt = 8,
Hgt = 20,
StartCall = "StartRoll",
NextAction = "Walk",
InLiquidAction = "Swim",
},
Scale = {
Prototype = Action,
Name = "Scale",
Procedure = DFA_SCALE,
Speed = 60,
Accel = 20,
Attach = CNAT_MultiAttach,
Directions = 2,
Length = 1,
Delay = 0,
X = 0,
Y = 20,
Wdt = 8,
Hgt = 20,
OffX = 0,
OffY = 0,
StartCall = "StartScale",
AbortCall = "StopScale",
},
Tumble = {
Prototype = Action,
Name = "Tumble",
Procedure = DFA_FLIGHT,
Speed = 200,
Accel = 0,
Directions = 2,
Length = 1,
Delay = 0,
X = 0,
Y = 40,
Wdt = 8,
Hgt = 20,
NextAction = "Tumble",
ObjectDisabled = 1,
InLiquidAction = "Swim",
StartCall = "StartTumble",
AbortCall = "StopTumble",
EndCall = "CheckStuck",
},
Dig = {
Prototype = Action,
Name = "Dig",
Procedure = DFA_DIG,
Speed = 50,
Directions = 2,
Length = 16,
Delay = 0,//15*3*0,
X = 0,
Y = 60,
Wdt = 8,
Hgt = 20,
NextAction = "Dig",
StartCall = "StartDigging",
AbortCall = "StopDigging",
DigFree = 11,
// InLiquidAction = "Swim",
Attach = CNAT_Left | CNAT_Right | CNAT_Bottom,
},
Bridge = {
Prototype = Action,
Name = "Bridge",
Procedure = DFA_THROW,
Directions = 2,
Length = 16,
Delay = 1,
X = 0,
Y = 60,
Wdt = 8,
Hgt = 20,
NextAction = "Bridge",
InLiquidAction = "Swim",
},
Swim = {
Prototype = Action,
Name = "Swim",
Procedure = DFA_SWIM,
Speed = 96,
Accel = 7,
Decel = 9,
Directions = 2,
Length = 1,
Delay = 0,
X = 0,
Y = 80,
Wdt = 8,
Hgt = 20,
OffX = 0,
OffY = 0,
// SwimOffset = -5,
StartCall = "StartSwim",
AbortCall = "StopSwim",
},
Hangle = {
Prototype = Action,
Name = "Hangle",
Procedure = DFA_HANGLE,
Speed = 48,
Accel = 20,
Directions = 2,
Length = 1,
Delay = 0,
X = 0,
Y = 100,
Wdt = 8,
Hgt = 20,
OffX = 0,
OffY = 3,
StartCall = "StartHangle",
AbortCall = "StopHangle",
InLiquidAction = "Swim",
},
Jump = {
Prototype = Action,
Name = "Jump",
Procedure = DFA_FLIGHT,
Speed = 200,
Accel = 14,
Directions = 2,
Length = 1,
Delay = 0,
X = 0,
Y = 120,
Wdt = 8,
Hgt = 20,
InLiquidAction = "Swim",
PhaseCall = "CheckStuck",
StartCall = "StartJump",
},
WallJump = {
Prototype = Action,
Name = "WallJump",
Procedure = DFA_FLIGHT,
Speed = 200,
Accel = 14,
Directions = 2,
Length = 1,
Delay = 0,
X = 0,
Y = 120,
Wdt = 8,
Hgt = 20,
InLiquidAction = "Swim",
PhaseCall = "CheckStuck",
},
Dive = {
Prototype = Action,
Name = "Dive",
Procedure = DFA_FLIGHT,
Speed = 200,
Accel = 16,
Directions = 2,
Length = 8,
Delay = 4,
X = 0,
Y = 160,
Wdt = 8,
Hgt = 20,
NextAction = "Hold",
ObjectDisabled = 1,
InLiquidAction = "Swim",
PhaseCall = "CheckStuck",
},
Dead = {
Prototype = Action,
Name = "Dead",
Directions = 2,
X = 0,
Y = 240,
Wdt = 8,
Hgt = 20,
Length = 1,
Delay = 0,
NextAction = "Hold",
StartCall = "StartDead",
NoOtherAction = 1,
ObjectDisabled = 1,
},
Ride = {
Prototype = Action,
Name = "Ride",
Procedure = DFA_ATTACH,
Directions = 2,
Length = 1,
Delay = 0,
X = 128,
Y = 120,
Wdt = 8,
Hgt = 20,
StartCall = "StartRiding",
AbortCall = "StopRiding",
InLiquidAction = "Swim",
},
Push = {
Prototype = Action,
Name = "Push",
Procedure = DFA_PUSH,
Speed = 200,
Accel = 100,
Directions = 2,
Length = 8,
Delay = 15,
X = 128,
Y = 140,
Wdt = 8,
Hgt = 20,
NextAction = "Push",
StartCall = "StartPushing",
AbortCall = "StopPushing",
InLiquidAction = "Swim",
},
Build = {
Prototype = Action,
Name = "Build",
Directions = 2,
Length = 8,
Delay = 15,
X = 128,
Y = 140,
Wdt = 8,
Hgt = 20,
NextAction = "Build",
InLiquidAction = "Swim",
Attach = CNAT_Bottom,
},
HangOnto = {
Prototype = Action,
Name = "HangOnto",
Procedure = DFA_ATTACH,
Directions = 2,
Length = 1,
Delay = 0,
X = 128,
Y = 120,
Wdt = 8,
Hgt = 20,
StartCall = "StartHangOnto",
AbortCall = "AbortHangOnto",
InLiquidAction = "Swim",
},
};
local Name = "Clonk";
local MaxEnergy = 50000;
local MaxBreath = 252; // Clonk can breathe for 7 seconds under water.
local JumpSpeed = 400;
local ThrowSpeed = 294;
func Definition(def) {
// Set perspective
SetProperty("PictureTransformation", Trans_Mul(Trans_Translate(0,1000,5000), Trans_Rotate(70,0,1,0)), def);
_inherited(def);
}