forked from Mirrors/openclonk
Merge branch 'master' into qteditor
Conflicts: planet/Objects.ocd/Items.ocd/Tools.ocd/Dynamite.ocd/Script.c planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/DefCore.txtqteditor
commit
bce903ee04
|
@ -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);
|
||||
|
|
|
@ -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$
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*--
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
Name=Boiling Laval
|
||||
Name=Boiling Lava
|
||||
Description=Causes Lava on the map to boil
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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};
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
|
@ -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")
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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};
|
||||
local Components = {Cloth = 1, Metal = 1};
|
||||
|
|
|
@ -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
|
Binary file not shown.
Binary file not shown.
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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};
|
|
@ -0,0 +1,2 @@
|
|||
Name=Helm
|
||||
Description=Bietet dem Clonk einigen Schutz. Drücke [Benutzen] um den Helm auf- oder abzusetzen.
|
|
@ -0,0 +1,2 @@
|
|||
Name=Helmet
|
||||
Description=Provides the clonk with some protection. Press [Use] to take the helmet on or off.
|
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
|
@ -1,5 +0,0 @@
|
|||
[DefCore]
|
||||
id=Library_CreatureControl
|
||||
Version=6,1
|
||||
Category=C4D_StaticBack
|
||||
HideInCreator=true
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
[DefCore]
|
||||
id=Library_Wearable
|
||||
Version=8,0
|
||||
Category=C4D_StaticBack
|
|
@ -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();
|
||||
}
|
||||
};
|
|
@ -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))
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Name=Kokosnussbaum
|
||||
Name=Kokospalme
|
|
@ -1 +1 @@
|
|||
Name=Coconut Tree
|
||||
Name=Coconut Palm
|
|
@ -1,7 +1,7 @@
|
|||
[Material]
|
||||
Name=Brick
|
||||
Shape=Smoother
|
||||
Density=50
|
||||
Density=90
|
||||
Friction=15
|
||||
Placement=80
|
||||
TextureOverlay=brick
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 #
|
||||
# ======================================================================= #
|
||||
|
|
|
@ -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, ...);
|
||||
}
|
||||
return _inherited(plr, ctrl, x, y, strength, repeat, status, ...);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Icon=34
|
||||
Title=AcidRift
|
||||
Version=6,0
|
||||
Difficulty=70
|
||||
Difficulty=80
|
||||
|
||||
[Definitions]
|
||||
Definition1=Objects.ocd
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Icon=36
|
||||
Title=Chine
|
||||
Version=6,0
|
||||
Difficulty=50
|
||||
Difficulty=60
|
||||
|
||||
[Definitions]
|
||||
Definition1=Objects.ocd
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Title=GemGrabbers
|
||||
Icon=35
|
||||
Version=6,0
|
||||
Difficulty=80
|
||||
Difficulty=90
|
||||
|
||||
[Definitions]
|
||||
Definition1=Objects.ocd
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Icon=23
|
||||
Title=Krakatoa
|
||||
Version=6,0
|
||||
Difficulty=60
|
||||
Difficulty=70
|
||||
|
||||
[Definitions]
|
||||
Definition1=Objects.ocd
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
|
@ -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$";
|
|
@ -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.
|
|
@ -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.
|
|
@ -0,0 +1,5 @@
|
|||
[DefCore]
|
||||
id=Goal_Refinery
|
||||
Version=6,0
|
||||
Category=C4D_StaticBack|C4D_Goal
|
||||
Picture=0,0,128,128
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -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$";
|
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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.
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 91 KiB |
|
@ -0,0 +1,2 @@
|
|||
DE:Rasches Raffinieren
|
||||
US:Rapid Refining
|
|
@ -62,6 +62,7 @@ don't need to include this file or any of the files it includes. */
|
|||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <math.h>
|
||||
|
||||
#include "lib/Standard.h"
|
||||
#include "C4Prototypes.h"
|
||||
|
|
Loading…
Reference in New Issue