/** Chippy Small, lovely creatures. */ local Name = "$Name$"; local Description = "$Description$"; // Remember the attachee to be able to detach again. local attach_object, attached_mesh; // Remember the energy sucked to frequently spawn offsprings. local energy_sucked; public func Construction() { AddEffect("Activity", this, 1, 10, this); SetAction("Walk"); energy_sucked = 0; return true; } public func Destruction() { if (GetAction() == "Clawing") StopClawing(); } public func Death() { var particles = { Prototype = Particles_Material(RGB(50, 200, 50)), OnCollision = PC_Bounce(), DampingX = 900, DampingY = 900, }; for (var particle_graphics in ["SmokeDirty", "Flash"]) { CreateParticle(particle_graphics, PV_Random(-1, 1), PV_Random(-1, 1), PV_Random(-20, 20), PV_Random(-20, 20), PV_Random(20, 60), particles, 60); } Sound("Animals::Chippie::Chirp*", false, 50); RemoveObject(); } public func AttachTargetLost() { SetAction("Jump"); } private func StartClawing() { AddEffect("Clawing", this, 1, 30, this); } private func StopClawing() { if (attach_object && attached_mesh != nil) attach_object->DetachMesh(attached_mesh); this.Visibility = VIS_All; RemoveEffect("Clawing", this); SetVertexXY(0, 0, -1); } private func FxClawingTimer(target, effect, time) { var e = GetActionTarget(); if(!e) return SetAction("Jump"); if((!e->GetAlive()) || GBackSemiSolid()) { SetAction("Jump"); return; } if(!Random(3)) { var damage = GetCon() * 10; e->DoEnergy(-damage, true, FX_Call_EngGetPunched, GetOwner()); energy_sucked += damage; if (energy_sucked > 10 * 1000) { LayEgg(); energy_sucked -= 10 * 1000; } // Grow and prosper. if (GetCon() < 150 && !Random(10)) { DoCon(1); DoEnergy(5); } } } private func StartJump() { RotateGraphics(0, false); if(!GetEffect("DmgShock", this) && !GetEffect("JumpCheck", this)) AddEffect("JumpCheck", this, 1, 4, this); } private func FxJumpCheckTimer(target, effect, time) { var e = FindObject(Find_AtPoint(), Find_OCF(OCF_Alive), Find_AnimalHostile(GetOwner())); if(e) { ClawTo(e); return -1; } } private func ClawTo(object obj) { // Play the sound on the object, because the chippie turns invisible. obj->Sound("Animals::Chippie::Bite*", false, 50); energy_sucked += 5 * 1000; obj->DoEnergy(-5, false, FX_Call_EngGetPunched, GetOwner()); // Woops, I broke it. if (!obj || !obj->GetAlive()) return; SetAction("Claw", obj); SetVertexXY(0, obj->GetX() - GetX(), obj->GetY() - GetY()); // Special handling for the Clonk - attach directly to a random bone. if (obj->~IsClonk()) { var bone_name = ["skeleton_leg_upper.R", "skeleton_leg_upper.L", "skeleton_arm_upper.R", "skeleton_arm_upper.L", "pos_back2"][Random(5)]; attach_object = obj; var scale = GetCon() * 1000 / 100; attached_mesh = attach_object->AttachMesh(this, bone_name, "back", Trans_Mul(Trans_Scale(scale, scale, scale), Trans_Rotate(Random(360), 0, 1, 0))); // Hide the attached object. this.Visibility = VIS_None; } else { this.MeshTransformation = Trans_Mul(Trans_Rotate(90, 0, 1, 0), Trans_Rotate(Random(360), 0, 0, 1)); } } private func EndJump() { RemoveEffect("JumpCheck", this); } private func StartWalk() { RotateGraphics(0, false); } private func StartScale() { RotateGraphics(90, false); } private func RotateGraphics(int r, bool mirror) { var transform = Trans_Rotate(r, 0, 0, 1); if (mirror) transform = Trans_Mul(transform, Trans_Scale(-1000, 1000, 1000)); this.MeshTransformation = transform; } private func StartHangle() { RotateGraphics(180, true); } private func Jump() { SetAction("Jump"); SetSpeed(GetXDir(), -10 - GetXDir()); } private func FxActivityTimer(target, effect, time) { if((GetAction() == "Jump") || (GetAction() == "Claw")) { return 1; } if(GetComDir() != COMD_Stop) if(!Random(5)) Jump(); if(!GetEffect("DmgShock", this) && !GBackSemiSolid()) { for(var enemy in FindObjects(Find_Distance(100), Find_OCF(OCF_Alive), Find_AnimalHostile(GetOwner()), Sort_Distance())) { if(!PathFree(GetX(), GetY(), enemy->GetX(), enemy->GetY())) continue; if(enemy->GetX() < GetX()) SetComDir(COMD_Left); else SetComDir(COMD_Right); if(ObjectDistance(this, enemy) < 20) { SetAction("Jump"); var a = Angle(GetX(), GetY(), enemy->GetX(), enemy->GetY()); SetSpeed(Sin(a, 20), -Cos(a, 20) - 2); } return 1; } if(GetEffect("DoDance", this)) { if(GetAction() == "Walk") { SetComDir(COMD_Stop); Jump(); return 1; } } else if(!Random(20) && !GetEffect("DanceCooldown", this)) { Sound("Animals::Chippie::Talk*"); var cnt = 0; for(var obj in FindObjects(Find_Distance(100), Find_ID(GetID()), Find_Allied(GetOwner()), Sort_Distance())) { if(++cnt > 5) break; obj->AddEffect("DoDance", obj, 1, 35*5, obj); obj->AddEffect("DanceCooldown", obj, 1, 35*10, obj); } if(!GetEffect("EggCooldown", this)) { if(!Random(10)) { LayEgg(); } } } } if(!Random(5)) { if(Random(2)) SetComDir(COMD_Right); else SetComDir(COMD_Left); } else SetComDir(COMD_Stop); return 1; } private func FxActivityDamage(target, effect, dmg) { if(dmg > 0) return dmg; AddEffect("DmgShock", this, 1, 35*5, this); return dmg; } private func LayEgg() { if(GetEffect("DmgShock", this)) return; var o = CreateObject(Chippie_Egg, 0, 0, GetOwner()); o->SetSpeed(-GetXDir(), -GetYDir()); o->SetCon(50); o->StartGrowth(10); AddEffect("EggCooldown", this, 1, 35*30, this); } local MaxEnergy = 10000; local MaxBreath = 10000; local NoBurnDecay = 1; local ContactIncinerate = 15; local CorrosionResist = 1; local BorderBound = C4D_Border_Sides; local ContactCalls = true; local ActMap = { Walk = { Prototype = Action, Name = "Walk", Procedure = DFA_WALK, Accel = 16, Decel = 22, Speed = 100, Directions = 2, FlipDir = 1, Length = 20, Delay = 1, Animation = "Move", StartCall = "StartWalk" }, Swim = { Prototype = Action, Name = "Swim", Procedure = DFA_SWIM, Accel = 16, Decel = 22, Speed = 100, Directions = 2, FlipDir = 1, Length = 20, Delay = 1, Animation = "Move", StartCall = "StartWalk" }, Scale = { Prototype = Action, Name = "Scale", Procedure = DFA_SCALE, Accel = 16, Decel = 22, Speed = 50, Directions = 2, FlipDir = 1, Length = 20, Delay = 2, Animation = "Move", StartCall = "StartScale" }, Hangle = { Prototype = Action, Name = "Hangle", Procedure = DFA_HANGLE, Accel = 16, Decel = 22, Speed = 50, Directions = 2, FlipDir = 1, Length = 20, Delay = 2, Animation = "Move", StartCall = "StartHangle" }, Kneel = { Prototype = Action, Name = "Kneel", Procedure = DFA_KNEEL, Directions = 2, FlipDir = 1, Length = 20, Delay = 2, Animation = "Move", NextAction = "Walk", }, Jump = { Prototype = Action, Name = "Jump", Procedure = DFA_FLIGHT, Speed = 200, Accel = 14, Directions = 2, FlipDir = 1, Length = 20, Delay = 2, Animation = "Move", StartCall = "StartJump", EndCall = "EndJump", AbortCall = "EndJump" }, Dead = { Prototype = Action, Name = "Dead", Directions = 2, FlipDir = 1, Length = 10, Delay = 3, Animation = "Move", NextAction = "Hold", NoOtherAction = 1, ObjectDisabled = 1, }, Claw = { Prototype = Action, Name = "Claw", Procedure = DFA_ATTACH, Directions = 2, FlipDir = 1, Length = 1, Delay = 0, Animation = "Move", NextAction = "Hold", StartCall = "StartClawing", EndCall = "StopClawing", AbortCall = "StopClawing", }, };