diff --git a/planet/Experimental.ocf/Shark.ocs/MapFg.bmp b/planet/Experimental.ocf/Shark.ocs/MapFg.bmp new file mode 100644 index 000000000..34cf68e83 Binary files /dev/null and b/planet/Experimental.ocf/Shark.ocs/MapFg.bmp differ diff --git a/planet/Experimental.ocf/Shark.ocs/Scenario.txt b/planet/Experimental.ocf/Shark.ocs/Scenario.txt new file mode 100644 index 000000000..1f22a1a4a --- /dev/null +++ b/planet/Experimental.ocf/Shark.ocs/Scenario.txt @@ -0,0 +1,14 @@ +[Head] +Icon=1 +Title=Sharks + +[Game] +Goals=MELE=1 + +[Player1] +Wealth=10 +Crew=Clonk=1; + +[Landscape] +NoScan=1 +MapZoom=12 \ No newline at end of file diff --git a/planet/Experimental.ocf/Shark.ocs/Script.c b/planet/Experimental.ocf/Shark.ocs/Script.c new file mode 100644 index 000000000..3218eefbe --- /dev/null +++ b/planet/Experimental.ocf/Shark.ocs/Script.c @@ -0,0 +1,30 @@ +func Initialize() +{ + Shark->Place(3); + Squid->Place(1); + Seaweed->Place(71); + Coral->Place(4); + Fern->Place(2); + Tree_Deciduous->Place(6); + Tree_Deciduous_Burned->Place(1); + SproutBerryBush->Place(3); + Butterfly->Place(1); +} + +private func InitializePlayer(iPlr) +{ + SetFoW(0, iPlr); + var crew = GetCrew(iPlr); + crew->SetPosition(10,300); + crew->CreateContents(Shovel); + crew->CreateContents(Hammer); + crew->CreateContents(Rock, 3); +} + +func RelaunchPlayer(int iPlr) +{ + var pclonk = CreateObject(Clonk, 10,300, iPlr); + pclonk->MakeCrewMember(iPlr); + SetCursor(iPlr, pclonk); + pclonk->CreateContents(Shovel); +} diff --git a/planet/Objects.ocd/Animals.ocd/Shark.ocd/DefCore.txt b/planet/Objects.ocd/Animals.ocd/Shark.ocd/DefCore.txt new file mode 100644 index 000000000..f4a02c3e8 --- /dev/null +++ b/planet/Objects.ocd/Animals.ocd/Shark.ocd/DefCore.txt @@ -0,0 +1,18 @@ +[DefCore] +id=Shark +Version=6,0 +Category=C4D_Living +Width=56 +Height=22 +Offset=-28,-11 +Vertices=8 +VertexX=-12,0,12,-18,-8,8,18 +VertexY=-5,-5,-5,2,5,5,2,9 +VertexCNAT=4,4,4,1,1,2,2,8 +VertexFriction=100,100,100,100,100,100,100,100 +Value=20 +Mass=70 +StretchGrowth=1 +IncompleteActivity=1 +Oversize=1 +Float=1 diff --git a/planet/Objects.ocd/Animals.ocd/Shark.ocd/Graphics.mesh b/planet/Objects.ocd/Animals.ocd/Shark.ocd/Graphics.mesh new file mode 100644 index 000000000..c53cd937b Binary files /dev/null and b/planet/Objects.ocd/Animals.ocd/Shark.ocd/Graphics.mesh differ diff --git a/planet/Objects.ocd/Animals.ocd/Shark.ocd/Scene.material b/planet/Objects.ocd/Animals.ocd/Shark.ocd/Scene.material new file mode 100644 index 000000000..52ed05dd4 --- /dev/null +++ b/planet/Objects.ocd/Animals.ocd/Shark.ocd/Scene.material @@ -0,0 +1,21 @@ +material Shark +{ + receive_shadows on + technique + { + pass + { + ambient 1.000000 1.000000 1.000000 1.000000 + diffuse 1.000000 1.000000 1.000000 1.000000 + specular 0.000000 0.000000 0.000000 1.000000 12.500000 + emissive 0.000000 0.000000 0.000000 1.000000 + + texture_unit + { + texture Shark.png + tex_address_mode wrap + filtering trilinear + } + } + } +} diff --git a/planet/Objects.ocd/Animals.ocd/Shark.ocd/Script.c b/planet/Objects.ocd/Animals.ocd/Shark.ocd/Script.c new file mode 100644 index 000000000..4909eeeae --- /dev/null +++ b/planet/Objects.ocd/Animals.ocd/Shark.ocd/Script.c @@ -0,0 +1,428 @@ +/** + Shark + Very strong water animal. + + @author Armin +*/ + +local BiteStrength = 25; +local attacking, walking, swimming, swim_animation, base_transform, turned; + +private func Construction() +{ + StartGrowth(15); + SetAction("Swim"); + if (!Random(2)) + SetComDir(COMD_Right); + else + SetComDir(COMD_Left); + if (GetAlive()) + AddTimer(this.Activity, 10); + + return _inherited(...); +} + +private func Attack(object target, int x, int y) +{ + if (!attacking || (target->GetAction() != "Swim" && target->GetAction() != "Jump") || !target->GetAlive() || !PathFree(GetX(), GetY(), target->GetX(), target->GetY())) + { + SetCommand("None"); + attacking = false; + SetAction("Swim"); + return 1; + } + var dis = Distance(GetX(), GetY(), target->GetX(), target->GetY()); + if (dis > 30) + { + var current_angle=Angle(GetX(), GetY(), target->GetX(), target->GetY()); + if (current_angle < 0) current_angle = 360 + current_angle; + var t = current_angle - 270; + var t2 = Cos(t, 90) - 90; // Expand the areas around 0deg and 180deg a bit so you see fish from the side more + this.MeshTransformation = Trans_Mul(Trans_Rotate(t, 0, 0, 1), Trans_Rotate(t2, 1, 0, 0)); + } + this->SetCommand("MoveTo", target); + if (dis < 20) + { + // Victim near. Bite him. + SetAction("Bite"); + Sound("Animals::Fish::Munch*"); + if (target->GetAlive()) + target->DoEnergy(-BiteStrength); + DoEnergy(BiteStrength); + + // Mission succesful. Swim back to the initial position. + SetCommand("None"); + this["MeshTransformation"] = Trans_Identity(); + this->SetCommand("MoveTo", nil, x, y); + ScheduleCall(this, "ResetHunger", 300); + return 1; + } + ScheduleCall(this, "Attack", 5, 0, target, x, y); +} + +private func Turn() +{ + if (GetCommand() != nil) + return 1; + SetComDir(COMD_None); + SetXDir(0); + SetYDir(0); + SetAction("Turn"); + + // The shark should now turn around in very short intervalls. + turned = true; + ScheduleCall(this, "ResetTurn", 80); +} + +private func Activity() +{ + if (GetAction() == "Turn") + return; + if (swimming) + { + if (Inside(GetXDir(), -6, 6) && !turned && GetAction() != "FastSwim") + { + SetCommand("None"); + Turn(); + } + else if (!attacking) + { + var target = FindObject(Find_ID(Clonk), Find_Distance(380), Find_Action("Swim")); + if (target) + if (PathFree(GetX(), GetY(), target->GetX(), target->GetY())) + { + attacking = true; + SetAction("FastSwim"); + Attack(target, GetX(), GetY()); + return 1; + } + + // Avoid surface. + if (!GBackLiquid(0, -10)) + { + if (GetDir()) + SetComDir(COMD_DownRight); + else + SetComDir(COMD_DownLeft); + return 1; + } + + // Avoid ground. + if (!GBackLiquid(0, 25)) + { + if (GetDir()) + SetComDir(COMD_UpRight); + else + SetComDir(COMD_UpLeft); + return 1; + } + + if (!turned) + { + // Wall? + if ((GBackSolid(+75, 0) && GetDir() == DIR_Right) ^ (GBackSolid(-75, 0) && GetDir() == DIR_Left)) + { + Turn(); + return; + } + + if (!Random(40)) + { + Turn(); + return 1; + } + } + } + } + else if (walking) + { + // PANIC WHERE THE WATER AT + var rx = RandomX(10, 25); + if (!Random(2)) rx *= -1; + + var has_water = false; + for (var y = 0; y <= 12; y += 4) + { + if (!GBackLiquid(rx, y)) continue; + has_water = true; + break; + } + + if (has_water) + { + if (rx < 0) SetComDir(COMD_Left); + else SetComDir(COMD_Right); + + if (!Random(2)) + DoJump(); + return true; + } + else + { + if (!Random(2)) + { + if (!Random(2)) SetComDir(COMD_Left); + else SetComDir(COMD_Right); + } + if (!Random(3)) + DoJump(); + } + } + return 1; +} + +private func Place(int amount, proplist rectangle, proplist settings) +{ + var max_tries = 2 * amount; + var loc_area = nil; + if (rectangle) loc_area = Loc_InArea(rectangle); + var f; + + while ((amount > 0) && (--max_tries > 0)) + { + var spot = FindLocation(Loc_Material("Water"), Loc_Space(20), loc_area); + if (!spot) continue; + + f = CreateObjectAbove(this, spot.x, spot.y, NO_OWNER); + if (!f) continue; + // Randomly add some large/slim fish + if (Random(3)) + { + // There are naturally smaller and larger sharks. + f->SetCon(RandomX(80, 120)); + // make sure the smaller ones don't grow larger any more + f->StopGrowth(); + // Slim fish. + if (f->GetCon() > 100 || !Random(3)) + f->SetYZScale(1000 - Random(300)); + } + + if (f->Stuck()) + { + f->RemoveObject(); + continue; + } + --amount; + } + return f; // return last created fish +} + +private func SetYZScale(int new_scale) +{ + base_transform = Trans_Scale(1000, new_scale, new_scale); + return true; +} + +private func Death() +{ + RemoveTimer(this.UpdateSwim); + RemoveTimer(this.Activity); + this.MeshTransformation = Trans_Rotate(160 + Random(41), 1, 0, 0); + if (base_transform) this.MeshTransformation = Trans_Mul(base_transform, this.MeshTransformation); + StopAnimation(swim_animation); + Decay(); + this.Collectible = true; + + // Maybe respawn a new fish if roe is near. + var roe = FindObject(Find_Distance(200), Find_ID(FishRoe)); + if (roe) + roe->Hatch(GetID()); + + return _inherited(...); +} + +private func DoJump() +{ + SetAction("Jump"); + Sound("Hits::SoftTouch*"); + + var x_dir = RandomX(ActMap.Jump.Speed/2, ActMap.Jump.Speed); + if (GetComDir() == COMD_Left) x_dir *= -1; + var y_dir = -RandomX(ActMap.Jump.Speed/3, ActMap.Jump.Speed); + SetSpeed(x_dir, y_dir); +} + +private func StartWalk() +{ + var len = GetAnimationLength("Swim"); + var pos = GetAnimationPosition(swim_animation); + SetAnimationPosition(swim_animation, Anim_Linear(pos, 0, len, 10, ANIM_Loop)); + this.MeshTransformation = Trans_Mul(Trans_Rotate(90 + RandomX(-10, 10), 1, 0, 0), base_transform); + SetObjDrawTransform(0,0,0,0,0,0); + swim_animation = PlayAnimation("Swim", 5, Anim_Linear(0, 0, len, 100, ANIM_Loop), Anim_Const(500)); + if (GBackLiquid()) + { + SetAction("Swim"); + return; + } + walking = true; + swimming = false; + + ResetHunger(); +} + +private func StartSwim() +{ + StopAnimation(GetRootAnimation(5)); + swimming = true; + walking = false; + this["MeshTransformation"] = Trans_Identity(); + if (GetCommand() != nil) + return 1; + if (GetDir() == DIR_Left) + { + SetDir(DIR_Right); + if (!Random(5)) SetComDir(COMD_UpRight); + else if (!Random(6)) SetComDir(COMD_DownRight); + else SetComDir(COMD_Right); + } + else + { + SetDir(DIR_Left); + if (!Random(5)) SetComDir(COMD_UpLeft); + else if (!Random(6)) SetComDir(COMD_DownLeft); + else SetComDir(COMD_Left); + } +} + +private func StartJump() +{ + if (GBackLiquid()) + { + SetAction("Swim"); + return; + } + swimming = false; + walking = false; +} + +private func ResetHunger() +{ + attacking = false; +} + +private func ResetTurn() +{ + turned = false; +} + +local ActMap = { +Swim = { + Prototype = Action, + Name = "Swim", + Procedure = DFA_SWIM, + Speed = 100, + Accel = 64, + Decel = 16, + Length = 52, + Delay = 10, + Directions = 2, + FlipDir = 1, + StartCall = "StartSwim", + Animation = "Swim" +}, +FastSwim = { + Prototype = Action, + Name = "FastSwim", + Procedure = DFA_SWIM, + Speed = 200, + Accel = 48, + Decel = 16, + Length = 20, + Delay = 5, + Directions = 2, + FlipDir = 0, + NextAction = "FastSwim", + Animation = "Swim" +}, +Turn = { + Prototype = Action, + Name = "Turn", + Procedure = DFA_SWIM, + Speed = 100, + Accel = 16, + Decel = 16, + Length = 52, + Delay = 10, + Directions = 2, + FlipDir = 1, + NextAction = "Swim", + Animation = "Turn" +}, +Bite = { + Prototype = Action, + Name = "Bite", + Procedure = DFA_SWIM, + Speed = 100, + Accel = 16, + Decel = 16, + Length = 2, + Delay = 10, + Directions = 2, + NextAction = "Swim", + Animation = "Bite" +}, +Walk = { + Prototype = Action, + Name = "Walk", + Procedure = DFA_WALK, + Speed = 30, + Accel = 16, + Decel = 16, + Length = 1, + Delay = 0, + FacetBase=1, + Directions = 2, + FlipDir = 1, + NextAction = "Walk", + StartCall = "StartWalk", + InLiquidAction = "Swim", +}, +Jump = { + Prototype = Action, + Name = "Jump", + Procedure = DFA_FLIGHT, + Speed = 30, + Accel = 16, + Decel = 16, + Length = 1, + Delay = 0, + FacetBase=1, + Directions = 2, + FlipDir = 1, + NextAction = "Jump", + StartCall = "StartJump", + InLiquidAction = "Swim", +}, +Dead = { + Prototype = Action, + Name = "Dead", + Procedure = DFA_NONE, + Speed = 10, + Length = 1, + Delay = 0, + FacetBase=1, + Directions = 2, + FlipDir = 1, + NextAction = "Hold", + NoOtherAction = 1, + ObjectDisabled = 1, + Animation = "Death" +} +}; +local Name = "$Name$"; +local Description = "$Description$"; +local MaxEnergy = 150000; +local MaxBreath = 360; // 360 = ten seconds +local Placement = 1; +local NoBurnDecay = 1; +local BreatheWater = 1; +local BorderBound = C4D_Border_Sides | C4D_Border_Top | C4D_Border_Bottom; + +func IsPrey() { return false; } +func IsPredator() { return true; } + +public func Definition(def) +{ + SetProperty("PictureTransformation", Trans_Mul(Trans_Rotate(20,1,0,0),Trans_Rotate(70,0,1,0)), def); +} diff --git a/planet/Objects.ocd/Animals.ocd/Shark.ocd/Shark.png b/planet/Objects.ocd/Animals.ocd/Shark.ocd/Shark.png new file mode 100644 index 000000000..586db7d9f Binary files /dev/null and b/planet/Objects.ocd/Animals.ocd/Shark.ocd/Shark.png differ diff --git a/planet/Objects.ocd/Animals.ocd/Shark.ocd/Shark.skeleton b/planet/Objects.ocd/Animals.ocd/Shark.ocd/Shark.skeleton new file mode 100644 index 000000000..9590e7835 Binary files /dev/null and b/planet/Objects.ocd/Animals.ocd/Shark.ocd/Shark.skeleton differ diff --git a/planet/Objects.ocd/Animals.ocd/Shark.ocd/StringTblDE.txt b/planet/Objects.ocd/Animals.ocd/Shark.ocd/StringTblDE.txt new file mode 100644 index 000000000..bcfe45612 --- /dev/null +++ b/planet/Objects.ocd/Animals.ocd/Shark.ocd/StringTblDE.txt @@ -0,0 +1,2 @@ +Name=Hai +Description=Unterwasserlebewesen mit extrem starker Beißkraft. diff --git a/planet/Objects.ocd/Animals.ocd/Shark.ocd/StringTblUS.txt b/planet/Objects.ocd/Animals.ocd/Shark.ocd/StringTblUS.txt new file mode 100644 index 000000000..837d3317f --- /dev/null +++ b/planet/Objects.ocd/Animals.ocd/Shark.ocd/StringTblUS.txt @@ -0,0 +1,2 @@ +Name=Shark +Description=Underwater animal with extremely strong bite force. diff --git a/planet/Worlds.ocf/Clonkomotive.ocs/Script.c b/planet/Worlds.ocf/Clonkomotive.ocs/Script.c index e0f25b1d1..dd4ba5354 100644 --- a/planet/Worlds.ocf/Clonkomotive.ocs/Script.c +++ b/planet/Worlds.ocf/Clonkomotive.ocs/Script.c @@ -165,9 +165,10 @@ private func InitVegetation(int map_size, int difficulty) private func InitAnimals(int map_size, int difficulty) { - // Place some fish and piranhas. + // Place some fish, sharks and piranhas. Fish->Place(20 + 4 * map_size); Piranha->Place((10 + 4 * map_size) * (difficulty - 1)); + Shark->Place(difficulty - 1); // Some insects: zaps, mosquitos, butterflies, fireflies. Zaphive->Place(2 + 4 * difficulty);