diff --git a/planet/Arena.ocf/HotIce.ocs/Map.c b/planet/Arena.ocf/HotIce.ocs/Map.c index 70c5533ce..837a208f5 100644 --- a/planet/Arena.ocf/HotIce.ocs/Map.c +++ b/planet/Arena.ocf/HotIce.ocs/Map.c @@ -77,6 +77,9 @@ func DrawSmallIslandsMap(proplist map) if (Abs(x-w/2) < w/10) szx += Random(3); // central islands sometimes wider map->Draw("^Ice-ice2", nil, [x-szx,y,1+2*szx,szy]); } + // Balloon spawn: do nothing further + if (SCENPAR_SpawnType == 1) + return true; // Starting islands for player spawns var spawn_island_count = Max(GetStartupPlayerCount(), 2); g_player_spawn_positions = CreateArray(spawn_island_count); diff --git a/planet/Arena.ocf/HotIce.ocs/ParameterDefs.txt b/planet/Arena.ocf/HotIce.ocs/ParameterDefs.txt index 0b0258015..ed18f2980 100644 --- a/planet/Arena.ocf/HotIce.ocs/ParameterDefs.txt +++ b/planet/Arena.ocf/HotIce.ocs/ParameterDefs.txt @@ -34,6 +34,24 @@ Default=1 Description=$DescWeaponsExplosive$ Value=1 +[ParameterDef] +Name=$SpawnType$ +Description=$DescSpawn$ +ID=SpawnType +Default=1 + + [Options] + + [Option] + Name=$ClassicSpawn$ + Description=$DescClassicSpawn$ + Value=0 + + [Option] + Name=$BalloonSpawn$ + Description=$DescBalloonSpawn$ + Value=1 + [ParameterDef] Name=$Rounds$ Description=$DescRounds$ diff --git a/planet/Arena.ocf/HotIce.ocs/Script.c b/planet/Arena.ocf/HotIce.ocs/Script.c index 5a0d941c8..288fd0e1f 100644 --- a/planet/Arena.ocf/HotIce.ocs/Script.c +++ b/planet/Arena.ocf/HotIce.ocs/Script.c @@ -61,7 +61,8 @@ func InitializeRound() // Checking for victory: Only active after a Clonk dies. g_check_victory_effect = AddEffect("CheckVictory", nil, 1, 0); g_player_spawn_index = 0; - ShuffleArray(g_player_spawn_positions); + if (GetType(g_player_spawn_positions) == C4V_Array) + ShuffleArray(g_player_spawn_positions); // Materials: Chests var i,pos; @@ -142,20 +143,34 @@ func InitPlayerRound(int plr) var ls_wdt = LandscapeWidth(), ls_hgt = LandscapeHeight(); var crew = GetCrew(plr), start_pos; // Position by map type? - if (g_player_spawn_positions && g_player_spawn_index < GetLength(g_player_spawn_positions)) + if (SCENPAR_SpawnType == 0) { - start_pos = g_player_spawn_positions[g_player_spawn_index++]; - var map_zoom = ls_wdt / g_map_width; - start_pos = {x=start_pos[0]*map_zoom+map_zoom/2, y=start_pos[1]*map_zoom}; + if (g_player_spawn_positions && g_player_spawn_index < GetLength(g_player_spawn_positions)) + { + start_pos = g_player_spawn_positions[g_player_spawn_index++]; + var map_zoom = ls_wdt / g_map_width; + start_pos = {x=start_pos[0]*map_zoom+map_zoom/2, y=start_pos[1]*map_zoom}; + } + else + { + // Start positions not defined or exhausted: Spawn in lower area for both maps becuase starting high is an an advantage. + start_pos = FindLocation(Loc_InRect(ls_wdt/5,ls_hgt/2,ls_wdt*3/5,ls_hgt/3), Loc_Wall(CNAT_Bottom), Loc_Func(Scenario.IsStartSpot)); + if (!start_pos) start_pos = FindLocation(Loc_InRect(ls_wdt/10,0,ls_wdt*8/10,ls_hgt*4/5), Loc_Wall(CNAT_Bottom), Loc_Func(Scenario.IsStartSpot)); + if (!start_pos) start_pos = {x=Random(ls_wdt*6/10)+ls_wdt*2/10, y=ls_hgt*58/100}; + } + crew->SetPosition(start_pos.x, start_pos.y-10); } - else + else // Balloon spawn { - // Start positions not defined or exhausted: Spawn in lower area for both maps becuase starting high is an an advantage. - start_pos = FindLocation(Loc_InRect(ls_wdt/5,ls_hgt/2,ls_wdt*3/5,ls_hgt/3), Loc_Wall(CNAT_Bottom), Loc_Func(Scenario.IsStartSpot)); - if (!start_pos) start_pos = FindLocation(Loc_InRect(ls_wdt/10,0,ls_wdt*8/10,ls_hgt*4/5), Loc_Wall(CNAT_Bottom), Loc_Func(Scenario.IsStartSpot)); - if (!start_pos) start_pos = {x=Random(ls_wdt*6/10)+ls_wdt*2/10, y=ls_hgt*58/100}; + var spawn_x = ls_wdt/3, spawn_y = 10; + spawn_x += Random(spawn_x); + var balloon = CreateObject(BalloonDeployed, spawn_x, spawn_y - 16, plr); + crew->SetPosition(spawn_x, spawn_y); + balloon->SetRider(crew); + crew->SetAction("Ride", balloon); + balloon->SetSpeed(0,0); + crew->SetSpeed(0,0); } - crew->SetPosition(start_pos.x, start_pos.y-10); // initial material if (SCENPAR_Weapons == 0) { @@ -190,9 +205,19 @@ func InitPlayerRound(int plr) // Disable the Clonk during the countdown. crew->SetCrewEnabled(false); crew->SetComDir(COMD_Stop); + + if (SCENPAR_SpawnType == 1 && balloon) + balloon->CreateEffect(IntNoGravity, 1, 1); + return true; } +local IntNoGravity = new Effect { + Timer = func() { + Target->SetSpeed(0,0); + } +}; + // Called by the round start countdown. func OnCountdownFinished() { @@ -201,6 +226,8 @@ func OnCountdownFinished() { clonk->SetCrewEnabled(true); SetCursor(clonk->GetOwner(), clonk); + if (SCENPAR_SpawnType == 1 && clonk->GetActionTarget()) + RemoveEffect("IntNoGravity", clonk->GetActionTarget()); } } diff --git a/planet/Arena.ocf/HotIce.ocs/StringTblDE.txt b/planet/Arena.ocf/HotIce.ocs/StringTblDE.txt index e1deac73b..fc3d3b0f6 100644 --- a/planet/Arena.ocf/HotIce.ocs/StringTblDE.txt +++ b/planet/Arena.ocf/HotIce.ocs/StringTblDE.txt @@ -10,6 +10,12 @@ WeaponsClassic=Klassisch DescWeaponsClassic=Bögen, Speere, Keulen und einige Feuersteine WeaponsExplosive=Explosiv DescWeaponsExplosive=Nur Granatwerfer mit Endlosmunition +SpawnType=Startpunkte +DescSpawn=Legt fest, wo die Clonks der Spieler starten. +ClassicSpawn=Klassisch +DescClassicSpawn=Die Clonks starten auf den Eisinseln. +BalloonSpawn=Ballons +DescBalloonSpawn=Die Clonks fallen mit Ballons vom Himmel. Rounds=Rundenzahl DescRounds=Mehrere Runden spielen Stalemate=Unentschieden! diff --git a/planet/Arena.ocf/HotIce.ocs/StringTblUS.txt b/planet/Arena.ocf/HotIce.ocs/StringTblUS.txt index 8b8692c38..6871e53d1 100644 --- a/planet/Arena.ocf/HotIce.ocs/StringTblUS.txt +++ b/planet/Arena.ocf/HotIce.ocs/StringTblUS.txt @@ -5,13 +5,19 @@ DescMapTypeBigIsland=One central main island with small spots of ice in the air MapTypeSpots=Small islands DescMapTypeSpots=Many small spots of ice in the air. Weapons=Weapons -DescWeapons=Defines which weapons are available for players +DescWeapons=Defines which weapons are available for players. WeaponsClassic=Classic -DescWeaponsClassic=Bows, spears and clubs available in chests +DescWeaponsClassic=Bows, spears and clubs available in chests. WeaponsExplosive=Explosive -DescWeaponsExplosive=Only grenade lauchers and wind bags available +DescWeaponsExplosive=Only grenade lauchers and wind bags available. +SpawnType=Spawn points +DescSpawn=Defines where the starting positions will be. +ClassicSpawn=Classic +DescClassicSpawn=All clonks start on the ice islands. +BalloonSpawn=Balloons +DescBalloonSpawn=The clonks will drop with balloons from the sky. Rounds=Number of rounds -DescRounds=Play for multiple rounds +DescRounds=Play for multiple rounds. Stalemate=Stalemate! WinningTeam=Winning team: %s RemainingRounds=%d rounds remaining. diff --git a/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Egg.ocd/Script.c b/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Egg.ocd/Script.c index 2760dd766..e35d1e09e 100644 --- a/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Egg.ocd/Script.c +++ b/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Egg.ocd/Script.c @@ -17,7 +17,6 @@ public func Place(int amount, proplist area) var location = nil; if (area) location = Loc_InArea(area->GetBoundingRectangle()); - var owner = GetCreaturePlayer(); while(amount > 0) { var p = nil; @@ -33,9 +32,7 @@ public func Place(int amount, proplist area) // small circle for(var r = 0; (r < 360) && (amount > 0); r += 40+Random(40)) { - var o = CreateObject(Chippie_Egg, p.x + Sin(r, 10 + RandomX(-2, 2)), p.y - Cos(r, 10 + RandomX(-2, 2)), owner); - if(owner == nil) - o->SetCreatureControlled(); + var o = CreateObject(Chippie_Egg, p.x + Sin(r, 10 + RandomX(-2, 2)), p.y - Cos(r, 10 + RandomX(-2, 2)), NO_OWNER); o->SetCon(RandomX(90, 100)); --amount; } diff --git a/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Script.c b/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Script.c index c3dd28d4d..c2335a20e 100644 --- a/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Script.c +++ b/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Script.c @@ -15,8 +15,6 @@ public func Construction() { AddEffect("Activity", this, 1, 10, this); SetAction("Walk"); - if (GetOwner() == NO_OWNER) - SetCreatureControlled(); energy_sucked = 0; return true; } @@ -106,7 +104,7 @@ private func StartJump() private func FxJumpCheckTimer(target, effect, time) { - var e = FindObject(Find_AtPoint(), Find_OCF(OCF_Alive), Find_Hostile(GetOwner())); + var e = FindObject(Find_AtPoint(), Find_OCF(OCF_Alive), Find_AnimalHostile(GetOwner())); if(e) { ClawTo(e); @@ -191,7 +189,7 @@ private func FxActivityTimer(target, effect, time) if(!GetEffect("DmgShock", this) && !GBackSemiSolid()) { - for(var enemy in FindObjects(Find_Distance(100), Find_OCF(OCF_Alive), Find_Hostile(GetOwner()), Sort_Distance())) + 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; diff --git a/planet/Objects.ocd/Animals.ocd/Mooq.ocd/Script.c b/planet/Objects.ocd/Animals.ocd/Mooq.ocd/Script.c index 4e81f3821..dd8e99333 100644 --- a/planet/Objects.ocd/Animals.ocd/Mooq.ocd/Script.c +++ b/planet/Objects.ocd/Animals.ocd/Mooq.ocd/Script.c @@ -62,8 +62,6 @@ func Construction() CheckTurn(GetDir()); SetTailOnFire(); - - SetCreatureControlled(); } func Death() @@ -508,7 +506,7 @@ func UpdateEnemy() var x = GetX(); var y = GetY(); - for (var obj in FindObjects(Find_Distance(200), Find_OCF(OCF_Alive), Find_Hostile(GetOwner()), Sort_Distance())) + for (var obj in FindObjects(Find_Distance(200), Find_OCF(OCF_Alive), Find_AnimalHostile(GetOwner()), Sort_Distance())) { if (!PathFree(x, y, obj->GetX(), obj->GetY())) continue; if (obj->GBackLiquid()) continue; diff --git a/planet/Objects.ocd/Animals.ocd/Puka.ocd/Script.c b/planet/Objects.ocd/Animals.ocd/Puka.ocd/Script.c index 5198090e1..51b7b42e4 100644 --- a/planet/Objects.ocd/Animals.ocd/Puka.ocd/Script.c +++ b/planet/Objects.ocd/Animals.ocd/Puka.ocd/Script.c @@ -71,8 +71,6 @@ public func Construction() if (Random(2)) SetDir(DIR_Left); else SetDir(DIR_Right); - SetCreatureControlled(); - // Two spot layouts are available. if (!Random(2)) SetMeshMaterial("Puka2"); @@ -348,7 +346,7 @@ private func UpdateEnemy() var x = GetX(); var y = GetY(); - for (var obj in FindObjects(Find_Distance(100), Find_OCF(OCF_Alive), Find_Hostile(GetOwner()), Sort_Distance())) + for (var obj in FindObjects(Find_Distance(100), Find_OCF(OCF_Alive), Find_AnimalHostile(GetOwner()), Sort_Distance())) { if (!PathFree(x, y, obj->GetX(), obj->GetY())) continue; enemy = obj; @@ -377,7 +375,7 @@ private func DoElectroCircle() }; // 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))) + for (var obj in FindObjects(Find_Distance(30), Find_OCF(OCF_Alive), Find_AnimalHostile(GetOwner()), Find_Exclude(this))) { var delta_x = 3 * (obj->GetX() - GetX()); var delta_y = 3 * (obj->GetY() - GetY()); @@ -645,7 +643,7 @@ private func EndShockWater() 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()))) + for (var obj in FindObjects(Find_Distance(120), Find_OCF(OCF_Alive), Find_AnimalHostile(this->GetOwner()))) { if (!obj->GBackLiquid()) continue; var angle = Angle(GetX(), GetY(), obj->GetX(), obj->GetY()); diff --git a/planet/Objects.ocd/Clonk.ocd/Animations.ocd/Script.c b/planet/Objects.ocd/Clonk.ocd/Animations.ocd/Script.c index 467a58c5f..7ed073701 100644 --- a/planet/Objects.ocd/Clonk.ocd/Animations.ocd/Script.c +++ b/planet/Objects.ocd/Clonk.ocd/Animations.ocd/Script.c @@ -594,6 +594,16 @@ func CheckScaleTop() return true; } +func CheckScaleTopHelper() +{ + // Check if the clonk has passed the material with its leg vertices + // and if COMD_Up is used to climb in which case corner scale would fail + + if (GBackSolid(-3+6*GetDir(), 6)) return false; + if (GetComDir() != COMD_Up) return false; + return true; +} + func FxIntScaleStart(target, effect, tmp) { if(tmp) return; @@ -624,6 +634,22 @@ func FxIntScaleTimer(target, number, time) // The animation's graphics has to be shifet a bit to adjust to the clonk movement var pos = GetAnimationPosition(number.animation_id); SetScaleRotation(0, 0, 0, 0, 0, 1); + // Check if corner scale help is needed + if (CheckScaleTopHelper()) + { + if (GetDir() == DIR_Left) + SetComDir(COMD_UpLeft); + else + SetComDir(COMD_UpRight); + number.corner_scale_helper = true; + } + else if (number.corner_scale_helper) + number.corner_scale_helper = false; + } + else if (number.corner_scale_helper) + { + // This will delay everything for 1 frame just for cleanup, hopefully it's not too bad + number.corner_scale_helper = false; } else if(!GBackSolid(-10+20*GetDir(), 8)) { @@ -708,9 +734,13 @@ func FxIntScaleStop(target, number, reason, tmp) /* if(number.animation_mode == 1) PlayAnimation(Clonk_WalkStand, CLONK_ANIM_SLOT_Movement, GetWalkAnimationPosition(Clonk_WalkStand), Anim_Const(1000)); // Finally stop if the user has scheduled a stop if(number.ScheduleStop) SetComDir(COMD_Stop);*/ - // and reset the transform + + // Reset the transform SetScaleRotation(0); -// SetObjDrawTransform(1000, 0, 0, 0, 1000, 0); + // Remove the corner scale helper com dir + if (number.corner_scale_helper) + if (GetComDir() == COMD_UpLeft || GetComDir() == COMD_UpRight) + Schedule(this, "SetComDir(COMD_Up)", 2); } /*-- diff --git a/planet/Objects.ocd/Clonk.ocd/Script.c b/planet/Objects.ocd/Clonk.ocd/Script.c index b3f0ba063..090fe40a2 100644 --- a/planet/Objects.ocd/Clonk.ocd/Script.c +++ b/planet/Objects.ocd/Clonk.ocd/Script.c @@ -108,6 +108,13 @@ protected func CatchBlow() if (GetAction() == "Dead") return; if (!Random(5)) PlaySoundHurt(); } + +protected func OnEnergyChange(int change, int cause, int caused_by) +{ + if (change < 0 && GetCursor(GetOwner()) == this) + PlayRumble(GetOwner(), Min(300 + 1000 * -change / this.MaxEnergy, 1000), 150); + return _inherited(...); +} protected func Grab(object pTarget, bool fGrab) { diff --git a/planet/Objects.ocd/Environment.ocd/Disasters.ocd/BoilingLava.ocd/StringTblUS.txt b/planet/Objects.ocd/Environment.ocd/Disasters.ocd/BoilingLava.ocd/StringTblUS.txt index eab9a8282..7762cb1a5 100644 --- a/planet/Objects.ocd/Environment.ocd/Disasters.ocd/BoilingLava.ocd/StringTblUS.txt +++ b/planet/Objects.ocd/Environment.ocd/Disasters.ocd/BoilingLava.ocd/StringTblUS.txt @@ -1,2 +1,2 @@ -Name=Boiling Laval +Name=Boiling Lava Description=Causes Lava on the map to boil diff --git a/planet/Objects.ocd/HUD.ocd/ObjectInteractionMenu.ocd/Script.c b/planet/Objects.ocd/HUD.ocd/ObjectInteractionMenu.ocd/Script.c index 6cae1926d..9d65ac056 100644 --- a/planet/Objects.ocd/HUD.ocd/ObjectInteractionMenu.ocd/Script.c +++ b/planet/Objects.ocd/HUD.ocd/ObjectInteractionMenu.ocd/Script.c @@ -156,7 +156,7 @@ func FxIntCheckObjectsTimer(target, effect fx) container_restriction = Find_Or(Find_Container(container), Find_InArray([container])); } - var new_objects = FindObjects(Find_AtRect(target->GetX() - 5, target->GetY() - 10, 10, 20), container_restriction, Find_Layer(target->GetObjectLayer()), + var new_objects = FindObjects(Find_AtRect(target->GetX() - 5, target->GetY() - 10, 10, 21), container_restriction, Find_Layer(target->GetObjectLayer()), // Find all containers and objects with a custom menu. Find_Or(Find_Func("IsContainer"), Find_Func("HasInteractionMenu")), // Do not show objects with an extra slot though - even if they are containers. They count as items here and can be accessed via the surroundings tab. @@ -997,7 +997,7 @@ func FxIntRefreshContentsMenuTimer(target, effect, time) { var j = 0, e = nil; var found_tracker = false; - while (e = GetEffect(nil, obj, j++)) + while (e = GetEffect("ExtraSlotTracker", obj, j++)) { if (e.keep_alive != extra_slot_keep_alive) continue; found_tracker = true; @@ -1005,9 +1005,10 @@ func FxIntRefreshContentsMenuTimer(target, effect, time) } if (!found_tracker) { - var e = AddEffect("ExtraSlotTracker", obj, 1, 30 + Random(60), this); + var e = AddEffect("ExtraSlotTracker", obj, 1, 30 + Random(60), nil, GetID()); e.keep_alive = extra_slot_keep_alive; e.callback_effect = effect; + e.obj = effect.obj; } } // How many objects are this object?! @@ -1170,8 +1171,8 @@ func FxIntRefreshContentsMenuTimer(target, effect, time) func FxExtraSlotTrackerTimer(object target, proplist effect, int time) { - if (!effect.keep_alive) return -1; - return 1; + if (!effect.keep_alive) + return -1; } // This is called by the extra-slot library. diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Dynamite.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/Dynamite.ocd/Script.c index 93dd4c13a..c08fb1568 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Dynamite.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Dynamite.ocd/Script.c @@ -1,14 +1,95 @@ /** Dynamite - A volatile tool that can be pressed into wallsfor accurate - mining, burning a short fuse before exploding. - - @author Newton + A volatile tool that can be pressed into wallsfor accurate mining, burning a short fuse before exploding. + + @author: Newton */ +/*-- Engine Callbacks --*/ + // time in frames until explosion local FuseTime = 140; +func Hit() +{ + Sound("Hits::GeneralHit?"); +} + +func Incineration(int caused_by) +{ + Extinguish(); + Fuse(); + SetController(caused_by); +} + +func RejectEntrance() +{ + return GetAction() == "Ready"; +} + +/*-- Callbacks --*/ + +public func OnCannonShot(object cannon) +{ + Fuse(); +} + +// Drop fusing dynamite on death to prevent explosion directly after respawn +public func IsDroppedOnDeath(object clonk) +{ + return (GetAction() == "Fuse"); +} + +public func IsFusing() +{ + return GetAction() == "Fuse"; +} + +// Called by the Dynamite box +public func SetReady() +{ + SetAction("Ready"); +} +// Called by the Dynamite box +public func SetFuse() +{ + SetAction("Fuse"); + // Object can't be collected anymore when it fuses. + this.Collectible = false; +} + +public func Reset() +{ + SetAction("Idle"); + // Object can be collected again. + this.Collectible = true; +} + +public func OnFuseFinished(object fuse) +{ + SetController(fuse->GetController()); + DoExplode(); +} + +// This will only when inside a dynamite box to display the remaining dynamite sticks in the HUD +public func GetStackCount() +{ + if (Contained()) + if (Contained()->GetID() == DynamiteBox) + { + return Contained()->ContentsCount(GetID()); + } +} + +public func IsInfiniteStackCount() +{ + return false; +} + +public func IsGrenadeLauncherAmmo() { return true; } + +/*-- Usage --*/ + public func ControlUse(object clonk, int x, int y, bool box) { // if already activated, nothing (so, throw) @@ -52,7 +133,19 @@ public func ControlUse(object clonk, int x, int y, bool box) return false; } -private func Place(object clonk, int x, int y, bool box) +public func Fuse() +{ + if (GetAction() != "Fuse") + { + if (!FindObject(Find_Category(C4D_StaticBack), Find_Func("IsFuse"), Find_ActionTargets(this))) + Sound("Fire::Fuse"); + SetAction("Fuse"); + // Object can't be collected anymore when it fuses. + this.Collectible = false; + } +} + +func Place(object clonk, int x, int y, bool box) { var angle = Angle(0,0,x,y); var pos = GetWall(angle); @@ -69,26 +162,9 @@ private func Place(object clonk, int x, int y, bool box) return false; } -public func Fuse() -{ - if (GetAction() != "Fuse") - { - if (!FindObject(Find_Category(C4D_StaticBack), Find_Func("IsFuse"), Find_ActionTargets(this))) - Sound("Fire::Fuse"); - SetAction("Fuse"); - // Object can't be collected anymore when it fuses. - this.Collectible = false; - } -} - -public func OnCannonShot(object cannon) -{ - Fuse(); -} - // returns true if there is a wall in direction in which "clonk" looks // and puts the offset to the wall into "xo, yo" - looking from the clonk -private func GetWall(int angle) +func GetWall(int angle) { var dist = 12; for (var dist = 12; dist < 18; dist++) @@ -101,41 +177,7 @@ private func GetWall(int angle) return false; } -protected func Hit() { Sound("Hits::GeneralHit?"); } - -protected func Incineration(int caused_by) -{ - Extinguish(); - Fuse(); - SetController(caused_by); -} - -protected func RejectEntrance() -{ - return GetAction() == "Ready"; -} - -// Controle of the Dynamite box -public func SetReady() -{ - SetAction("Ready"); -} -// Controle of the Dynamite box -public func SetFuse() -{ - SetAction("Fuse"); - // Object can't be collected anymore when it fuses. - this.Collectible = false; -} - -public func Reset() -{ - SetAction("Idle"); - // Object can be collected again. - this.Collectible = true; -} - -private func Fusing() +func Fusing() { var x = Sin(GetR(), 5); var y = -Cos(GetR(), 5); @@ -155,11 +197,6 @@ private func Fusing() return; } -public func OnFuseFinished(object fuse) -{ - SetController(fuse->GetController()); - DoExplode(); -} public func DoExplode() { @@ -169,17 +206,9 @@ public func DoExplode() Explode(26); } +/*-- Production --*/ + public func IsChemicalProduct() { return true; } -public func IsGrenadeLauncherAmmo() { return true; } - -public func IsFusing() { return GetAction() == "Fuse"; } - -// Drop fusing dynamite on death to prevent explosion directly after respawn -public func IsDroppedOnDeath(object clonk) -{ - return (GetAction() == "Fuse"); -} - /*-- Properties --*/ @@ -207,8 +236,7 @@ local ActMap = { }; local Name = "$Name$"; local Description = "$Description$"; -local Collectible = 1; - +local Collectible = true; local BlastIncinerate = 1; local ContactIncinerate = 1; -local Components = {Coal = 1, Firestone = 1}; +local Components = {Coal = 1, Firestone = 1}; \ No newline at end of file diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Igniter.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Igniter.ocd/Script.c index 11c8a2f73..03a067b63 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Igniter.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Igniter.ocd/Script.c @@ -38,9 +38,11 @@ public func ControlUse(object clonk, int x, int y) { if (clonk->GetAction() != "Walk") return true; - - ignited = 1; - + if (ignited) + return true; + + ignited = true; + // The clonk has to stand. clonk->SetAction("Stand"); clonk->SetXDir(0); @@ -91,7 +93,13 @@ public func GetCarryMode() public func GetCarryPhase() { return 250; } -public func GetCarrySpecial(clonk) +public func GetCarryTransform() +{ + if (ignited) + return Trans_Mul(Trans_Rotate(0, 1), Trans_Translate(-1000)); +} + +public func GetCarrySpecial() { if (ignited) return "pos_hand2"; diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Script.c index 337ea7191..848f47938 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Script.c @@ -1,10 +1,12 @@ /** Dynamite box - Contains five dynamite sticks which can be placed and detonated from a distance. + Contains five dynamite sticks which can be placed and detonated from a distance. @author: Newton */ +#include Library_HasExtraSlot + static const DYNA_MaxLength = 500; static const DYNA_MaxCount = 5; @@ -17,6 +19,8 @@ local wire; func Initialize() { + CreateContents(Dynamite, DYNA_MaxCount); + count = DYNA_MaxCount; dynamite_sticks = []; wires = []; @@ -29,7 +33,6 @@ func Initialize() // Hide it TODO: Remove if the mesh isn't shown if there is a picture set this.PictureTransformation = Trans_Scale(); UpdatePicture(); - return; } func Hit() @@ -37,24 +40,84 @@ func Hit() Sound("Hits::Materials::Wood::DullWoodHit?"); } -func Incineration(int caused_by) +func Incineration(int caused_by) { ActivateFuse(); if (!GetEffect("Fuse", this)) AddEffect("Fuse", this, 100, 1, this); Sound("Fire::Fuse"); SetController(caused_by); - return; } func Damage(int change, int type, int by_player) { Incinerate(nil, by_player); - return; } -public func OnCannonShot(object cannon) +func RejectCollect(id def, object obj) { - Incinerate(nil, cannon->GetController()); + if (obj->GetID() != Dynamite) + return true; + // One dynamite box can only support 5 sticks of dynamite, regardless if these are in the box + // or already taken out (connected with wires) + var sticks = ContentsCount(Dynamite); + for (var i = 0; i < GetLength(wires); i++) + if (wires[i]) + sticks++; + + if (sticks >= DYNA_MaxCount) + return true; + + return false; +} + +func Ejection() +{ + count--; + + if (count == 0) + { + ChangeToIgniter(); + if (Contained()) + { + var pos = Contained()->~GetItemPos(this); + Contained()->~UpdateAttach(); + Contained()->~OnSlotFull(pos); + } + } + else + { + UpdatePicture(); + } + + // Make sure the inventory gets notified of the changes. + if (Contained()) + Contained()->~OnInventoryChange(); +} + +func ContentsDestruction() +{ + Ejection(); +} + +func Collection2() +{ + if (count == 0 && GetID() == Igniter) + { + ChangeToBox(); + if (Contained()) + { + var pos = Contained()->~GetItemPos(this); + Contained()->~UpdateAttach(); + Contained()->~OnSlotFull(pos); + } + } + + count++; + + UpdatePicture(); + + if (Contained()) + Contained()->~OnInventoryChange(); } /*-- Callbacks --*/ @@ -78,6 +141,11 @@ public func OnFuseFinished(object fuse) DoExplode(); } +public func OnCannonShot(object cannon) +{ + Incinerate(nil, cannon->GetController()); +} + /*-- Usage --*/ public func SetDynamiteCount(int new_count) @@ -87,49 +155,34 @@ public func SetDynamiteCount(int new_count) // Update inventory if contained in a crew member. if (Contained()) Contained()->~OnInventoryChange(); - return; } -public func HoldingEnabled() { return true; } - public func ControlUse(object clonk, int x, int y) { - var dynamite = dynamite_sticks[count - 1] = CreateContents(Dynamite); + var dynamite = Contents(); + + if (!dynamite || dynamite->GetID() != Dynamite) + return false; + if (!dynamite->ControlUse(clonk, x, y, 1)) - { - dynamite->RemoveObject(); return true; - } + if(wire) wire->Connect(dynamite_sticks[count], dynamite); wire = CreateObject(Fuse); wire->Connect(dynamite, this); Sound("Objects::Connect"); - wires[count - 1] = wire; - - count--; - - if (count == 0) - { - var pos = clonk->GetItemPos(this); - ChangeToIgniter(); - clonk->UpdateAttach(); - clonk->OnSlotFull(pos); - } - else - { - UpdatePicture(); - } + wires[count] = wire; - // Make sure the inventory gets notified of the changes. - clonk->~OnInventoryChange(); return true; } // Empty this box and turn it into an igniter public func ChangeToIgniter() { + if (GetID() == Igniter) return; + count = 0; UpdatePicture(); ChangeDef(Igniter); @@ -137,6 +190,16 @@ public func ChangeToIgniter() return true; } +// Change back into a box +public func ChangeToBox() +{ + if (GetID() == DynamiteBox) return; + + ChangeDef(DynamiteBox); + UpdatePicture(); + return true; +} + public func ActivateFuse() { // Activate all fuses. @@ -199,7 +262,7 @@ func UpdatePicture() } // Display the remaining dynamite sticks in menus. -public func GetInventoryIconOverlay() +/*public func GetInventoryIconOverlay() { // Full boxes don't need an overlay. Same for igniters. if (count == DYNA_MaxCount || count <= 0) return nil; @@ -231,17 +294,19 @@ public func GetInventoryIconOverlay() } return overlay; -} +}*/ -func Definition(def) { +func Definition(def) +{ SetProperty("PictureTransformation", Trans_Mul(Trans_Rotate(150, 1, 0, 0), Trans_Rotate(140, 0, 1, 0)), def); } /*-- Properties --*/ -local Collectible = 1; local Name = "$Name$"; local Description = "$Description$"; +local Collectible = true; local BlastIncinerate = 1; local ContactIncinerate = 2; local Components = {Wood = 1, Coal = 2, Firestone = 2}; +local MaxContentsCount = 5; \ No newline at end of file diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Hook.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Hook.ocd/Script.c index e494ffb3f..0a4970123 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Hook.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Hook.ocd/Script.c @@ -169,8 +169,10 @@ public func OnRopeBreak() /*-- Grapple rope controls --*/ -public func FxIntGrappleControlControl(object target, proplist effect, int ctrl, int x, int y, int strength, repeat, release) +public func FxIntGrappleControlControl(object target, proplist effect, int ctrl, int x, int y, int strength, bool repeat, int status) { + if (status == CONS_Moved) return false; + var release = status == CONS_Up; // Cancel this effect if clonk is now attached to something. if (target->GetProcedure() == "ATTACH") { diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Pipe.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/Pipe.ocd/Script.c index c9480ecb4..89eed571e 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Pipe.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Pipe.ocd/Script.c @@ -101,11 +101,14 @@ public func CanBeStackedWith(object other) return inherited(other) && (PipeState == other.PipeState); } + /** The pump calls this function to prevent clogging of the intake. Cycles through several aperture offset indices. */ -func CycleApertureOffset() +public func HasAperture() { return true; } + +public func CycleApertureOffset() { // Cycle in three steps of three px each through X and Y // covering a 3x3 grid on points -3,0,+3 diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Shovel.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/Shovel.ocd/Script.c index 3b35b6826..9a8c54f13 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Shovel.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Shovel.ocd/Script.c @@ -33,6 +33,8 @@ public func IsDigging() { return is_digging; } public func HoldingEnabled() { return true; } +public func DefaultCrosshairAngle(object clonk, int d) { return 900 * d; } + public func ControlUseStart(object clonk, int x, int y) { AddEffect("ShovelDig", clonk, 1, 1, this); diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/WindBag.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/WindBag.ocd/Script.c index cb017da29..1b6a525b8 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/WindBag.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/WindBag.ocd/Script.c @@ -22,7 +22,15 @@ func Hit() /*-- Usage --*/ -public func ControlUse(object clonk, x, y) +public func DefaultCrosshairAngle(object clonk, int d) +{ + // Easy mode for gamepad users: automatically boost a jump. + if (clonk->GetYDir() < -10) + return Angle(0, 0, -clonk->GetXDir(), -clonk->GetYDir(), 10); + return 0; +} + +protected func ControlUse(object clonk, x, y) { if (!GetEffect("IntReload", this) && !GetEffect("IntBurstWind", this)) { @@ -251,4 +259,4 @@ local Name = "$Name$"; local Description = "$Description$"; local Collectible = true; local MaxIntake = 30; -local Components = {Cloth = 1, Metal = 1}; \ No newline at end of file +local Components = {Cloth = 1, Metal = 1}; diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/DefCore.txt new file mode 100644 index 000000000..9a8aa0eff --- /dev/null +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/DefCore.txt @@ -0,0 +1,14 @@ +[DefCore] +id=Helmet +Version=8,0 +Category=C4D_Object +Width=10 +Height=10 +Offset=-5,-5 +Vertices=2 +VertexX=0,0 +VertexY=-4,5 +VertexFriction=50,50 +Value=10 +Mass=10 +Rotate=1 \ No newline at end of file diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Graphics.mesh b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Graphics.mesh new file mode 100644 index 000000000..3e75179f7 Binary files /dev/null and b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Graphics.mesh differ diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Helmet_greek.skeleton b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Helmet_greek.skeleton new file mode 100644 index 000000000..d77dfb661 Binary files /dev/null and b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Helmet_greek.skeleton differ diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Scene.material b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Scene.material new file mode 100644 index 000000000..7abc790c7 --- /dev/null +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Scene.material @@ -0,0 +1,23 @@ +material Helmet_Greek +{ + receive_shadows on + technique + { + pass + { + cull_hardware none + + ambient 0.8 0.8 0.8 1.0 + diffuse 0.64 0.64 0.64 1.0 + specular 0.16 0.16 0.16 1.0 12.5 + emissive 0.0 0.0 0.0 1.0 + + texture_unit + { + texture helmet.jpg + tex_address_mode wrap + filtering trilinear + } + } + } +} diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Script.c new file mode 100644 index 000000000..e18b41a60 --- /dev/null +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Script.c @@ -0,0 +1,102 @@ +/** + Helmet + Protective head armor. + + @author: pluto, Clonkonaut +*/ + +#include Library_Wearable + +/*-- Engine Callbacks --*/ + +func Hit() +{ + Sound("Hits::Materials::Metal::DullMetalHit?"); +} + +/*-- Usage --*/ + +public func ControlUse(object clonk) +{ + if (IsWorn()) + TakeOff(); + else + PutOn(clonk); + + return true; +} + +// Helmet effect: 20% less damage +func OnDamage(int damage, int cause, int by_player) +{ + // Do nothing on energy gained + if (damage > 0) return damage; + // Doesn't protect against all damage + if (cause == FX_Call_EngBlast || cause == FX_Call_EngFire || cause == FX_Call_EngAsphyxiation || cause == FX_Call_EngCorrosion) + return damage; + + return damage - (damage*20/100); +} + +/*-- Production --*/ + +public func IsWeapon() { return true; } +public func IsArmoryProduct() { return true; } + +/*-- Display --*/ + +public func GetWearPlace() +{ + return WEARABLE_Head; +} + +public func GetWearBone() +{ + return "Main"; +} + +public func GetWearTransform() +{ + return Trans_Mul(Trans_Rotate(90, 0, 0, 1), Trans_Translate(0, -300)); +} + +public func GetCarryMode(object clonk, bool secondary) +{ + if (IsWorn() || display_disabled) + return CARRY_None; + if (secondary || !clonk->~HasHandAction(false, true)) + return CARRY_Back; + return CARRY_BothHands; +} + +public func GetCarryPhase(object clonk) +{ + return 550; +} + +public func GetCarryBone(object clonk, bool secondary) +{ + return "Main"; +} + +public func GetCarryTransform(object clonk, bool secondary, bool no_hand, bool on_back) +{ + if (secondary) + return Trans_Mul(Trans_Rotate(180, 1), Trans_Rotate(0, 0, 1), Trans_Rotate(90, 0, 0, 1), Trans_Translate(-4000)); + if (no_hand || on_back) + return Trans_Mul(Trans_Rotate(0, 1), Trans_Rotate(0, 0, 1), Trans_Rotate(90, 0, 0, 1), Trans_Translate(-4000)); + + return Trans_Mul(Trans_Rotate(80, 0, 0, 1), Trans_Rotate(-90, 0, 1), Trans_Rotate(-45, 0, 0, 1), Trans_Translate(-1000, 4000)); +} + +func Definition(def) +{ + SetProperty("PictureTransformation", Trans_Mul(Trans_Rotate(45, 0, 1), Trans_Rotate(10, 0, 0, 1)),def); +} + +/*-- Properties --*/ + +local Name = "$Name$"; +local Description = "$Description$"; +local Collectible = true; +local Components = {Wood = 1, Metal = 1}; \ No newline at end of file diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/StringTblDE.txt b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/StringTblDE.txt new file mode 100644 index 000000000..acde36bfa --- /dev/null +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/StringTblDE.txt @@ -0,0 +1,2 @@ +Name=Helm +Description=Bietet dem Clonk einigen Schutz. Drücke [Benutzen] um den Helm auf- oder abzusetzen. \ No newline at end of file diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/StringTblUS.txt b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/StringTblUS.txt new file mode 100644 index 000000000..98e9a04b8 --- /dev/null +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/StringTblUS.txt @@ -0,0 +1,2 @@ +Name=Helmet +Description=Provides the clonk with some protection. Press [Use] to take the helmet on or off. \ No newline at end of file diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/helmet.jpg b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/helmet.jpg new file mode 100644 index 000000000..f3653e1c8 Binary files /dev/null and b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/helmet.jpg differ diff --git a/planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/DefCore.txt b/planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/DefCore.txt deleted file mode 100644 index 3601e99da..000000000 --- a/planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/DefCore.txt +++ /dev/null @@ -1,5 +0,0 @@ -[DefCore] -id=Library_CreatureControl -Version=6,1 -Category=C4D_StaticBack -HideInCreator=true diff --git a/planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/Script.c deleted file mode 100644 index 4bf33369b..000000000 --- a/planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/Script.c +++ /dev/null @@ -1,76 +0,0 @@ -/** - AnimalControl - Cares about the ownership of non-player-controlled units. - They are hostile to every other player. - - global func GetCreaturePlayer() - global func SetAnimalControlled() -*/ - -static CreatureControl_animal_player; -static CreatureControl_yet_to_set; -static CreatureControl_initializing; - -private func Enqueue(obj) -{ - if(GetType(CreatureControl_yet_to_set) != C4V_Array) - CreatureControl_yet_to_set = []; - PushBack(CreatureControl_yet_to_set, obj); -} - -/** - Returns the hostile NPC player or creates it. - Returns nil when the NPC player is currently joining. -*/ -global func GetCreaturePlayer() -{ - if(CreatureControl_animal_player != nil) - return CreatureControl_animal_player; - if(CreatureControl_initializing == true) - return nil; - - CreatureControl_initializing = true; - CreateScriptPlayer("Creatures", RGB(50, 100, 50), 0, CSPF_NoScenarioInit | CSPF_NoEliminationCheck | CSPF_Invisible, Library_CreatureControl); - return nil; -} - -/** - Sets the owner of an object to the hostile NPC player. -*/ -global func SetCreatureControlled() -{ - if(!this) return false; - var o = GetCreaturePlayer(); - if(o != nil) return SetOwner(o); - - // No owner during creation. If the scripter overwrites it to a real owner, it's not changed later. - SetOwner(NO_OWNER); - Library_CreatureControl->Enqueue(this); -} - -public func InitializeScriptPlayer(plr, team) -{ - CreatureControl_animal_player = plr; - - if(CreatureControl_yet_to_set != nil) - { - for(var obj in CreatureControl_yet_to_set) - { - if (!obj) continue; - - // Overwritten by the scripter? - if (obj->GetOwner() != NO_OWNER) continue; - obj->SetOwner(CreatureControl_animal_player); - } - } - CreatureControl_yet_to_set = nil; - - // hostile! - for(var i = 0; i < GetPlayerCount(); ++i) - { - var p = GetPlayerByIndex(i); - if(p == CreatureControl_animal_player) continue; - SetHostility(p, plr, true, true, true); - SetHostility(plr, p, true, true, true); - } -} \ No newline at end of file diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c index b82df0628..e3ecd0d3f 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c @@ -5,68 +5,85 @@ Virtual cursor for gamepad controls */ -local crew, angle, dirx, diry, xpos,ypos, analogaim, aiming, menu; +local crew, angle, xpos, ypos, aiming, menu; static const CURSOR_Radius = 100; +// This is supposed to be a constant, but C4Script doesn't allow constant expressions there. +private func CURSOR_Deadzone() { return PLRCON_MaxStrength / 5; } protected func Initialize() { - this["Visibility"] = VIS_None; - dirx = diry = xpos = ypos = 0; + SetVisibility(false); + xpos = ypos = 0; aiming = false; } public func FxMoveTimer() { - var speed = 0; - var dpad_rotatespeed = 35; - - // dpad mode - if(diry) + if (!crew) { - if (diry < 0) speed = -Sin(angle,100,10); - else if (diry > 0) speed = +Sin(angle,100,10); - angle += dpad_rotatespeed*speed/100; - UpdateAnalogpadPos(); + RemoveObject(); + return FX_Execute_Kill; } - if(dirx) - { - if (dirx < 0) speed = -Cos(angle,100,10); - else if (dirx > 0) speed = +Cos(angle,100,10); - angle += dpad_rotatespeed*speed/100; - UpdateAnalogpadPos(); - } - // analog pad mode - if(!dirx && !diry) - { - var target_angle = Angle(0,0,xpos,ypos)*10; - var analog_strength = BoundBy(Sqrt(xpos*xpos+ypos*ypos),0,100); + var target_angle = Angle(0,0,xpos,ypos)*10; + + if (!Visible() && !InDeadzone()) + { + // The player moved the aiming stick while the crosshair wasn't visible: Use angle directly. + angle = target_angle; + SetVisibility(true); + } + else if (!InDeadzone()) + { + // Smooth small movements of the stick while the crosshair is visible. var angle_diff = Normalize(target_angle - angle, -1800, 10); - if (angle_diff == 0) angle_diff = 1; - - angle = angle + angle_diff * analog_strength / 100 / 8; + if (Abs(angle_diff) < 450) + angle = angle + angle_diff / 8; + else + angle = target_angle; + } + else if (!aiming) + { + // The player doesn't touch the stick and no item is using the crosshair right now. + SetVisibility(false); + // Aim somewhere useful. Note that this can be overwritten by objects and isn't used for throwing. + angle = 800*(crew->GetDir()*2-1); } UpdatePosition(); - if(aiming) crew->TriggerHoldingControl(); + crew->TriggerHoldingControl(); } -private func UpdateAnalogpadPos() +private func AnalogStrength() { return BoundBy(Sqrt(xpos*xpos+ypos*ypos), 0, PLRCON_MaxStrength); } +private func InDeadzone() { return AnalogStrength() < CURSOR_Deadzone(); } +private func Visible() { return this.Visibility != VIS_None; } + +// Updates the visibility, returing true if it was changed. +private func SetVisibility(bool visible) { - xpos = Sin(angle/10,100); - ypos = Cos(angle/10,-100); + var newvis, oldvis; + if (visible) + newvis = VIS_Owner; + else + newvis = VIS_None; + oldvis = this.Visibility; + this.Visibility = newvis; + return newvis != oldvis; } -public func StartAim(object clonk, bool stealth, object GUImenu) +private func CreateMoveEffect(object clonk) { - // only reinitialize angle if the crosshair hasn't been there before - if(!GetEffect("Move",this)) - { - // which should basically be only the case on the first time aiming - angle = 800*(clonk->GetDir()*2-1); - } - + crew = clonk; + UpdatePosition(); + RemoveEffect("Move",this); + AddEffect("Move",this,1,1,this); +} + +public func StartAim(object clonk, int default_angle, object GUImenu) +{ + aiming = true; + // gui or landscape mode: if (GUImenu) { @@ -79,22 +96,12 @@ public func StartAim(object clonk, bool stealth, object GUImenu) SetCategory(C4D_StaticBack | C4D_IgnoreFoW); menu = nil; } - - // set starting position for analog pad - UpdateAnalogpadPos(); - - crew = clonk; - UpdatePosition(); - RemoveEffect("Move",this); - AddEffect("Move",this,1,1,this); - if(!stealth) - { - this["Visibility"] = VIS_Owner; - crew->SetComDir(COMD_Stop); - aiming = true; - EnableKeyAimControls(true); - } + // Use the given angle if the player wasn't aiming before. + if (SetVisibility(true) && default_angle) + angle = default_angle; + + CreateMoveEffect(clonk); } private func UpdatePosition() @@ -112,65 +119,41 @@ private func UpdatePosition() private func MirrorCursor() { + return; angle = -Normalize(angle,-1800,10); - UpdateAnalogpadPos(); } public func StopAim() { - RemoveEffect("Move",this); - this["Visibility"] = VIS_None; - dirx = 0; - diry = 0; - EnableKeyAimControls(false); - analogaim = false; aiming = false; } -private func EnableKeyAimControls(bool enable) -{ - SetPlayerControlEnabled(GetOwner(), CON_AimUp, enable); - SetPlayerControlEnabled(GetOwner(), CON_AimDown, enable); - SetPlayerControlEnabled(GetOwner(), CON_AimLeft, enable); - SetPlayerControlEnabled(GetOwner(), CON_AimRight, enable); -} - +// Aiming means that some object is currently actively using the crosshair. public func IsAiming() { return aiming; } -public func Aim(int ctrl, object clonk, int strength, int repeat, int release) +// The crosshair is also active when the player is holding the aiming stick. +public func IsActive() +{ + return aiming || Visible(); +} + +public func Aim(int ctrl, object clonk, int strength, int repeat, int status) { // start (stealth) aiming if(!GetEffect("Move",this)) - StartAim(clonk,true); + CreateMoveEffect(clonk); // aiming with analog pad - if (ctrl == CON_AimAxisUp || ctrl == CON_AimAxisDown || ctrl == CON_AimAxisLeft || ctrl == CON_AimAxisRight) + if (status == CONS_Moved && + (ctrl == CON_AimAxisUp || ctrl == CON_AimAxisDown || ctrl == CON_AimAxisLeft || ctrl == CON_AimAxisRight)) { - dirx = diry = 0; - if(ctrl == CON_AimAxisUp) ypos = -strength; if(ctrl == CON_AimAxisDown) ypos = strength; if(ctrl == CON_AimAxisLeft) xpos = -strength; if(ctrl == CON_AimAxisRight) xpos = strength; - analogaim = true; - return true; - } - // stop - else if (release && !analogaim) - { - if(ctrl == CON_AimUp || ctrl == CON_AimDown) diry = 0; - else if(ctrl == CON_AimLeft || ctrl == CON_AimRight) dirx = 0; - return true; - } - else if(!release /*&& !repeat */ && !analogaim) - { - if(ctrl == CON_AimUp) diry = -1; - else if(ctrl == CON_AimDown) diry = 1; - else if(ctrl == CON_AimLeft) dirx = -1; - else if(ctrl == CON_AimRight) dirx = 1; return true; } return false; diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c index 3c3eaf93b..ec79095e2 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c @@ -46,6 +46,9 @@ static const ACTIONTYPE_EXTRA = 4; // elevators within this range (x) can be called static const ELEVATOR_CALL_DISTANCE = 30; +// default throwing angle used while the Clonk isn't aiming +static const DEFAULT_THROWING_ANGLE = 500; + /* ++++++++++++++++++++++++ Clonk Inventory Control ++++++++++++++++++++++++ */ /* @@ -178,13 +181,13 @@ public func GetExtraInteractions() /* +++++++++++++++++++++++++++ Clonk Control +++++++++++++++++++++++++++ */ /* Main control function */ -public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { if (!this) return false; // Contents menu - if (ctrl == CON_Contents && !release) + if (ctrl == CON_Contents && status == CONS_Down) { // Close any menu if open. if (GetMenu()) @@ -221,10 +224,11 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re else ctrl = CON_Use; repeat = true; - release = false; + status = CONS_Down; } // controls except a few reset a previously given command - else SetCommand("None"); + else if (status != CONS_Moved) + SetCommand("None"); /* aiming with analog pad or keys: This works completely different. There are CON_AimAxis* and CON_Aim*, @@ -238,23 +242,29 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re CON_Left is still called afterwards. So if the clonk finally starts to aim, the virtual cursor already aims into the direction in which he ran */ - if (ctrl == CON_AimAxisUp || ctrl == CON_AimAxisDown || ctrl == CON_AimAxisLeft || ctrl == CON_AimAxisRight - || ctrl == CON_AimUp || ctrl == CON_AimDown || ctrl == CON_AimLeft || ctrl == CON_AimRight) + if (ctrl == CON_AimAxisUp || ctrl == CON_AimAxisDown || ctrl == CON_AimAxisLeft || ctrl == CON_AimAxisRight) { - var success = VirtualCursor()->Aim(ctrl,this,strength,repeat,release); + var success = VirtualCursor()->Aim(ctrl,this,strength,repeat,status); // in any case, CON_Aim* is called but it is only successful if the virtual cursor is aiming return success && VirtualCursor()->IsAiming(); } + // Simulate a mouse cursor for gamepads. + if (HasVirtualCursor()) + { + x = this.control.mlastx; + y = this.control.mlasty; + } + // save last mouse position: // if the using has to be canceled, no information about the current x,y // is available. Thus, the last x,y position needs to be saved - if (ctrl == CON_Use || ctrl == CON_UseAlt) + else if (ctrl == CON_Use || ctrl == CON_UseAlt) { this.control.mlastx = x; this.control.mlasty = y; } - + var proc = GetProcedure(); // building, vehicle, mount, contents, menu control @@ -269,23 +279,23 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // menu if (this.control.menu) { - return Control2Menu(ctrl, x,y,strength, repeat, release); + return Control2Menu(ctrl, x,y,strength, repeat, status); } var contents = this->GetHandItem(0); // usage - var use = (ctrl == CON_Use || ctrl == CON_UseDelayed || ctrl == CON_UseAlt || ctrl == CON_UseAltDelayed); + var use = (ctrl == CON_Use || ctrl == CON_UseAlt); if (use) { if (house) { - return ControlUse2Script(ctrl, x, y, strength, repeat, release, house); + return ControlUse2Script(ctrl, x, y, strength, repeat, status, house); } // control to grabbed vehicle else if (vehicle && proc == "PUSH") { - return ControlUse2Script(ctrl, x, y, strength, repeat, release, vehicle); + return ControlUse2Script(ctrl, x, y, strength, repeat, status, vehicle); } else if (vehicle && proc == "ATTACH") { @@ -301,25 +311,25 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re usage via CancelUse(). */ - if (ControlUse2Script(ctrl, x, y, strength, repeat, release, vehicle)) + if (ControlUse2Script(ctrl, x, y, strength, repeat, status, vehicle)) return true; else { // handled if the horse is the used object - // ("using" is set to the object in StartUse(Delayed)Control - when the + // ("using" is set to the object in StartUseControl - when the // object returns true on that callback. Exactly what we want) if (this.control.current_object == vehicle) return true; // has been cancelled (it is not the start of the usage but no object is used) - if (!this.control.current_object && (repeat || release)) return true; + if (!this.control.current_object && (repeat || status == CONS_Up)) return true; } } // releasing the use-key always cancels shelved commands (in that case no this.control.current_object exists) - if(release) StopShelvedCommand(); + if(status == CONS_Up) StopShelvedCommand(); // Release commands are always forwarded even if contents is 0, in case we // need to cancel use of an object that left inventory - if (contents || (release && this.control.current_object)) + if (contents || (status == CONS_Up && this.control.current_object)) { - if (ControlUse2Script(ctrl, x, y, strength, repeat, release, contents)) + if (ControlUse2Script(ctrl, x, y, strength, repeat, status, contents)) return true; } } @@ -327,7 +337,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // A click on throw can also just abort usage without having any other effects. // todo: figure out if wise. var currently_in_use = this.control.current_object != nil; - if ((ctrl == CON_Throw || ctrl == CON_ThrowDelayed) && currently_in_use && !release) + if (ctrl == CON_Throw && currently_in_use && status == CONS_Down) { CancelUse(); return true; @@ -336,7 +346,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // Throwing and dropping // only if not in house, not grabbing a vehicle and an item selected // only act on press, not release - if ((ctrl == CON_Throw || ctrl == CON_ThrowDelayed) && !house && (!vehicle || proc == "ATTACH" || proc == "PUSH") && !release) + if (ctrl == CON_Throw && !house && (!vehicle || proc == "ATTACH" || proc == "PUSH") && status == CONS_Down) { if (contents) { @@ -365,33 +375,19 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re if (only_drop || Distance(0, 0, x, y) < 10 || (Abs(x) < 10 && y > 10)) only_drop = true; // throw - if (ctrl == CON_Throw) + CancelUse(); + + if (only_drop) + return ObjectCommand("Drop", contents); + else { - CancelUse(); - - if (only_drop) - return ObjectCommand("Drop", contents); - else - return ObjectCommand("Throw", contents, x, y); - } - // throw delayed - if (ctrl == CON_ThrowDelayed) - { - CancelUse(); - if (release) + if (HasVirtualCursor() && !VirtualCursor()->IsActive()) { - VirtualCursor()->StopAim(); - - if (only_drop) - return ObjectCommand("Drop", contents); - else - return ObjectCommand("Throw", contents, this.control.mlastx, this.control.mlasty); - } - else - { - VirtualCursor()->StartAim(this); - return true; + var angle = DEFAULT_THROWING_ANGLE * (GetDir()*2 - 1); + x = +Sin(angle, CURSOR_Radius, 10); + y = -Cos(angle, CURSOR_Radius, 10); } + return ObjectCommand("Throw", contents, x, y); } } } @@ -402,14 +398,14 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // forward to script... if (house) { - return ControlMovement2Script(ctrl, x, y, strength, repeat, release, house); + return ControlMovement2Script(ctrl, x, y, strength, repeat, status, house); } else if (vehicle) { - if (ControlMovement2Script(ctrl, x, y, strength, repeat, release, vehicle)) return true; + if (ControlMovement2Script(ctrl, x, y, strength, repeat, status, vehicle)) return true; } - return ObjectControlMovement(plr, ctrl, strength, release); + return ObjectControlMovement(plr, ctrl, strength, status); } // Do a roll on landing or when standing. This means that the CON_Down was not handled previously. @@ -433,7 +429,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // Fall through half-solid mask if (ctrl == CON_FallThrough) { - if(!release) + if(status == CONS_Down) { if (this->IsWalking()) { @@ -469,7 +465,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } // Unhandled control - return _inherited(plr, ctrl, x, y, strength, repeat, release, ...); + return _inherited(plr, ctrl, x, y, strength, repeat, status, ...); } // A wrapper to SetCommand to catch special behaviour for some actions. @@ -617,18 +613,12 @@ func CanReIssueCommand(proplist data) if(data.ctrl == CON_Use) return !data.obj->~RejectUse(this); - - if(data.ctrl == CON_UseDelayed) - return !data.obj->~RejectUse(this); } func ReIssueCommand(proplist data) { if(data.ctrl == CON_Use) return StartUseControl(data.ctrl, this.control.mlastx, this.control.mlasty, data.obj); - - if(data.ctrl == CON_UseDelayed) - return StartUseDelayedControl(data.ctrl, data.obj); } func StartUseControl(int ctrl, int x, int y, object obj) @@ -651,6 +641,17 @@ func StartUseControl(int ctrl, int x, int y, object obj) this.control.using_type = DetermineUsageType(obj); this.control.alt = ctrl != CON_Use; + if (HasVirtualCursor()) + { + var cursor = VirtualCursor(), angle; + if (!cursor->IsActive() && (angle = obj->~DefaultCrosshairAngle(this, GetDir()*2 - 1))) + { + x = +Sin(angle, CURSOR_Radius, 10); + y = -Cos(angle, CURSOR_Radius, 10); + } + cursor->StartAim(this, angle); + } + var hold_enabled = obj->Call("~HoldingEnabled"); if (hold_enabled) @@ -687,37 +688,6 @@ func StartUseControl(int ctrl, int x, int y, object obj) return handled; } -func StartUseDelayedControl(int ctrl, object obj) -{ - this.control.started_use = false; - - if(obj->~RejectUse(this)) - { - // remember for later: - ShelveCommand(this, "CanReIssueCommand", this, "ReIssueCommand", {obj = obj, ctrl = ctrl}); - // but still catch command - return true; - } - - // Disable climb/hangle actions for the duration of this use - if (obj.ForceFreeHands && !GetEffect("IntControlFreeHands", this)) AddEffect("IntControlFreeHands", this, 130, 0, this); - - this.control.current_object = obj; - this.control.using_type = DetermineUsageType(obj); - this.control.alt = ctrl != CON_UseDelayed; - - VirtualCursor()->StartAim(this); - - // call UseStart - var handled = obj->Call(GetUseCallString("Start"),this,this.control.mlastx,this.control.mlasty); - this.control.noholdingcallbacks = !handled; - - if(handled) - this.control.started_use = true; - - return handled; -} - func CancelUseControl(int x, int y) { // forget possibly stored commands @@ -782,11 +752,6 @@ func HoldingUseControl(int ctrl, int x, int y, object obj) { var mex = x; var mey = y; - if (ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed) - { - mex = this.control.mlastx; - mey = this.control.mlasty; - } //Message("%d,%d",this,mex,mey); @@ -829,29 +794,6 @@ func HoldingUseControl(int ctrl, int x, int y, object obj) return handled; } -func StopUseDelayedControl(object obj) -{ - // ControlUseStop, ControlUseAltStop, ContainedUseAltStop, etc... - var handled = obj->Call(GetUseCallString("Stop"), this, this.control.mlastx, this.control.mlasty); - if (!handled) - handled = obj->Call(GetUseCallString(), this, this.control.mlastx, this.control.mlasty); - - if (obj == this.control.current_object) - { - VirtualCursor()->StopAim(); - // see StopUseControl - if(handled != -1) - { - this.control.current_object = nil; - this.control.using_type = nil; - this.control.alt = false; - } - this.control.noholdingcallbacks = false; - } - - return handled; -} - // very infrequent timer to prevent dangling effects, this is not necessary for correct functioning func FxItemRemovalCheckTimer(object target, proplist effect, int time) { @@ -876,43 +818,31 @@ func FxItemRemovalCheckStop(object target, proplist effect, int reason, bool tem // Control use redirected to script -func ControlUse2Script(int ctrl, int x, int y, int strength, bool repeat, bool release, object obj) +func ControlUse2Script(int ctrl, int x, int y, int strength, bool repeat, int status, object obj) { // standard use if (ctrl == CON_Use || ctrl == CON_UseAlt) { - if (!release && !repeat) + if (status == CONS_Down && !repeat) { return StartUseControl(ctrl,x, y, obj); } - else if (release && (obj == this.control.current_object || obj == GetActionTarget())) + else if (status == CONS_Up && (obj == this.control.current_object || obj == GetActionTarget())) { return StopUseControl(x, y, obj); } } - // gamepad use - else if (ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed) - { - if (!release && !repeat) - { - return StartUseDelayedControl(ctrl, obj); - } - else if (release && (obj == this.control.current_object || obj == GetActionTarget())) - { - return StopUseDelayedControl(obj); - } - } // more use (holding) - if (ctrl == CON_Use || ctrl == CON_UseAlt || ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed) + if (ctrl == CON_Use || ctrl == CON_UseAlt) { - if (release) + if (status == CONS_Up) { // leftover use release CancelUse(); return true; } - else if (repeat && !this.control.noholdingcallbacks) + else if (status == CONS_Down && repeat && !this.control.noholdingcallbacks) { return HoldingUseControl(ctrl, x, y, obj); } @@ -922,7 +852,7 @@ func ControlUse2Script(int ctrl, int x, int y, int strength, bool repeat, bool r } // Control use redirected to script -func ControlMovement2Script(int ctrl, int x, int y, int strength, bool repeat, bool release, object obj) +func ControlMovement2Script(int ctrl, int x, int y, int strength, bool repeat, int status, object obj) { // overloads of movement commandos if (ctrl == CON_Left || ctrl == CON_Right || ctrl == CON_Down || ctrl == CON_Up || ctrl == CON_Jump) @@ -931,7 +861,7 @@ func ControlMovement2Script(int ctrl, int x, int y, int strength, bool repeat, b if (Contained() == obj) control_string = "Contained"; - if (release) + if (status == CONS_Up) { // if any movement key has been released, ControlStop is called if (obj->Call(Format("~%sStop", control_string), this, ctrl)) @@ -1040,7 +970,7 @@ func SetMenu(new_menu, bool unclosable) SetComDir(COMD_Stop); if (PlayerHasVirtualCursor(GetOwner())) - VirtualCursor()->StartAim(this,false, new_menu); + VirtualCursor()->StartAim(this, 0, new_menu); else { if (GetType(new_menu) == C4V_C4Object && new_menu->~CursorUpdatesEnabled()) diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c index b061bcc9c..f92ec2c37 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c @@ -19,12 +19,12 @@ local virtual_cursor; /* This part of gamepad control handles only object-style menus. Fullscreen menus are handled differently. */ -func Control2Menu(int ctrl, int x, int y, int strength, bool repeat, bool release) +func Control2Menu(int ctrl, int x, int y, int strength, bool repeat, int status) { /* all this stuff is already done on a higher layer - in playercontrol.c now this is just the same for gamepad control */ - if (!PlayerHasVirtualCursor(GetOwner())) + if (!HasVirtualCursor()) return true; if (!this->GetMenu()) return false; @@ -36,27 +36,27 @@ func Control2Menu(int ctrl, int x, int y, int strength, bool repeat, bool releas // update angle for visual effect on the menu if (repeat) { - if (ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed) + if (ctrl == CON_Use || ctrl == CON_UseAlt) this->GetMenu()->~UpdateCursor(mex,mey); } // click on menu - if (release) + if (status == CONS_Up) { // select - if (ctrl == CON_UseDelayed) + if (ctrl == CON_Use) this->GetMenu()->~OnMouseClick(mex,mey); } return true; } -public func ObjectControlMovement(int plr, int ctrl, int strength, bool release) +public func ObjectControlMovement(int plr, int ctrl, int strength, int status) { // from PlayerControl.c - var result = inherited(plr,ctrl,strength,release,...); + var result = inherited(plr,ctrl,strength,status,...); // do the following only if strength >= CON_Gamepad_Deadzone - if(!release) + if(status == CONS_Down) if(strength != nil && strength < CON_Gamepad_Deadzone) return result; @@ -66,7 +66,7 @@ public func ObjectControlMovement(int plr, int ctrl, int strength, bool release) if(!virtual_cursor) return result; // change direction of virtual_cursor - if(!release) + if(status == CONS_Down) virtual_cursor->Direction(ctrl); return result; @@ -79,7 +79,7 @@ func ReinitializeControls() // if is aiming or in menu and no virtual cursor is there, create one if (!virtual_cursor) if (this.menu || this.control.current_object) // properties declared in ClonkControl.ocd - VirtualCursor()->StartAim(this,false,this.menu); + VirtualCursor()->StartAim(this,0,this.menu); } else { @@ -91,6 +91,9 @@ func ReinitializeControls() /* Virtual cursor stuff */ +// Helper function. +private func HasVirtualCursor() { return PlayerHasVirtualCursor(GetOwner()); } + // get virtual cursor, if noone is there, create it private func VirtualCursor() { @@ -122,19 +125,12 @@ public func UpdateVirtualCursorPos() public func TriggerHoldingControl() { - // using has been commented because it must be possible to use the virtual - // cursor aim also without a used object - for menus - // However, I think the check for 'this.control.current_object' here is just an unecessary safeguard - // since there is always a using-object if the clonk is aiming for a throw - // or a use. If the clonk uses it, there will be callbacks that cancel the - // callbacks to the virtual cursor - // - Newton - if (/*this.control.current_object && */!this.control.noholdingcallbacks) + if (this.control.current_object && !this.control.noholdingcallbacks) { - var ctrl = CON_UseDelayed; + var ctrl = CON_Use; if (this.control.alt) - ctrl = CON_UseAltDelayed; - ObjectControl(GetOwner(), ctrl, 0, 0, 0, true, false); + ctrl = CON_UseAlt; + ObjectControl(GetOwner(), ctrl, 0, 0, 0, true, CONS_Down); } } @@ -143,4 +139,4 @@ func RemoveVirtualCursor() { if (virtual_cursor) virtual_cursor->StopAim(); -} \ No newline at end of file +} diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkInteractionControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkInteractionControl.ocd/Script.c index 56ab6d8bd..4558ef246 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkInteractionControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkInteractionControl.ocd/Script.c @@ -26,13 +26,13 @@ public func OnShiftCursor(object new_cursor) return _inherited(new_cursor, ...); } -public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { if (!this) - return inherited(plr, ctrl, x, y, strength, repeat, release, ...); + return inherited(plr, ctrl, x, y, strength, repeat, status, ...); // Begin interaction. - if (ctrl == CON_Interact && !release) + if (ctrl == CON_Interact && status == CONS_Down) { this->CancelUse(); BeginInteract(); @@ -50,7 +50,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } // Finish picking up (aka "collect"). - if (ctrl == CON_Interact && release) + if (ctrl == CON_Interact && status == CONS_Up) { EndInteract(); return true; @@ -71,7 +71,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } } - return inherited(plr, ctrl, x, y, strength, repeat, release, ...); + return inherited(plr, ctrl, x, y, strength, repeat, status, ...); } private func FxIntHighlightInteractionStart(object target, proplist fx, temp, proplist interaction, proplist interaction_help) diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkInventoryControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkInventoryControl.ocd/Script.c index f3e4db417..758bfc23c 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkInventoryControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkInventoryControl.ocd/Script.c @@ -55,17 +55,17 @@ func RejectCollect(id objid, object obj) return false; } -public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { if (!this) - return inherited(plr, ctrl, x, y, strength, repeat, release, ...); + return inherited(plr, ctrl, x, y, strength, repeat, status, ...); // Quickswitch changes the current active inventory slot - if (ctrl == CON_QuickSwitch && !release) + if (ctrl == CON_QuickSwitch && status == CONS_Down) { // but ignore quickswitch if we have more than 1 hand-slot if(this.HandObjects > 1) - return inherited(plr, ctrl, x, y, strength, repeat, release, ...);; + return inherited(plr, ctrl, x, y, strength, repeat, status, ...);; // A number key (hotkey) is pressed, change quick switch slot /*if (this.inventory.hotkey_down != nil) @@ -78,7 +78,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re SetHandItemPos(0, this.inventory.quick_slot); // quick_slot is updated in SetHandItemPos return true; } - if (ctrl == CON_QuickSwitch && release) // Do nothing for now but will be used in the future + if (ctrl == CON_QuickSwitch && status == CONS_Up) // Do nothing for now but will be used in the future { return true; } @@ -86,7 +86,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re if (!Contained()) { // Quick-pickup item via click? Note that this relies on being executed after the normal Clonk controls - if (ctrl == CON_Use && !this->GetHandItem(0) && !release) + if (ctrl == CON_Use && !this->GetHandItem(0) && status == CONS_Down) { var sort = Sort_Distance(x, y); var items = FindAllPickupItems(sort); @@ -97,7 +97,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } // Begin picking up objects. - if (ctrl == CON_PickUp && !release) + if (ctrl == CON_PickUp && status == CONS_Down) { this->CancelUse(); BeginPickingUp(); @@ -105,7 +105,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } // Drop the mouse item? - if (ctrl == CON_Drop && !release) + if (ctrl == CON_Drop && status == CONS_Down) { // Do not immediately collect another thing unless chosen with left/right. if (this.inventory.is_picking_up) @@ -139,7 +139,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } // Finish picking up (aka "collect"). - if (ctrl == CON_PickUp && release) + if (ctrl == CON_PickUp && status == CONS_Up) { EndPickingUp(); return true; @@ -223,7 +223,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re if (this.inventory.hotkey_down != nil && hot > 0 && hot <= this.MaxContentsCount && this.inventory.hotkey_down != hot) { // do nothing if this is just key down - if (!release) + if (status == CONS_Down) return true; // switch the two slots this->~Switch2Items(this.inventory.hotkey_down-1, hot-1); @@ -240,7 +240,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } // hotkey up: perform slot selection - if (hot > 0 && hot <= this.MaxContentsCount && release) + if (hot > 0 && hot <= this.MaxContentsCount && status == CONS_Up) { // This wasn't liked by many players, so slot selection is back to key down. @@ -256,7 +256,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re return true; } // a hotkey is pressed, save it for now - if (hot > 0 && hot <= this.MaxContentsCount && !release) + if (hot > 0 && hot <= this.MaxContentsCount && status == CONS_Down) { this.inventory.hotkey_down = hot; // For safety @@ -267,7 +267,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re return true; } - return inherited(plr, ctrl, x, y, strength, repeat, release, ...); + return inherited(plr, ctrl, x, y, strength, repeat, status, ...); } private func FxIntHighlightItemStart(object target, proplist fx, temp, object item) diff --git a/planet/Objects.ocd/Libraries.ocd/Constructor.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Constructor.ocd/Script.c index 2eb80fc8d..e371138de 100644 --- a/planet/Objects.ocd/Libraries.ocd/Constructor.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/Constructor.ocd/Script.c @@ -83,12 +83,12 @@ public func FxControlConstructionPreviewStart(object clonk, effect, int temp, id } // Called by Control2Effect -public func FxControlConstructionPreviewControl(object clonk, effect, int ctrl, int x, int y, int strength, bool repeat, bool release) +public func FxControlConstructionPreviewControl(object clonk, effect, int ctrl, int x, int y, int strength, bool repeat, int status) { if (ctrl != CON_Aim) { // CON_Use is accept, but don't remove the preview, this is done on releasing the button. - if (ctrl == CON_Use && !release) + if (ctrl == CON_Use && status == CONS_Down) { var ok = CreateConstructionSite(clonk, effect.structure, AbsX(effect.preview->GetX()), AbsY(effect.preview->GetY() + effect.preview.dimension_y/2), effect.preview.blocked, effect.preview.direction, effect.preview.stick_to); if (ok) @@ -105,7 +105,7 @@ public func FxControlConstructionPreviewControl(object clonk, effect, int ctrl, // (yes, this means that actionbar-hotkeys wont work for it. However clicking the button will.) else if (IsInteractionControl(ctrl)) { - if (release) + if (status == CONS_Up) effect.preview->Flip(); return true; } diff --git a/planet/Objects.ocd/Libraries.ocd/LadderClimb.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/LadderClimb.ocd/Script.c index 438080c7f..2b2239cdf 100644 --- a/planet/Objects.ocd/Libraries.ocd/LadderClimb.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/LadderClimb.ocd/Script.c @@ -337,13 +337,13 @@ public func FxIntClimbControlStop(object target, effect fx, int reason, bool tmp return FX_OK; } -public func FxIntClimbControlControl(object target, effect fx, int ctrl, int x, int y, int strength, bool repeat, bool release) +public func FxIntClimbControlControl(object target, effect fx, int ctrl, int x, int y, int strength, bool repeat, int status) { // Only handle movement controls. if (ctrl != CON_Up && ctrl != CON_Down && ctrl != CON_Right && ctrl != CON_Left) return false; // Perform actions on key down and not on release. - if (release) + if (status != CONS_Down) return false; // Move up and down by setting com dir. if (ctrl == CON_Up) diff --git a/planet/Objects.ocd/Libraries.ocd/LiquidControl.ocd/LiquidContainer.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/LiquidControl.ocd/LiquidContainer.ocd/Script.c index 63b1d7ddd..b0815c9d1 100644 --- a/planet/Objects.ocd/Libraries.ocd/LiquidControl.ocd/LiquidContainer.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/LiquidControl.ocd/LiquidContainer.ocd/Script.c @@ -125,6 +125,11 @@ func PutLiquid(liquid_name, int amount, object source) return after - before; } +func AcceptsLiquid(liquid_name, int amount) +{ + return amount <= this->GetLiquidContainerMaxFillLevel() - GetLiquidAmount(liquid_name); +} + private func GetLiquidDef(liquid_name) { if (GetType(liquid_name) == C4V_String) diff --git a/planet/Objects.ocd/Libraries.ocd/Wearable.ocd/DefCore.txt b/planet/Objects.ocd/Libraries.ocd/Wearable.ocd/DefCore.txt new file mode 100644 index 000000000..11e494853 --- /dev/null +++ b/planet/Objects.ocd/Libraries.ocd/Wearable.ocd/DefCore.txt @@ -0,0 +1,4 @@ +[DefCore] +id=Library_Wearable +Version=8,0 +Category=C4D_StaticBack \ No newline at end of file diff --git a/planet/Objects.ocd/Libraries.ocd/Wearable.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Wearable.ocd/Script.c new file mode 100644 index 000000000..996fd67e2 --- /dev/null +++ b/planet/Objects.ocd/Libraries.ocd/Wearable.ocd/Script.c @@ -0,0 +1,180 @@ +/** + Library_Wearable + Library for all clothing and other things worn on the clonk. + The library will make sure that not two objects are worn at the same + position at the same time. + + @author: Clonkonaut +*/ + +/* Bone names of attachment on the clonk and also identifiers */ + +// Headwear like helmets, caps or similar +static const WEARABLE_Head = "skeleton_head"; + +local wear_effect; + +local display_disabled = false; + +/* Overloads */ + +// These functions must exist in order for this library to work + +public func GetWearPlace() +{ + return; // must return one of the WEARABLE_* constants +} + +/* Other functions that can be present in the object: + +func GetWearBone: return the bone with which it is attached to the clonk (default: "main") +func GetWearTransform(clonk): transformation added when worn + +func StayAfterDeath: return true if the item should remain on the clonk after its death (default is that it does not stay) + +func OnPutOn(clonk): callback after the item was put on +func OnTakenOff(clonk): callback after the item was taken off + +func OnDamage(damage_amount, cause, by_player): Callback whenever the wearer is damaged, parameters are passed on from the effect Damage callback + Return value is returned (useful for protective clothing) + +func GetCarryMode: must(!) return CARRY_None whenever display_disabled is true, otherwise display error will likely occur + +*/ + +/* Engine Callbacks */ + +// It is assumed that a wearable must be contained in the clonk to be worn. +func Departure() +{ + if (IsWorn()) + TakeOff(); + _inherited(...); +} + +func Destruction() +{ + if (IsWorn()) + TakeOff(); + _inherited(...); +} + +/* Interface */ + +// The clonk will put on the item and take off any other item currently worn +// in the same place, unless no_force is true in which case false will be returned +// when something else is worn. +public func PutOn(object clonk, bool no_force) +{ + // ??? + if (!clonk->~IsClonk()) return false; + + // Remove all other things before putting on + if (!no_force) + { + var effect; + for (var i = GetEffectCount("Wearing", clonk); effect = GetEffect("Wearing", clonk, i); i--) + if (effect.identifier == GetWearPlace()) + RemoveEffect(nil, clonk, effect); + } + + // It is not impossible that the item is currently held in the hand of the clonk. + // If so, temporarily disable display because the same mesh cannot be attached twice. + // Any item must adhere this variable in GetCarryMode! + display_disabled =true; + clonk->~UpdateAttach(); + + wear_effect = clonk->CreateEffect(Wearing, 2, nil, GetWearPlace(), this); + + if (wear_effect == -1) // got rejected + wear_effect = nil; + + display_disabled = false; + clonk->~UpdateAttach(); + + if (wear_effect) + { + // Callback to do whatever + this->~OnPutOn(clonk); + return true; + } + + return false; +} + +public func IsWorn() +{ + return wear_effect; +} + +public func TakeOff() +{ + if (!wear_effect) + return false; + + return RemoveEffect(nil, nil, wear_effect); +} + +func TakenOff() +{ + wear_effect = nil; + if (Contained()) + Contained()->~UpdateAttach(); + // Callback to do whatever; note that at this point the item isn't necessary contained. + this->~OnTakenOff(); +} + +/* Wearing effect */ + +local Wearing = new Effect { + Construction = func(string wearing_identifier, object worn_item) { + // Save where this thing is worn + this.identifier = wearing_identifier; + // Save what is worn + this.item = worn_item; + }, + + Start = func() { + // Check if parameters are properly set + if (this.identifier == nil) return -1; + if (this.item == nil) return -1; + + var attachment_bone = this.item->~GetWearBone() ?? "main"; + var attachment_transform = this.item->~GetWearTransform(this.Target); + + this.attach = Target->AttachMesh(this.item, this.identifier, attachment_bone, attachment_transform); + }, + + Damage = func(int damage, int cause, int by_player) { + if (!this.item) return damage; + + var ret = this.item->~OnDamage(damage, cause, by_player); + if (ret == nil) + ret = damage; + return ret; + }, + + Effect = func(string new_name, var1) { + // Reject wearing effects if in the same place + if (new_name == "Wearing") + if (var1 == this.identifier) + return -1; + }, + + Stop = func(int reason) { + // Items can prevent being removed from the clonk on death + if (reason == FX_Call_RemoveDeath) + if (this.item && this.item->~StayAfterDeath(this.Target)) + return -1; + + if (this.Target) this.Target->DetachMesh(this.attach); + this.attach = nil; + }, + + Destruction = func() { + if (this.attach != nil && this.Target) + this.Target->DetachMesh(this.attach); + if (this.item) + this.item->TakenOff(); + } +}; \ No newline at end of file diff --git a/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/Script.c b/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/Script.c index d9ce96d08..e58e10abe 100644 --- a/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/Script.c +++ b/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/Script.c @@ -35,7 +35,7 @@ func OnClonkDeathEx(object clonk, int plr, int killed_by) var which_one = Random(3) + 1; var log=""; if (!GetPlayerName(killed_by)) - log=Format(Translate(Format("KilledByGaya%d", which_one)), GetTaggedPlayerName(plr), name); + log=Format(Translate(Format("KilledByGaia%d", which_one)), GetTaggedPlayerName(plr), name); else if (plr == killed_by) log=Format(Translate(Format("Selfkill%d", which_one)), GetTaggedPlayerName(plr), name); else if (!Hostile(plr,killed_by)) diff --git a/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblDE.txt b/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblDE.txt index 9789edc2d..d6e45a1f6 100644 --- a/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblDE.txt +++ b/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblDE.txt @@ -7,9 +7,9 @@ Selfkill3=%s hat Selbstmord begangen! Der arme %s. KilledByPlayer1=%s hat einen %s an %s verloren. KilledByPlayer2=%ss %s konnte nichts gegen %s machen. KilledByPlayer3=%s konnte mit seinem %s nicht gut genug kämpfen für %s. -KilledByGaya1=%s hat einen %s weggezaubert bekommen. -KilledByGaya2=%ss %s stirbt von alleine. -KilledByGaya3=%s hat einen %s an Gaya verloren. +KilledByGaia1=%s hat einen %s weggezaubert bekommen. +KilledByGaia2=%ss %s stirbt von alleine. +KilledByGaia3=%s hat einen %s an Gaia verloren. Teamkill1=%s hat einen %s an %s verloren. Teamkiller! Teamkill2=%ss %s ist bei %s in Ungnade gefallen. Teamkill3=%ss %s wurde von %s sauber hintergangen. diff --git a/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblUS.txt b/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblUS.txt index 97b7075c5..683683392 100644 --- a/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblUS.txt +++ b/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblUS.txt @@ -7,9 +7,9 @@ Selfkill3=%s committed suicide! Poor %s. KilledByPlayer1=%s has lost his %s to %s. KilledByPlayer2=%s's %s couldn't do anything against %s. KilledByPlayer3=%s's %s was not able to defeat %s. -KilledByGaya1=%s's %s was spirited away. -KilledByGaya2=%s's %s died on its own. -KilledByGaya3=%s lost a %s to Gaya. +KilledByGaia1=%s's %s was spirited away. +KilledByGaia2=%s's %s died on its own. +KilledByGaia3=%s lost a %s to Gaia. Teamkill1=%s has lost a %s to %s. Teamkiller! Teamkill2=%s's %s fell out of %s's favour. Teamkill3=%s's %s was denied by %s. diff --git a/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c index 86a66590e..3adc79e43 100644 --- a/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c @@ -326,7 +326,6 @@ protected func Pumping() break; } } - stored_material_amount = i; if (stored_material_amount <= 0) stored_material_name = nil; @@ -338,8 +337,8 @@ protected func Pumping() } else { - // Put into wait state if no liquid could be pumped for a while - if (++clog_count >= max_clog_count) + // Put into wait state if no liquid could be pumped for a while or if the drain has no aperture, i.e. is a liquid tank. + if (++clog_count >= max_clog_count || !drain_obj->~HasAperture()) { SetState("WaitForLiquid"); } @@ -383,7 +382,6 @@ func InsertMaterialAtDrain(object drain_obj, string material_name, int amount) drain_obj->InsertMaterial(material_index, drain_obj.ApertureOffsetX, drain_obj.ApertureOffsetY); } } - return amount <= 0; } @@ -403,9 +401,10 @@ func CheckState() } else { - // can pump but has no liquid -> wait for liquid - var source_ok = IsLiquidSourceOk(); - var drain_ok = IsLiquidDrainOk(); + // Can pump but has no liquid or can't dispense liquid -> wait. + var source_mat = GetLiquidSourceMaterial(); + var source_ok = source_mat != nil; + var drain_ok = GetLiquidDrainOk(source_mat); if (!source_ok || !drain_ok) { if (!source_ok) @@ -532,30 +531,39 @@ private func PumpHeight2Power(int pump_height) return used_power; } -// TODO: check usage of this, probably has to return true if the source is a container // Returns whether there is liquid at the source pipe to pump. -private func IsLiquidSourceOk() +private func GetLiquidSourceMaterial() { - // source + // Get the source object and check whether there is liquid. + // TODO: If the source is a liquid container check which material will be supplied. var source_obj = GetSourceObject(); - if(!source_obj->GBackLiquid(source_obj.ApertureOffsetX, source_obj.ApertureOffsetY)) + var is_liquid = source_obj->GBackLiquid(source_obj.ApertureOffsetX, source_obj.ApertureOffsetY); + var liquid = MaterialName(source_obj->GetMaterial(source_obj.ApertureOffsetX, source_obj.ApertureOffsetY)); + if (!is_liquid) { - source_obj->~CycleApertureOffset(this); // try different offsets, so we can resume pumping after clog because 1px of earth was dropped on the source pipe - return false; + // Try different offsets, so we can resume pumping after clog because 1px of earth was dropped on the source pipe. + source_obj->~CycleApertureOffset(this); + return; } - return true; + return liquid; } -// TODO: check usage of this, probably has to return true if the drain is a container -// Returns whether the drain pipe is free. -private func IsLiquidDrainOk() +// Returns whether the drain pipe is free or the liquid container accepts the given material. +private func GetLiquidDrainOk(string liquid) { - // target (test with the very popular liquid "water") var drain_obj = GetDrainObject(); - if(!drain_obj->CanInsertMaterial(Material("Water"),drain_obj.ApertureOffsetX, drain_obj.ApertureOffsetY)) + if (drain_obj->~HasAperture()) { - drain_obj->~CycleApertureOffset(this); // try different offsets, so we can resume pumping after clog because 1px of earth was dropped on the source pipe - return false; + if (!drain_obj->CanInsertMaterial(Material(liquid), drain_obj.ApertureOffsetX, drain_obj.ApertureOffsetY)) + { + drain_obj->~CycleApertureOffset(this); // try different offsets, so we can resume pumping after clog because 1px of earth was dropped on the source pipe + return false; + } + } + else if (drain_obj->~IsLiquidContainer()) + { + if (!drain_obj->AcceptsLiquid(liquid, 1)) + return false; } return true; } diff --git a/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblDE.txt b/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblDE.txt index 4d6509f68..8f0f23be1 100644 --- a/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblDE.txt +++ b/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblDE.txt @@ -1 +1 @@ -Name=Kokosnussbaum \ No newline at end of file +Name=Kokospalme \ No newline at end of file diff --git a/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblUS.txt b/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblUS.txt index 7f72f6ab9..8c07a102a 100644 --- a/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblUS.txt +++ b/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblUS.txt @@ -1 +1 @@ -Name=Coconut Tree \ No newline at end of file +Name=Coconut Palm \ No newline at end of file diff --git a/planet/Parkour.ocf/VolcanoEscapeEx.ocs/Material.ocg/Brick.ocm b/planet/Parkour.ocf/VolcanoEscapeEx.ocs/Material.ocg/Brick.ocm index 8a6ee7805..5d40a079a 100644 --- a/planet/Parkour.ocf/VolcanoEscapeEx.ocs/Material.ocg/Brick.ocm +++ b/planet/Parkour.ocf/VolcanoEscapeEx.ocs/Material.ocg/Brick.ocm @@ -1,7 +1,7 @@ [Material] Name=Brick Shape=Smoother -Density=50 +Density=90 Friction=15 Placement=80 TextureOverlay=brick diff --git a/planet/System.ocg/Controls.c b/planet/System.ocg/Controls.c index 0ba627b9b..ad1c35f84 100644 --- a/planet/System.ocg/Controls.c +++ b/planet/System.ocg/Controls.c @@ -21,9 +21,8 @@ global func IsMovementControl(int ctrl) /** Control throws selected item */ global func IsThrowControl(int ctrl) { - // left mouse button - if(ctrl == CON_Throw - || ctrl == CON_ThrowDelayed) + // right mouse button + if(ctrl == CON_Throw) return true; return false; @@ -99,4 +98,4 @@ global func IsUseControl(int ctrl) { if (ctrl == CON_Use || ctrl == CON_UseAlt) return true; return false; -} \ No newline at end of file +} diff --git a/planet/System.ocg/FindObject.c b/planet/System.ocg/FindObject.c index 4ebc4998d..66d6ed84c 100644 --- a/planet/System.ocg/FindObject.c +++ b/planet/System.ocg/FindObject.c @@ -137,6 +137,15 @@ global func Find_Hostile(int plr) return p; } +/* +Similar to Find_Hostile, but defaults to treating all players as hostile when plr = NO_OWNER. +*/ +global func Find_AnimalHostile(int plr) +{ + if (plr == NO_OWNER) return Find_Not(Find_Owner(NO_OWNER)); + return Find_Or(Find_Owner(NO_OWNER), Find_Hostile(plr)); +} + global func Find_Allied(int plr) { var p = [C4FO_Or]; diff --git a/planet/System.ocg/PlayerControl.c b/planet/System.ocg/PlayerControl.c index 452128ffb..cb8b55af1 100644 --- a/planet/System.ocg/PlayerControl.c +++ b/planet/System.ocg/PlayerControl.c @@ -18,12 +18,11 @@ global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int stren { var release = status == CONS_Up; //Log("%d, %s, %i, %d, %d, %d, %v, %v", plr, GetPlayerControlName(ctrl), spec_id, x,y,strength, repeat, status); - if (status == CONS_Moved) return false; // Control handled by definition? Forward - if (spec_id) return spec_id->ForwardedPlayerControl(plr, ctrl, x, y, strength, repeat, release); + if (spec_id) return spec_id->ForwardedPlayerControl(plr, ctrl, x, y, strength, repeat, status); // Forward control to player - if (Control2Player(plr,ctrl, x, y, strength, repeat, release)) return true; + if (Control2Player(plr,ctrl, x, y, strength, repeat, status)) return true; // Forward control to cursor var cursor = GetCursor(plr); @@ -34,7 +33,7 @@ global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int stren // menu controls: - if (cursor->~GetMenu()) + if (cursor->~GetMenu() && status != CONS_Moved) { // direction keys are always forwarded to the menu // (because the clonk shall not move while the menu is open) @@ -83,11 +82,11 @@ global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int stren } // Overload by effect? - if (cursor->Control2Effect(plr, ctrl, cursorX, cursorY, strength, repeat, release)) return true; + if (cursor->Control2Effect(plr, ctrl, cursorX, cursorY, strength, repeat, status)) return true; - if (cursor->ObjectControl(plr, ctrl, cursorX, cursorY, strength, repeat, release)) + if (cursor->ObjectControl(plr, ctrl, cursorX, cursorY, strength, repeat, status)) { - if (cursor && !release && !repeat) + if (cursor && status == CONS_Down && !repeat) { // non-mouse controls reset view if (!x && !y) ResetCursorView(plr); @@ -127,7 +126,7 @@ global func PlayerHasVirtualCursor(int plr) // Control2Player // Player-wide controls -global func Control2Player(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +global func Control2Player(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { // select previous or next if (ctrl == CON_PreviousCrew) @@ -202,7 +201,7 @@ global func StopSelected(int plr) // Control2Effect // Call control function in all effects that have "Control" in their name -global func Control2Effect(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +global func Control2Effect(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { // x and y are local coordinates if (!this) return false; @@ -213,7 +212,7 @@ global func Control2Effect(int plr, int ctrl, int x, int y, int strength, bool r { iEffect = GetEffect("*Control*", this, i); if (iEffect) - if (EffectCall(this, iEffect, "Control", ctrl, x,y,strength, repeat, release)) + if (EffectCall(this, iEffect, "Control", ctrl, x,y,strength, repeat, status)) return true; } // No effect handled the control @@ -224,7 +223,7 @@ global func Control2Effect(int plr, int ctrl, int x, int y, int strength, bool r // Called from PlayerControl when a control is issued to the cursor // Return whether handled // To be overloaded by specific objects to enable additional controls -global func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +global func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { if (!this) return false; @@ -233,7 +232,7 @@ global func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // Movement controls if (ctrl == CON_Left || ctrl == CON_Right || ctrl == CON_Up || ctrl == CON_Down || ctrl == CON_Jump) - return ObjectControlMovement(plr, ctrl, strength, release, repeat); + return ObjectControlMovement(plr, ctrl, strength, status, repeat); // Unhandled control return false; @@ -276,7 +275,7 @@ global func NameComDir(comdir) } // Called when CON_Left/Right/Up/Down controls are issued/released // Return whether handled -global func ObjectControlMovement(int plr, int ctrl, int strength, bool release, bool repeat) +global func ObjectControlMovement(int plr, int ctrl, int strength, int status, bool repeat) { if (!this) return false; @@ -284,13 +283,13 @@ global func ObjectControlMovement(int plr, int ctrl, int strength, bool release, if (Contained()) return false; // this is for controlling movement with Analogpad - if(!release) + if(status == CONS_Down) if(strength != nil && strength < CON_Gamepad_Deadzone) return true; var proc = GetProcedure(); // Some specific movement controls - if (!release) + if (status == CONS_Down) { // Jump control if (ctrl == CON_Jump) diff --git a/planet/System.ocg/PlayerControls.txt b/planet/System.ocg/PlayerControls.txt index 4ffe4702e..a385a7449 100644 --- a/planet/System.ocg/PlayerControls.txt +++ b/planet/System.ocg/PlayerControls.txt @@ -37,8 +37,6 @@ # # Gamepad controls # ------------------------------------- - # ThrowDelayed - # UseDelayed # AimUp AimDown AimLeft AimRight # AimAxisUp AimAxisDown AimAxisLeft AimAxisRight # @@ -59,26 +57,6 @@ DefaultDisabled=1 CoordinateSpace=Viewport - [ControlDef] - Identifier=AimUp - DefaultDisabled=1 - Hold=1 - - [ControlDef] - Identifier=AimDown - DefaultDisabled=1 - Hold=1 - - [ControlDef] - Identifier=AimLeft - DefaultDisabled=1 - Hold=1 - - [ControlDef] - Identifier=AimRight - DefaultDisabled=1 - Hold=1 - [ControlDef] Identifier=AimAxisUp GUIName=$CON_AimAxisUp$ @@ -164,12 +142,6 @@ Hold=1 SendCursorPos=1 - [ControlDef] - Identifier=ThrowDelayed - GUIName=$CON_Throw$ - GUIDesc=$CON_Throw_Desc$ - Hold=1 - [ControlDef] Identifier=Drop GUIName=$CON_Drop$ @@ -286,13 +258,6 @@ Hold=1 SendCursorPos=1 - [ControlDef] - Identifier=UseDelayed - GUIName=$CON_Use$ - GUIDesc=$CON_Use_Desc$ - Hold=1 - SendCursorPos=1 - [ControlDef] Identifier=UseAlt GUIName=$CON_UseAlt$ @@ -300,13 +265,6 @@ Hold=1 SendCursorPos=1 - [ControlDef] - Identifier=UseAltDelayed - GUIName=$CON_UseAlt$ - GUIDesc=$CON_UseAlt_Desc$ - Hold=1 - SendCursorPos=1 - [ControlDef] Identifier=CancelUse @@ -960,11 +918,54 @@ GUIGroup=40 Control=Interact + [Assignment] + Key=CON_Interact,CON_Left + Control=InteractNext_Left + Priority=75 + + [Assignment] + Key=CON_Interact,CON_Right + Control=InteractNext_Right + Priority=75 + + [Assignment] + Key=CON_Interact,CON_Up + Control=InteractNext_CycleObject + Priority=75 + + [Assignment] + Key=CON_Interact,CON_Down + Control=InteractNext_Stop + Priority=75 + [Assignment] Key=ControllerButtonX Control=PickUp GUIGroup=50 + [Assignment] + Key=CON_PickUp,CON_Left + Control=PickUpNext_Left + + [Assignment] + Key=CON_PickUp,CON_Right + Control=PickUpNext_Right + + [Assignment] + Key=CON_PickUp,CON_Up + Control=PickUpNext_All + Priority=75 + + [Assignment] + Key=CON_PickUp,CON_Down + Control=PickUpNext_Stop + Priority=75 + + [Assignment] + Key=CON_PickUp,CON_Throw + Control=Drop + Priority=75 + # Crew [Assignment] @@ -985,13 +986,13 @@ GUIDesc=$KEY_GamepadUse_Desc$ GUIGroup=20 Priority=100 - Control=UseDelayed + Control=Use [Assignment] Key=ControllerLeftTrigger GUIGroup=20 Priority=100 - Control=ThrowDelayed + Control=Throw # TODO: Zoom @@ -1017,58 +1018,12 @@ Name=*_GamepadCon_* [Assignment] - Key=CON_AimAxisLeft - Priority=50 - Control=Left - - [Assignment] - Key=CON_AimAxisRight - Priority=50 - Control=Right - - [Assignment] - Key=CON_AimAxisDown - Priority=50 - Control=Down - - [Assignment] - Key=CON_AimAxisUp - Priority=50 - Control=Up - - [Assignment] - Key=CON_Left - Priority=70 - Control=AimLeft - - [Assignment] - Key=CON_Right - Priority=70 - Control=AimRight - - [Assignment] - Key=CON_Down - Priority=70 - Control=AimDown - - [Assignment] - Key=CON_Up - Priority=70 - Control=AimUp - - [Assignment] - Key=CON_Down,CON_UseDelayed + Key=CON_Down,CON_Throw GUIDisabled=1 GUIGroup=20 Priority=150 Control=Drop - [Assignment] - Key=CON_UseDelayed - GUIName=None - Priority=50 - Control=ThrowDelayed - # ======================================================================= # # Default mouse control # # ======================================================================= # diff --git a/planet/Tutorials.ocf/PlayGround.ocs/System.ocg/SpawnMenu.c b/planet/Tutorials.ocf/PlayGround.ocs/System.ocg/SpawnMenu.c index 9ebd166fe..1037cf6fc 100644 --- a/planet/Tutorials.ocf/PlayGround.ocs/System.ocg/SpawnMenu.c +++ b/planet/Tutorials.ocf/PlayGround.ocs/System.ocg/SpawnMenu.c @@ -2,13 +2,13 @@ #appendto Library_ClonkControl -public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { if (!this) return false; // Spawn menu - if (ctrl == CON_SpawnMenu && !release) + if (ctrl == CON_SpawnMenu && status == CONS_Down) { // Close any menu if open. if (GetMenu()) @@ -31,5 +31,5 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } // Unhandled control will be handled by the library itself. - return _inherited(plr, ctrl, x, y, strength, repeat, release, ...); -} \ No newline at end of file + return _inherited(plr, ctrl, x, y, strength, repeat, status, ...); +} diff --git a/planet/Tutorials.ocf/Tutorial.ocd/System.ocg/HideShowTutorialGuide.c b/planet/Tutorials.ocf/Tutorial.ocd/System.ocg/HideShowTutorialGuide.c index 6ae73ada9..ebc09423e 100644 --- a/planet/Tutorials.ocf/Tutorial.ocd/System.ocg/HideShowTutorialGuide.c +++ b/planet/Tutorials.ocf/Tutorial.ocd/System.ocg/HideShowTutorialGuide.c @@ -1,9 +1,9 @@ // Shows and hides the tutorial guide if the [H] button is pressed. -global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int strength, bool repeat, bool release) +global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int strength, bool repeat, int status) { if (ctrl != CON_TutorialGuide) - return _inherited(plr, ctrl, spec_id, x, y, strength, repeat, release, ...); + return _inherited(plr, ctrl, spec_id, x, y, strength, repeat, status, ...); // Don't do anything if the player is a sequence. if (GetActiveSequence()) return; @@ -17,4 +17,4 @@ global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int stren else guide->HideGuide(); return; -} \ No newline at end of file +} diff --git a/planet/Worlds.ocf/AcidRift.ocs/Scenario.txt b/planet/Worlds.ocf/AcidRift.ocs/Scenario.txt index fd9c2db89..fa5d1232b 100644 --- a/planet/Worlds.ocf/AcidRift.ocs/Scenario.txt +++ b/planet/Worlds.ocf/AcidRift.ocs/Scenario.txt @@ -2,7 +2,7 @@ Icon=34 Title=AcidRift Version=6,0 -Difficulty=70 +Difficulty=80 [Definitions] Definition1=Objects.ocd diff --git a/planet/Worlds.ocf/Chine.ocs/Scenario.txt b/planet/Worlds.ocf/Chine.ocs/Scenario.txt index da3395859..b993a38cb 100644 --- a/planet/Worlds.ocf/Chine.ocs/Scenario.txt +++ b/planet/Worlds.ocf/Chine.ocs/Scenario.txt @@ -2,7 +2,7 @@ Icon=36 Title=Chine Version=6,0 -Difficulty=50 +Difficulty=60 [Definitions] Definition1=Objects.ocd diff --git a/planet/Worlds.ocf/FloodedVeins.ocs/DescUS.txt b/planet/Worlds.ocf/FloodedVeins.ocs/DescUS.txt index 796ae581e..9d431fed0 100644 --- a/planet/Worlds.ocf/FloodedVeins.ocs/DescUS.txt +++ b/planet/Worlds.ocf/FloodedVeins.ocs/DescUS.txt @@ -2,7 +2,7 @@ Flooded Veins You stumble upon an abandoned settlement beneath the Forest of Orgos in your quest for more gold. Legends tell a story of even more valuable materials named gems which may be found here. Might this abandoned settlement be a failed attempt to find these gems? Set up an expedition to explore the flooded caves around and to discover possible gem veins. -Goal: Sell gems +Goal: Sell gems. Hints: - The flooded caves may be drained using pumps, you can get rid off the excess water where you entered the cave. diff --git a/planet/Worlds.ocf/GemGrabbers.ocs/Scenario.txt b/planet/Worlds.ocf/GemGrabbers.ocs/Scenario.txt index 1fb23a875..b11cf3346 100644 --- a/planet/Worlds.ocf/GemGrabbers.ocs/Scenario.txt +++ b/planet/Worlds.ocf/GemGrabbers.ocs/Scenario.txt @@ -2,7 +2,7 @@ Title=GemGrabbers Icon=35 Version=6,0 -Difficulty=80 +Difficulty=90 [Definitions] Definition1=Objects.ocd diff --git a/planet/Worlds.ocf/Krakatoa.ocs/Scenario.txt b/planet/Worlds.ocf/Krakatoa.ocs/Scenario.txt index 14f3475b8..824360a9a 100644 --- a/planet/Worlds.ocf/Krakatoa.ocs/Scenario.txt +++ b/planet/Worlds.ocf/Krakatoa.ocs/Scenario.txt @@ -2,7 +2,7 @@ Icon=23 Title=Krakatoa Version=6,0 -Difficulty=60 +Difficulty=70 [Definitions] Definition1=Objects.ocd diff --git a/planet/Worlds.ocf/RapidRefining.ocs/DescDE.txt b/planet/Worlds.ocf/RapidRefining.ocs/DescDE.txt new file mode 100644 index 000000000..b2c3daa0c --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/DescDE.txt @@ -0,0 +1,9 @@ +Rasches Raffinieren + +An apparently infinite oil well is hidden deep inside a cave. Connect the well to the refinery drain outside of the cave using pumps and supply the refinery. + +Ziel: Pumpe Öl. + +Tipps: +- Do not set oil on fire, it will burn for a long time. +- You can connect multiple pipes to the refinery drain. diff --git a/planet/Worlds.ocf/RapidRefining.ocs/DescUS.txt b/planet/Worlds.ocf/RapidRefining.ocs/DescUS.txt new file mode 100644 index 000000000..5a1d29e52 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/DescUS.txt @@ -0,0 +1,9 @@ +Rapid Refining + +An apparently infinite oil well is hidden deep inside a cave. Connect the well to the refinery drain outside of the cave using pumps and supply the refinery. + +Goal: Pump oil. + +Hints: +- Do not set oil on fire, it will burn for a long time. +- You can connect multiple pipes to the refinery drain. diff --git a/planet/Worlds.ocf/RapidRefining.ocs/Icon.png b/planet/Worlds.ocf/RapidRefining.ocs/Icon.png new file mode 100644 index 000000000..6ff07f93b Binary files /dev/null and b/planet/Worlds.ocf/RapidRefining.ocs/Icon.png differ diff --git a/planet/Worlds.ocf/RapidRefining.ocs/Map.c b/planet/Worlds.ocf/RapidRefining.ocs/Map.c new file mode 100644 index 000000000..9c0d024cb --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/Map.c @@ -0,0 +1,250 @@ +/** + Rapid Refining + Use the oil from an underground well to power your settlement. + + @author Maikel +*/ + +#include Library_Map + + +// Called be the engine: draw the complete map here. +protected func InitializeMap(proplist map) +{ + // Map settings. + var overground_wdt = 40; + var overground_hgt = 20; + + // Retrieve the settings according to the MapSize setting. + var map_size; + if (SCENPAR_MapSize == 1) + map_size = [250, 150]; + if (SCENPAR_MapSize == 2) + map_size = [275, 150]; + if (SCENPAR_MapSize == 3) + map_size = [300, 150]; + + // Set the map size. + map->Resize(map_size[0], map_size[1]); + + // The overground area is in the top left corner, the underground are thereby the remainder. + var underground = {Algo = MAPALGO_Not, Op = {Algo = MAPALGO_Rect, X = 0, Y = 0, Wdt = overground_wdt, Hgt = overground_hgt}}; + Draw("Earth", underground); + + // Draw materials in the underground area and then overlay the rest of the map. + DrawMaterial("Earth-earth_root", underground, 2, 12); + DrawMaterial("Earth-earth_spongy", underground, 2, 12); + DrawMaterial("Granite", underground, 3, 6); + DrawMaterial("Tunnel", underground, 5, 8); + DrawMaterial("Rock-rock", underground, 3, 4); + DrawMaterial("Rock", underground, 3, 4); + DrawMaterial("Ore", underground, 6, 6); + DrawMaterial("Firestone", underground, 5, 4); + DrawMaterial("Coal", underground, 6, 4); + + // Draw some underground water lakes. + var underground_water = {Algo = MAPALGO_And, Op = [underground, {Algo = MAPALGO_Rect, X = 0, Y = map.Hgt / 2, Wdt = map.Wdt - 20, Hgt = map.Hgt / 2}]}; + DrawMaterial("Water", underground_water, [4, 10], 6); + + // The entrance border is out of granite. + var entrance_border = {Algo = MAPALGO_Border, Left = 3, Op = underground}; + entrance_border = {Algo = MAPALGO_Or, Op = [entrance_border, {Algo = MAPALGO_Turbulence, Iterations = 2, Amplitude = [6, 8], Scale = [6, 8], Seed = Random(65536), Op = entrance_border}]}; + DrawRock(entrance_border); + + // The entrance floor is out of earth and brick. + var entrance_floor = {Algo = MAPALGO_Border, Top = 3, Op = underground}; + Draw("Brick", entrance_floor); + var entrance_floor_earth = {Algo = MAPALGO_Border, Top = 2, Op = underground}; + var entrance_floor_earth = {Algo = MAPALGO_And, Op = [entrance_floor_earth, {Algo = MAPALGO_Rect, X = 4, Y = 0, Wdt = 17, Hgt = map.Hgt}]}; + Draw("Earth", entrance_floor_earth); + + // There are borders on the full underground area of the map. + var wdt = 3; + var underground_border = {Algo = MAPALGO_Not, Op = {Algo = MAPALGO_Rect, X = wdt, Y = wdt, Wdt = map.Wdt - 2 * wdt, Hgt = map.Hgt - 2 * wdt}}; + underground_border = {Algo = MAPALGO_And, Op = [underground_border, underground]}; + underground_border = {Algo = MAPALGO_Or, Op = [underground_border, {Algo = MAPALGO_Turbulence, Iterations = 6, Amplitude = 12, Scale = 16, Seed = Random(65536), Op = underground_border}]}; + underground_border = {Algo = MAPALGO_And, Op = [underground_border, underground, {Algo = MAPALGO_Not, Op = entrance_floor}]}; + DrawRock(underground_border); + + // Draw a tunnel to the oil well. + DrawMainTunnel(map, overground_wdt, overground_hgt); + + // Some slabs of granite/rock which block the path to the oil. + DrawRockSlabs(map); + + // There is a smaller oil field below the entrance. + DrawOilLakes(map); + + // The main oil well is in the bottom right of the map. + DrawOilWell(map, underground_border); + + // A large water lake at the bottom of the map. + DrawWaterLake(map, underground_border); + + // Some liquid veins above the oil well. + DrawLiquidVeins(map, underground_border); + + // Fix liquid borders. + FixLiquidBorders(); + + // Return true to tell the engine a map has been successfully created. + return true; +} + +public func DrawMainTunnel(proplist map, int overground_wdt, int overground_hgt) +{ + var sx = overground_wdt; + var sy = overground_hgt - 3; + var ex = map.Wdt - 20; + var ey = map.Hgt - 30; + var nr_steps = 10; + var tunnel_x = [], tunnel_y = []; + for (var index = 0; index <= nr_steps; index++) + { + var dev = 4 * Min(index, nr_steps - index); + tunnel_x[index] = sx + (ex - sx) * index / nr_steps + RandomX(-dev, dev); + tunnel_y[index] = sy + (ey - sy) * index / nr_steps + RandomX(-dev, dev); + } + + // Draw main tunnel. + var tunnel = {Algo = MAPALGO_Polygon, X = tunnel_x, Y = tunnel_y, Wdt = 3, Empty = true, Open = true}; + tunnel = {Algo = MAPALGO_Or, Op = [tunnel, {Algo = MAPALGO_Turbulence, Iterations = 2, Amplitude = [6, 8], Scale = [6, 8], Seed = Random(65536), Op = tunnel}]}; + Draw("Tunnel", tunnel); + + // Draw branches. + for (var index = 2; index <= nr_steps - 2; index++) + { + var x = tunnel_x[index]; + var y = tunnel_y[index]; + var to_x = x + RandomX(-5, 5); + var to_y = y + (2 * Random(2) - 1) * RandomX(16, 22); + var tunnel_branch = {Algo = MAPALGO_Polygon, X = [x, to_x], Y = [y, to_y], Wdt = 2, Empty = true, Open = true}; + tunnel_branch = {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 12, Scale = 8, Seed = Random(65536), Op = tunnel_branch}; + Draw("Tunnel", tunnel_branch); + } + return; +} + +public func DrawRockSlabs(proplist map) +{ + var slabs = {Algo = MAPALGO_Lines, X = 6, Y = 1, Distance = 32}; + slabs = {Algo = MAPALGO_And, Op = [slabs, {Algo = MAPALGO_RndChecker, Ratio = 75, Seed = Random(65536)}]}; + slabs = {Algo = MAPALGO_Turbulence, Iterations = 2, Amplitude = [6, 8], Scale = [6, 8], Seed = Random(65536), Op = slabs}; + slabs = {Algo = MAPALGO_And, Op = [slabs, {Algo = MAPALGO_Rect, X = map.Wdt / 3, Y = 0, Wdt = 2 * map.Wdt / 3, Hgt = map.Hgt}]}; + DrawRock(slabs); + return; +} + +public func DrawWaterLake(proplist map, proplist underground_border) +{ + var lake_height = 20; + var lake_width = 80; + var waterfall_height = 62; + var tunnel_height = 6; + + // Draw a large lake with tunnel above. + underground_border = {Algo = MAPALGO_And, Op = [underground_border, {Algo = MAPALGO_Not, Op = {Algo = MAPALGO_Rect, X = 0, Y = map.Hgt - lake_height - 2, Wdt = lake_width, Hgt = 6}}]}; + var lake_floor_rock = {Algo = MAPALGO_And, Op = [{Algo = MAPALGO_Lines, X = 3, Y = 0, Distance = 10}, {Algo = MAPALGO_Rect, X = 0, Y = map.Hgt - 7, Wdt = lake_width, Hgt = 7}]}; + var lake_floor_rock = {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 16, Scale = 8, Seed = Random(65536), Op = lake_floor_rock}; + underground_border = {Algo = MAPALGO_Or, Op = [underground_border, lake_floor_rock]}; + DrawRock(lake_floor_rock); + + + var tunnel = {Algo = MAPALGO_Rect, X = 0, Y = map.Hgt - lake_height - tunnel_height, Wdt = lake_width, Hgt = tunnel_height}; + tunnel = {Algo = MAPALGO_Or, Op = [tunnel, {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 16, Scale = 8, Seed = Random(65536), Op = tunnel}]}; + tunnel = {Algo = MAPALGO_And, Op = [tunnel, {Algo = MAPALGO_Not, Op = underground_border}]}; + Draw("Tunnel", tunnel); + + var lake = {Algo = MAPALGO_Rect, X = 0, Y = map.Hgt - lake_height, Wdt = lake_width, Hgt = lake_height}; + lake = {Algo = MAPALGO_And, Op = [lake, {Algo = MAPALGO_Not, Op = underground_border}]}; + Draw("Water:Water", lake); + + var lake_floor = {Algo = MAPALGO_Border, Bottom = 2, Op = lake}; + Draw("Sand", lake_floor); + + var lake_boundary = {Algo = MAPALGO_Rect, X = lake_width - 1, Y = map.Hgt - lake_height, Wdt = 2, Hgt = lake_height}; + lake_boundary = {Algo = MAPALGO_Or, Op = [lake_boundary, {Algo = MAPALGO_Turbulence, Iterations = 3, Amplitude = 12, Scale = 12, Seed = Random(65536), Op = lake_boundary}]}; + Draw("Everrock", lake_boundary); + var lake_boundary_rock = {Algo = MAPALGO_Border, Wdt = -2, Op = lake_boundary}; + DrawRock(lake_boundary_rock); + + // Draw a waterfall pooring into the lake. + var waterfall = {Algo = MAPALGO_Rect, X = 3, Y = map.Hgt - lake_height - waterfall_height, Wdt = 9, Hgt = waterfall_height}; + waterfall = {Algo = MAPALGO_Or, Op = [waterfall, {Algo = MAPALGO_Turbulence, Iterations = 3, Amplitude = 12, Scale = 12, Seed = Random(65536), Op = waterfall}]}; + waterfall = {Algo = MAPALGO_And, Op = [waterfall, {Algo = MAPALGO_Not, Op = underground_border}, {Algo = MAPALGO_Not, Op = lake}]}; + Draw("Tunnel", waterfall); + return; +} + +public func DrawOilLakes(proplist map) +{ + for (var cnt = 0; cnt < 3; cnt++) + { + var oil_lake_x = RandomX(map.Wdt / 10, 3 * map.Wdt / 10); + var oil_lake_y = RandomX(2 * map.Hgt / 7, 5 * map.Hgt / 7); + var oil_lake = {Algo = MAPALGO_Rect, X = oil_lake_x, Y = oil_lake_y, Wdt = 13, Hgt = 15}; + oil_lake = {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 10, Scale = 10, Seed = Random(65536), Op = oil_lake}; + var oil_lake_filled = {Algo = MAPALGO_And, Op = [oil_lake, {Algo = MAPALGO_Rect, X = 0, Y = oil_lake_y - 3, Wdt = map.Wdt, Hgt = map.Hgt}]}; + Draw("Tunnel", oil_lake); + Draw("Oil", oil_lake_filled); + var oil_lake_border = {Algo = MAPALGO_Border, Left = 2, Right = 2, Bottom = 3, Top = 1, Op = oil_lake}; + DrawRock(oil_lake_border); + } + return; +} + +public func DrawOilWell(proplist map, proplist underground_border) +{ + var oil_field = {Algo = MAPALGO_Polygon, + X = [map.Wdt, map.Wdt - 16, map.Wdt - 14, map.Wdt - 10, map.Wdt - 17, map.Wdt - 22, map.Wdt - 22, map.Wdt - 27, map.Wdt - 29], + Y = [map.Hgt - 5, map.Hgt - 5, map.Hgt - 12, map.Hgt - 18, map.Hgt - 23, map.Hgt - 20, map.Hgt - 12, map.Hgt - 12, map.Hgt - 16], + Wdt = 3, Empty = true, Open = true}; + var oil_field_oil = {Algo = MAPALGO_And, Op = [oil_field, {Algo = MAPALGO_Rect, X = 0, Y = map.Hgt - 8, Wdt = map.Wdt, Hgt = 8}]}; + var oil_field_water = {Algo = MAPALGO_And, Op = [oil_field, {Algo = MAPALGO_Rect, X = 0, Y = 0, Wdt = map.Wdt, Hgt = map.Hgt - 8}]}; + Draw("Oil:Oil", oil_field_oil); + Draw("Water", oil_field_water); + var oil_field_border = {Algo = MAPALGO_Border, Left = -3, Right = -3, Top = -3, Bottom = -5, Op = oil_field}; + Draw("Everrock", oil_field_border); + var oil_field_entrance = {Algo = MAPALGO_Rect, X = map.Wdt - 31, Y = map.Hgt - 22, Wdt = 5, Hgt = 5}; + Draw("Tunnel", oil_field_entrance); + return; +} + +public func DrawLiquidVeins(proplist map, proplist underground_border) +{ + // Draw some gold as a source of wealth. + var gold = {Algo = MAPALGO_Rect, X = map.Wdt - 60, Y = 10, Wdt = 50, Hgt = 36}; + gold = {Algo = MAPALGO_And, Op = [gold, {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 12, Scale = 12, Seed = Random(65536), Op = gold}]}; + DrawMaterial("Gold", gold, 4, 30); + + // Draw the veins. + var vein_material = "Water"; + if (SCENPAR_Difficulty == 2) + vein_material = "Acid"; + if (SCENPAR_Difficulty == 3) + vein_material = "DuroLava"; + var vein_area = {Algo = MAPALGO_Polygon, X = [map.Wdt - 96, map.Wdt, map.Wdt, map.Wdt - 44], Y = [0, 0, 108, 82]}; + vein_area = {Algo = MAPALGO_And, Op = [vein_area, {Algo = MAPALGO_Not, Op = underground_border}]}; + + var veins = {Algo = MAPALGO_Or, Op = [ + {Algo = MAPALGO_Lines, X = 2, Y = -1, Distance = 12}, + {Algo = MAPALGO_Lines, X = 2, Y = 1, Distance = 12}, + {Algo = MAPALGO_Lines, X = 0, Y = 1, Distance = 16} + ]}; + veins = {Algo = MAPALGO_And, Op = [veins, vein_area]}; + veins = {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 12, Scale = 12, Seed = Random(65536), Op = veins}; + + Draw(vein_material, veins); + return; +} + + +/*-- Helper Functions --*/ + +public func DrawRock(proplist layer) +{ + Draw("Granite", layer); + DrawMaterial("Rock-rock", layer, 4, 18); + DrawMaterial("Rock", layer, 4, 18); + return; +} \ No newline at end of file diff --git a/planet/Worlds.ocf/RapidRefining.ocs/ParameterDefs.txt b/planet/Worlds.ocf/RapidRefining.ocs/ParameterDefs.txt new file mode 100644 index 000000000..b9f83b2cc --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/ParameterDefs.txt @@ -0,0 +1,47 @@ +[ParameterDef] +Name=$Difficulty$ +Description=$DescDifficulty$ +ID=Difficulty +Default=1 +LeagueValue=3 + + [Options] + + [Option] + Name=$DiffNormal$ + Description=$DescDiffNormal$ + Value=1 + + [Option] + Name=$DiffHard$ + Description=$DescDiffHard$ + Value=2 + + [Option] + Name=$DiffInsane$ + Description=$DescDiffInsane$ + Value=3 + +[ParameterDef] +Name=$MapSize$ +Description=$DescMapSize$ +ID=MapSize +Default=1 +LeagueValue=1 + + [Options] + + [Option] + Name=$MapSmall$ + Description=$DescMapSmall$ + Value=1 + + [Option] + Name=$MapAverage$ + Description=$DescMapAverage$ + Value=2 + + [Option] + Name=$MapLarge$ + Description=$DescMapLarge$ + Value=3 diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/DefCore.txt b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/DefCore.txt new file mode 100644 index 000000000..21e1294e5 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/DefCore.txt @@ -0,0 +1,14 @@ +[DefCore] +id=RefineryDrain +Version=6,0 +Category=C4D_Structure +Width=16 +Height=32 +Offset=-8,-16 +Vertices=4 +VertexX=-8,-8,8,8 +VertexY=-2,15,-2,15 +VertexCNAT=5,9,6,10 +VertexFriction=50,50,100,100 +Construction=1 +Mass=10 diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Graphics.4.png b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Graphics.4.png new file mode 100644 index 000000000..a1107ec0c Binary files /dev/null and b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Graphics.4.png differ diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Script.c b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Script.c new file mode 100644 index 000000000..3d66d1bf2 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Script.c @@ -0,0 +1,99 @@ +/** + Refinery Drain + Oil must be pumped into this structure to be processed further. + + @author Maikel +*/ + +#include Library_Structure +#include Library_Ownable +#include Library_Tank + + +/*-- Pipeline --*/ + +public func GetLiquidContainerMaxFillLevel() +{ + return 10**9; +} + +public func IsLiquidContainerForMaterial(string liquid) +{ + return WildcardMatch("Oil", liquid); +} + +public func QueryConnectPipe(object pipe) +{ + if (pipe->IsDrainPipe() || pipe->IsNeutralPipe()) + { + return false; + } + else + { + pipe->Report("$MsgPipeProhibited$"); + return true; + } +} + +public func OnPipeConnect(object pipe, string specific_pipe_state) +{ + SetNeutralPipe(pipe); + pipe->Report("$MsgConnectedPipe$"); +} + + +/*-- Interaction Interface --*/ + +public func GetOilAmount() +{ + var oil = FindObject(Find_ID(Oil), Find_Container(this)); + if (oil) + return oil->GetStackCount() / 1000; + return 0; +} + +public func HasInteractionMenu() { return true; } + +public func GetInteractionMenus(object clonk) +{ + var menus = _inherited() ?? []; + var oil_menu = + { + title = "$MsgOilOverview$", + entries_callback = this.GetOilDisplayMenuEntries, + callback_hover = "OnOilDisplayHover", + callback_target = this, + BackgroundColor = RGB(0, 50, 50), + Priority = 20 + }; + PushBack(menus, oil_menu); + return menus; +} + +public func GetOilDisplayMenuEntries(object clonk) +{ + return + [{ + symbol = Oil, + extra_data = "oil", + custom = { + Style = GUI_FitChildren | GUI_TextVCenter | GUI_TextLeft, + Bottom = "1.1em", + BackgroundColor = {Std = 0, OnHover = 0x50ff0000}, + Priority = 1, + Text = Format("$MsgOilPumped$", GetOilAmount()) + } + }]; +} + +public func OnOilDisplayHover(id symbol, string extra_data, desc_menu_target, menu_id) +{ + GuiUpdateText(Format("$MsgOilDescription$", GetOilAmount()), menu_id, 1, desc_menu_target); + return; +} + + +/*-- Properties --*/ + +local Name = "$Name$"; +local Description = "$Description$"; \ No newline at end of file diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/StringTblDE.txt b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/StringTblDE.txt new file mode 100644 index 000000000..124025bdc --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/StringTblDE.txt @@ -0,0 +1,9 @@ +Name=Raffinerie Drain +Description=Attach the drain pipe of a pump to this structure to pump oil into the refinery. Multiple pipes can be connected to the refinery drain. + +MsgOilOverview=Oil Overview +MsgOilPumped=Oil amount: %d {{Oil}}. +MsgOilDescription=Currently %d {{Oil}} has been transferred into the refinery. + +MsgConnectedPipe=Rohr angeschlossen. +MsgPipeProhibited=Zuflussrohre können nicht an den Raffinerie angeschlossen werden. \ No newline at end of file diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/StringTblUS.txt b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/StringTblUS.txt new file mode 100644 index 000000000..6cf60abdd --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/StringTblUS.txt @@ -0,0 +1,9 @@ +Name=Refinery Drain +Description=Attach the drain pipe of a pump to this structure to pump oil into the refinery. Multiple pipes can be connected to the refinery drain. + +MsgOilOverview=Oil Overview +MsgOilPumped=Oil amount: %d {{Oil}}. +MsgOilDescription=Currently %d {{Oil}} has been transferred into the refinery. + +MsgConnectedPipe=Connected pipe. +MsgPipeProhibited=Source pipes cannot be connected to the foundry. \ No newline at end of file diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/DefCore.txt b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/DefCore.txt new file mode 100644 index 000000000..d0267e7e4 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/DefCore.txt @@ -0,0 +1,5 @@ +[DefCore] +id=Goal_Refinery +Version=6,0 +Category=C4D_StaticBack|C4D_Goal +Picture=0,0,128,128 diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/Graphics.png b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/Graphics.png new file mode 100644 index 000000000..ddd20a87e Binary files /dev/null and b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/Graphics.png differ diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/Script.c b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/Script.c new file mode 100644 index 000000000..675afdc9b --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/Script.c @@ -0,0 +1,49 @@ +/** + Refinery Goal + A certain amount of oil has to be pumped into the refinery drain. + + @author Maikel +*/ + + +#include Library_Goal + +local goal_amount; + +protected func Initialize() +{ + goal_amount = 0; + return _inherited(...); +} + +public func SetGoalAmount(int amount) +{ + goal_amount = amount; + return; +} + +private func GetPumpedAmount() +{ + var refinery_drain = FindObject(Find_ID(RefineryDrain)); + if (!refinery_drain) + return 0; + return refinery_drain->GetOilAmount(); +} + +public func IsFulfilled() +{ + return GetPumpedAmount() >= goal_amount; +} + +public func GetDescription(int plr) +{ + if (IsFulfilled()) + return "$DescriptionCompleted$"; + return Format("$Description$", GetPumpedAmount(), goal_amount); +} + + +/*-- Proplist --*/ + +local Name = "$Name$"; +local Description = "$Description$"; diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/StringTblDE.txt b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/StringTblDE.txt new file mode 100644 index 000000000..9cd8cccaf --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/StringTblDE.txt @@ -0,0 +1,3 @@ +Name=Raffinerie +Description=You have currently pumped %d {{Oil}} into the refinery drain out of the %d {{Oil}} needed to fulfill this goal. +DescriptionCompleted=Congratulations! You have pumped enough oil into the refinery drain. \ No newline at end of file diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/StringTblUS.txt b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/StringTblUS.txt new file mode 100644 index 000000000..e1d7be9eb --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/StringTblUS.txt @@ -0,0 +1,3 @@ +Name=Refinery +Description=You have currently pumped %d {{Oil}} into the refinery drain out of the %d {{Oil}} needed to fulfill this goal. +DescriptionCompleted=Congratulations! You have pumped enough oil into the refinery drain. \ No newline at end of file diff --git a/planet/Worlds.ocf/RapidRefining.ocs/Scenario.txt b/planet/Worlds.ocf/RapidRefining.ocs/Scenario.txt new file mode 100644 index 000000000..a3955837d --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/Scenario.txt @@ -0,0 +1,31 @@ +[Head] +Title=RapidRefining +Icon=24 +Version=6,0 +Difficulty=50 + +[Definitions] +Definition1=Objects.ocd + +[Player1] +Crew=Clonk=2 + +[Player2] +Crew=Clonk=2 + +[Player3] +Crew=Clonk=2 + +[Player4] +Crew=Clonk=2 + +[Landscape] +Sky=Clouds1 +TopOpen=0 +BottomOpen=0 + +[Weather] +Climate=0 +YearSpeed=0 +Wind=0,50,-50,50 + diff --git a/planet/Worlds.ocf/RapidRefining.ocs/Script.c b/planet/Worlds.ocf/RapidRefining.ocs/Script.c new file mode 100644 index 000000000..d1fa12ee2 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/Script.c @@ -0,0 +1,223 @@ +/** + Rapid Refining + Use the oil from an underground well to power your settlement. + + @author Maikel +*/ + + +// Whether the intro has been initialized. +static intro_init; + +// Whether the first players has been initialized. +static first_plr_init; + +protected func Initialize() +{ + // Show wealth in HUD. + GUI_Controller->ShowWealth(); + + // Rules: team account and buying at flagpole. + CreateObject(Rule_TeamAccount); + CreateObject(Rule_BuyAtFlagpole); + + // Goal: pump oil into refinery drain. + var goal = CreateObject(Goal_Refinery); + var amount = 400; + if (SCENPAR_Difficulty == 2) + amount = 800; + else if (SCENPAR_Difficulty == 3) + amount = 1600; + goal->SetGoalAmount(amount); + + // Initialize different parts of the scenario. + InitEnvironment(SCENPAR_Difficulty); + InitVegetation(SCENPAR_MapSize); + InitAnimals(SCENPAR_MapSize, SCENPAR_Difficulty); + return; +} + +protected func OnGoalsFulfilled() +{ + // Give the remaining players their achievement. + GainScenarioAchievement("Done", BoundBy(SCENPAR_Difficulty, 1, 3)); + return false; +} + + +/*-- Player Initialization --*/ + +protected func InitializePlayer(int plr) +{ + // Harsh zoom range. + SetPlayerZoomByViewRange(plr, 400, nil, PLRZOOM_Direct | PLRZOOM_LimitMax); + SetPlayerViewLock(plr, true); + SetFoW(false, plr); + + // First player inits the base. + if (!first_plr_init) + { + InitBase(plr, 4 - SCENPAR_Difficulty); + first_plr_init = true; + // Give only the first joined player some wealth. + SetWealth(plr, 150 - 50 * SCENPAR_Difficulty); + } + + // Position and materials for the crew. + var crew; + for (var i = 0; crew = GetCrew(plr, i); ++i) + { + crew->SetPosition(20 + Random(32), 160 - 10); + crew->CreateContents(Shovel); + } + + // Give the player basic and pumping knowledge. + GivePlayerBasicKnowledge(plr); + GivePlayerPumpingKnowledge(plr); + GivePlayerWeaponryKnowledge(plr); + GivePlayerAdvancedKnowledge(plr); + GivePlayerFarmingKnowledge(plr); + RemovePlayerSpecificKnowledge(plr, [WindGenerator]); + + // Give the player the elementary base materials. + GivePlayerElementaryBaseMaterial(plr); + GivePlayerToolsBaseMaterial(plr); + + // Initialize the intro sequence if not yet started. + if (!intro_init) + { + //StartSequence("Intro", 0); + intro_init = true; + } + return; +} + +private func InitBase(int owner, int amount) +{ + var y = 160; + + // The basic settlement: flagpole, wind generator, chest. + CreateObjectAbove(Flagpole, 184, y, owner); + var chest = CreateObjectAbove(Chest, 202, y, owner); + chest->CreateContents(Hammer, 2); + chest->CreateContents(Axe, 2); + CreateObjectAbove(WindGenerator, 222, y, owner); + + // Two pumps connected to the refinery drain. + var refinery_exit = CreateObjectAbove(RefineryDrain, 8, y, owner); + var pump1 = CreateObjectAbove(Pump, 250, y, owner); + var pump2 = CreateObjectAbove(Pump, 284, y, owner); + var pipe1 = pump1->CreateObject(Pipe); + pipe1->ConnectPipeTo(pump1); + pipe1 = pump1->CreateObject(Pipe, 8); + pipe1->ConnectPipeTo(pump1); + pipe1->ConnectPipeTo(refinery_exit); + var pipe2 = pump2->CreateObject(Pipe, 8); + pipe2->ConnectPipeTo(pump2); + pipe2 = pump2->CreateObject(Pipe, -8); + pipe2->ConnectPipeTo(pump2); + + // Additional material in the chest. + if (amount >= 2) + { + chest->CreateContents(Wood, 12); + chest->CreateContents(Metal, 8); + chest->CreateContents(Dynamite, 4); + if (amount >= 3) + { + chest->CreateContents(Wood, 12); + chest->CreateContents(Metal, 8); + chest->CreateContents(Loam, 4); + chest->CreateContents(Pickaxe, 2); + chest->CreateContents(Bread, 4); + } + } + return; +} + + +/*-- Scenario Initialization --*/ + +private func InitEnvironment(int difficulty) +{ + // Sky has some parallax. + SetSkyParallax(1, 20, 20); + + // Some earthquakes if difficulty prescribes it. + if (difficulty >= 2) + Earthquake->SetChance(4 * (difficulty - 1)); + + // A waterfall above the underground lake. + var waterfall_x = 50; + var waterfall_y = LandscapeHeight() - 600; + var trunk = CreateObjectAbove(Trunk, waterfall_x, waterfall_y); + trunk->DoCon(30); trunk->SetR(150); trunk.Plane = 510; + trunk.MeshTransformation = [-70, 0, 998, 0, 0, 1000, 0, 0, -998, 0, -70, 0]; + trunk->MakeInvincible(); + + var waterfall = CreateWaterfall(waterfall_x + 22, waterfall_y - 10, 10, "Water"); + waterfall->SetDirection(2, 0, 3, 6); + waterfall->SetSoundLocation(waterfall_x + 40, waterfall_y + 240); + + CreateLiquidDrain(8, 1040, 10); + CreateLiquidDrain(16, 1040, 10); + CreateLiquidDrain(24, 1040, 10); + return; +} + +private func InitVegetation(int map_size) +{ + var wdt = LandscapeWidth(); + var hgt = LandscapeHeight(); + + // Some plants and trees on the outside. + Tree_Deciduous->Place(16, Shape->Rectangle(0, 0, 240, 160)); + Tree_Coniferous2->Place(2, Shape->Rectangle(0, 0, 240, 160)); + Cotton->Place(4, Shape->Rectangle(0, 0, 240, 160)); + SproutBerryBush->Place(2, Shape->Rectangle(0, 0, 240, 160)); + Grass->Place(100); + + // Some plants and in the caves. + LargeCaveMushroom->Place(40 + 6 * map_size, nil, {terraform = false}); + Fern->Place(40 + 6 * map_size); + Mushroom->Place(40 + 6 * map_size); + Branch->Place(20 + 3 * map_size); + + // Some objects in the earth. + PlaceObjects(Rock, 40 + 10 * map_size + Random(5),"Earth"); + PlaceObjects(Firestone, 40 + 10 * map_size + Random(5), "Earth"); + PlaceObjects(Loam, 40 + 10 * map_size + Random(5), "Earth"); + + // Underwater plants. + var place_rect = Shape->Rectangle(0, 2 * hgt / 3, wdt / 4, hgt / 3); + Seaweed->Place(12, place_rect); + Coral->Place(8, place_rect); + + // Place some diamonds in the hard to reach location. + Diamond->Place(20, Shape->Rectangle(5 * wdt / 6, 0, wdt / 6, hgt / 4)); + return; +} + +private func InitAnimals(int map_size, int difficulty) +{ + var wdt = LandscapeWidth(); + var hgt = LandscapeHeight(); + + // Some butterflies as atmosphere. + for (var i = 0; i < 8; i++) + PlaceAnimal(Butterfly); + + // Some wipfs underground. + Wipf->Place(10); + + // Place some fishes and piranhas as difficulty prescribes it. + var place_rect = Shape->Rectangle(0, 2 * hgt / 3, wdt / 4, hgt / 3); + var fish_count = 15; + Fish->Place(fish_count * (3 - difficulty), place_rect); + Piranha->Place(fish_count * (difficulty - 1), place_rect); + + // Bats on higher difficulty. + if (difficulty >= 2) + Bat->Place((difficulty - 1) * 12, Shape->Rectangle(2 * wdt / 3, 0, wdt / 3, hgt)); + return; +} diff --git a/planet/Worlds.ocf/RapidRefining.ocs/StringTblDE.txt b/planet/Worlds.ocf/RapidRefining.ocs/StringTblDE.txt new file mode 100644 index 000000000..bd0d3c937 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/StringTblDE.txt @@ -0,0 +1,19 @@ +# Scenario parameters: difficulty +Difficulty=Schwierigkeit +DescDifficulty=Setzt die Schwierigkeit dieser Runde. +DiffNormal=Normal +DescDiffNormal=Die Schwierigkeit dieser Runde ist normal. +DiffHard=Schwer +DescDiffHard=Die Schwierigkeit dieser Runde ist schwer. +DiffInsane=Irrsinnig +DescDiffInsane=Die Schwierigkeit dieser Runde ist irrsinnig. + +# Scenario parameters: map size +MapSize=Kartengröße +DescMapSize=Setzt die Kartengröße dieser Runde. +MapSmall=Klein +DescMapSmall=Die Karte dieser Runde wird klein sein +MapAverage=Durchschnittlich +DescMapAverage=Die Karte dieser Runde wird durchschnittlich sein. +MapLarge=Groß +DescMapLarge=Die Karte dieser Runde wird groß sein. diff --git a/planet/Worlds.ocf/RapidRefining.ocs/StringTblUS.txt b/planet/Worlds.ocf/RapidRefining.ocs/StringTblUS.txt new file mode 100644 index 000000000..ec0653e17 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/StringTblUS.txt @@ -0,0 +1,19 @@ +# Scenario parameters: difficulty +Difficulty=Difficulty +DescDifficulty=Sets this round's difficulty. +DiffNormal=Normal +DescDiffNormal=This round's difficulty will be set to normal. +DiffHard=Hard +DescDiffHard=This round's difficulty will be set to hard. +DiffInsane=Insane +DescDiffInsane=This round's difficulty will be set to insane. + +# Scenario parameters: map size +MapSize=Map size +DescMapSize=Sets this round's map size. +MapSmall=Small +DescMapSmall=This round's map will be small. +MapAverage=Average +DescMapAverage=This round's map will be average. +MapLarge=Large +DescMapLarge=This round's map will be large. diff --git a/planet/Worlds.ocf/RapidRefining.ocs/System.ocg/PipeLength.c b/planet/Worlds.ocf/RapidRefining.ocs/System.ocg/PipeLength.c new file mode 100644 index 000000000..dbf340872 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/System.ocg/PipeLength.c @@ -0,0 +1,9 @@ +// Maximum pipe length depends on difficulty. + +#appendto PipeLine + +public func Definition(proplist def) +{ + def.PipeMaxLength = def.PipeMaxLength * (12 - 2 * SCENPAR_Difficulty) / 10; + return; +} diff --git a/planet/Worlds.ocf/RapidRefining.ocs/Title.jpg b/planet/Worlds.ocf/RapidRefining.ocs/Title.jpg new file mode 100644 index 000000000..870f446e0 Binary files /dev/null and b/planet/Worlds.ocf/RapidRefining.ocs/Title.jpg differ diff --git a/planet/Worlds.ocf/RapidRefining.ocs/Title.txt b/planet/Worlds.ocf/RapidRefining.ocs/Title.txt new file mode 100644 index 000000000..cd783994a --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/Title.txt @@ -0,0 +1,2 @@ +DE:Rasches Raffinieren +US:Rapid Refining \ No newline at end of file diff --git a/src/C4Include.h b/src/C4Include.h index c1377b5ae..942581524 100644 --- a/src/C4Include.h +++ b/src/C4Include.h @@ -62,6 +62,7 @@ don't need to include this file or any of the files it includes. */ #include #include #include +#include #include "lib/Standard.h" #include "C4Prototypes.h"