Remove folders from planet/ which aren't part of the release

stable-8
Lukas Werling 2018-01-31 17:52:14 +01:00
parent 18bb8371d3
commit 4262fd0c08
314 changed files with 0 additions and 15700 deletions

View File

@ -1,5 +0,0 @@
[DefCore]
id=Ambience
Version=8,0
Category=C4D_StaticBack | C4D_Rule
Picture=0,0,128,128

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,298 +0,0 @@
/**
Ambience
Controls sound and music depending on the environment the player is in
@author Sven2
*/
local exec_counter; // counter to distribute execution of players across frames
local last_environment; // array indexed by player number: pointer to environment the player was in last
local environments; // array of available environments for which it is checked if the player is in. sorted by priority.
// Initialization
protected func Initialize()
{
// Base environment
Environment = {
actions = [],
min_change_delay = 1,
min_initial_change_delay = 5,
AddSound = this.Env_AddSound,
AddAction = this.Env_AddAction,
SetMusic = this.Env_SetMusic
};
// Register default environments (overloadable)
this->InitializeEnvironments();
// Periodic execution of ambience events
last_environment = [];
AddTimer(this.Execute, 10);
return true;
}
func InitializeEnvironments()
{
// Register all standard environments
environments = [];
// Underwater: Clonk is swimming in water
var underwater = this.env_underwater = new Environment {};
underwater->SetMusic("underwater");
underwater.CheckPlayer = this.EnvCheck_Underwater;
AddEnvironment(underwater, 1400);
// City: Clonk is surrounded by buildings
var city = this.env_city = new Environment {};
city->SetMusic("city");
city.CheckPlayer = this.EnvCheck_City;
AddEnvironment(city, 1200);
// Lava: Lava material is nearby
var lava = this.env_lava = new Environment {};
lava->SetMusic("lava");
lava.CheckPlayer = this.EnvCheck_Lava;
lava.mat_mask = CreateArray(); // material mask for lava materials. +1 cuz sky.
lava.mat_mask[Material("Lava")+1] = true; // loop over materials and check incindiary instead? Whoever introduces the next lava type can do that...
lava.mat_mask[Material("DuroLava")+1] = true;
lava.min_change_delay = 3; // Easy to miss lava on search.
AddEnvironment(lava, 1000);
// Underground: Clonk in front of tunnel
var underground = this.env_underground = new Environment {};
underground->SetMusic("underground");
underground.CheckPlayer = this.EnvCheck_Underground;
AddEnvironment(underground, 800);
// Mountains: Overground and lots of rock around
var mountains = this.env_mountains = new Environment {};
mountains->SetMusic("mountains");
mountains.CheckPlayer = this.EnvCheck_Mountains;
mountains.mat_mask = CreateArray(); // material mask for mountain materials. +1 cuz sky.
mountains.mat_mask[Material("Rock")+1] = true;
mountains.mat_mask[Material("Granite")+1] = true;
mountains.mat_mask[Material("Ore")+1] = true;
mountains.mat_mask[Material("Gold")+1] = true;
mountains.min_change_delay = 3; // Pretty unstable condition
AddEnvironment(mountains, 600);
// Snow: It's snowing around the clonk
var snow = this.env_snow = new Environment {};
snow->SetMusic("snow");
snow.CheckPlayer = this.EnvCheck_Snow;
snow.min_change_delay = 6; // Persist a while after snowing stopped
snow.mat = Material("Snow");
AddEnvironment(snow, 400);
// Night: Sunlight blocked by planet
var night = this.env_night = new Environment {};
night->SetMusic("night");
night.CheckPlayer = this.EnvCheck_Night;
AddEnvironment(night, 200);
// Overground: Default environment
var overground = this.env_overground = new Environment {};
overground->SetMusic("overground");
overground.CheckPlayer = this.EnvCheck_Overground;
overground->AddSound("UI::Ding", 100);
AddEnvironment(overground, 0);
return true;
}
private func Execute()
{
// Per-player execution every third timer (~.8 seconds)
var i=GetPlayerCount(C4PT_User);
while (i--) if (!(++exec_counter % 3))
{
ExecutePlayer(GetPlayerByIndex(i, C4PT_User));
}
return true;
}
private func ExecutePlayer(int plr)
{
var cursor = GetCursor(plr);
// Determine environment the player is currently in
var environment = nil;
if (cursor)
{
var last_env = last_environment[plr];
var x = cursor->GetX(), y = cursor->GetY();
for (var test_environment in environments)
{
if (environment = test_environment->CheckPlayer(cursor, x, y, test_environment == last_env))
{
// We've found a matchign environment.
// Was it a change? Then check delays first
if (test_environment != last_env)
{
if (last_env && last_env.no_change_delay)
{
// Environment should change but a delay is specified. Keep last environment for now.
--last_env.no_change_delay;
environment = last_env;
break;
}
// New environment and change delay has passed.
environment.no_change_delay = environment.min_initial_change_delay;
Log("%s environment: %s", GetPlayerName(plr), environment.music);
}
else
{
// Was no change: Reset change delays
environment.no_change_delay = Max(environment.no_change_delay, environment.min_change_delay);
}
break;
}
}
}
last_environment[plr] = environment;
if (!environment) return true;
// Music by environment
this->SetPlayList(environment.music, plr, true, 3000);
// Sounds and actions by environment
for (var action in environment.actions)
if (Random(1000) < action.chance)
cursor->Call(action.fn, action.par[0], action.par[1], action.par[2], action.par[3], action.par[4]);
return true;
}
func InitializePlayer(int plr)
{
// Newly joining players should have set playlist immediately (so they don't start playing a random song just to switch it immediately)
ExecutePlayer(plr);
return true;
}
func RemovePlayer(int plr)
{
// Ensure newly joining players don't check on another player's environment
last_environment[plr] = nil;
return true;
}
protected func Activate(int byplr)
{
MessageWindow(this.Description, byplr);
return true;
}
/* Environment functions */
func AddEnvironment(proplist new_env, priority)
{
if (GetType(priority)) new_env.Priority = priority;
this.environments[GetLength(environments)] = new_env;
SortArrayByProperty(this.environments, "Priority", true);
return true;
}
private func Env_AddSound(string snd_name, chance)
{
return Env_AddAction(Global.Sound, snd_name, chance ?? 50);
}
private func Env_AddAction(afn, par0, par1, par2, par3, par4)
{
return this.actions[GetLength(this.actions)] = { fn=afn, par=[par0, par1, par2, par3, par4] };
}
private func Env_SetMusic(string playlist)
{
this.music = playlist;
return true;
}
/* Default environment checks */
private func EnvCheck_Underwater(object cursor, int x, int y, bool is_current)
{
// Clonk should be swimming
if (cursor->GetProcedure() != "SWIM") return nil;
// For initial change, clonk should also be diving: Check for breath below 80%
// Use > instead of >= to ensure 0-breath-clonks can also get the environment
if (!is_current && cursor->GetBreath() > cursor.MaxBreath*4/5) return nil;
return this;
}
private func EnvCheck_City(object cursor, int x, int y, bool is_current)
{
// There must be buildings around the clonk
var building_count = cursor->ObjectCount(cursor->Find_AtRect(-180,-100,360,200), Find_Func("IsStructure"));
// 3 buildings to start the environment. Just 1 building to sustain it.
if (building_count < 3-2*is_current) return nil;
return this;
}
private func EnvCheck_Lava(object cursor, int x, int y, bool is_current)
{
// Check for lava pixels. First check if the last lava pixel we found is still in place.
var search_range;
if (is_current)
{
if (this.mat_mask[GetMaterial(this.last_x, this.last_y)+1])
if (Distance(this.last_x, this.last_y, x, y) < 140)
return this;
search_range = 140;
}
else
{
search_range = 70;
}
// Now search for lava in search range
var ang = Random(360);
for (; search_range >= 0; search_range -= 10)
{
ang += 200;
var x2 = x + Sin(ang, search_range);
var y2 = y + Cos(ang, search_range);
if (this.mat_mask[GetMaterial(x2, y2)+1])
{
// Lava found!
this.last_x = x2;
this.last_y = y2;
return this;
}
}
// No lava found
return nil;
}
private func EnvCheck_Underground(object cursor, int x, int y, bool is_current)
{
// Check for underground: No sky at cursor or above
if (GetMaterial(x,y)<0) return nil;
if (GetMaterial(x,y-30)<0) return nil;
if (GetMaterial(x-10,y-20)<0) return nil;
if (GetMaterial(x+10,y-20)<0) return nil;
return this;
}
private func EnvCheck_Mountains(object cursor, int x, int y, bool is_current)
{
// Check for mountains: Rock materials below
var num_rock;
for (var y2=0; y2<=45; y2+=15)
for (var x2=-75; x2<=75; x2+=15)
num_rock += this.mat_mask[GetMaterial(x+x2,y+y2)+1];
// need 15pts on first check; 5 to sustain
if (num_rock < 15-is_current*10) return nil;
return this;
}
private func EnvCheck_Snow(object cursor, int x, int y, bool is_current)
{
// Must be snowing from above
if (GetPXSCount(this.mat, x-300, y-200, 600, 300) < 20 - is_current*15) return nil;
return this;
}
private func EnvCheck_Night(object cursor, int x, int y, bool is_current)
{
// Night time.
if (!Time->IsNight()) return nil;
return this;
}
private func EnvCheck_Overground(object cursor, int x, int y, bool is_current)
{
// This is the fallback environment
return this;
}
/*-- Proplist --*/
local Name = "$Name$";
local Description = "$Description$";
local Environment;

View File

@ -1,2 +0,0 @@
Name=Ambiente
Description=Regelt die Geraeuschkulisse.

View File

@ -1,3 +0,0 @@
Name=Ambience
Description=Controls environmental sounds and music.

View File

@ -1,13 +0,0 @@
[DefCore]
id=Fireglobe
Category=C4D_Object
Width=10
Height=10
Offset=-5,-5
Vertices=1
VertexY=0
VertexFriction=100
Picture=0,0,60,60
Value=8
Mass=1
Rotate=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -1,7 +0,0 @@
[DefCore]
id=VisualPath
Version=8,0
Category=C4D_StaticBack
Width=1
Height=1
Picture=0,0,1,1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 851 B

View File

@ -1,46 +0,0 @@
public func Set(int sx, int sy, int ex, int ey) {
//SetObjectBlitMode(GFX_BLIT_Additive);
SetAction("Vis");
SetPosition(sx,sy);
SetClrModulation(RGB(255,0,0));
var cl = 1000*Distance(sx,sy,ex,ey)/256;
var w = 650;
var r = Angle(sx,sy,ex,ey)-180;
var fsin = -Sin(r, 1000), fcos = Cos(r, 1000);
var xoff = -4;
var yoff = 0;
var width = +fcos*w/1000, height = +fcos*cl/1000;
var xskew = +fsin*cl/1000, yskew = -fsin*w/1000;
var xadjust = +fcos*xoff + fsin*yoff;
var yadjust = -fsin*xoff + fcos*yoff;
// set matrix values
SetObjDrawTransform (
width, xskew, xadjust,
yskew, height, yadjust
);
}
local ActMap = {
Vis = {
Prototype = Action,
Name = "Vis",
Procedure = DFA_FLOAT,
Length = 1,
X = 0,
Y = 0,
Wdt = 32,
Hgt = 256,
OffX = -16,
OffY = 0,
NextAction = "Hold"
},
};
local Name = "Path";

View File

@ -1,206 +0,0 @@
/*
FireGlobe
Author: Newton
*/
local sx,sy,ex,ey;
local vis;
local aimed;
func Construction()
{
vis = nil;
aimed = false;
}
func ControlUse(object clonk, int x, int y)
{
if(!aimed) return false;
// fire fireball
var angle = Angle(0,0,x,y);
Exit();
Launch(angle,120,clonk);
SetDivert(sx,sy,ex,ey);
return true;
}
func ControlUseStart(object clonk, int x, int y)
{
if(aimed) return false;
sx = x+clonk->GetX();
sy = y+clonk->GetY();
if(vis) vis->RemoveObject();
vis = CreateObjectAbove(VisualPath,0,0,clonk->GetOwner());
vis->Set(sx,sy,x+clonk->GetX(),y+clonk->GetY());
vis["Visibility"]=VIS_Owner;
return true;
}
func HoldingEnabled() { return true; }
func ControlUseHolding(object clonk, int x, int y)
{
if(aimed) return false;
if(vis) vis->Set(sx,sy,x+clonk->GetX(),y+clonk->GetY());
}
func ControlUseStop(object clonk, int x, int y)
{
if(aimed) return false;
ex = x+clonk->GetX();
ey = y+clonk->GetY();
vis->Set(sx,sy,ex,ey);
aimed=true;
return true;
}
public func DelLine()
{
if(vis) vis->RemoveObject();
}
public func Deselection()
{
DelLine();
}
public func Destruction()
{
DelLine();
}
public func Launch(int angle, int str, object shooter)
{
var xdir = Sin(angle,str);
var ydir = Cos(angle,-str);
SetXDir(xdir);
SetYDir(ydir);
AddEffect("HitCheck", this, 1,1, nil,nil, shooter);
AddEffect("InFlight", this, 1,1, this);
}
public func SetDivert(int x1, int y1, int x2, int y2)
{
var inflight = GetEffect("InFlight",this);
inflight.ax = x1;
inflight.ay = y1;
inflight.bx = x2;
inflight.by = y2;
inflight.freeflight = true;
}
public func HitObject(object obj)
{
Hit();
}
public func Hit()
{
DelLine();
Explode(20);
}
// rotate arrow according to speed
public func FxInFlightStart(object target, effect, int temp)
{
if(temp) return;
effect.x = target->GetX();
effect.y = target->GetY();
}
public func FxInFlightTimer(object target, effect, int time)
{
var oldx = effect.x;
var oldy = effect.y;
var newx = target->GetX();
var newy = target->GetY();
if(effect.freeflight)
{
var ax = effect.ax;
var ay = effect.ay;
var bx = effect.bx;
var by = effect.by;
var pos = Intersect(oldx, oldy, newx, newy, ax, ay, bx, by);
if (pos != nil)
{
var angle = Angle(ax, ay, bx, by);
var speed = 60;
target->SetXDir(Sin(angle,speed));
target->SetYDir(-Cos(angle, speed));
effect.freeflight = false;
}
}
effect.x = newx;
effect.y = newy;
}
// Returns nil or coordinates of intersection.
global func Intersect(int Ax, int Ay, int Bx, int By, int Px, int Py, int Qx, int Qy)
{
var BAx = Bx-Ax;
var BAy = By-Ay;
var PAx = Px-Ax;
var PAy = Py-Ay;
var QPx = Qx-Px;
var QPy = Qy-Py;
var denominator = (BAy*QPx - BAx*QPy);
var numerator = (BAx*PAy - BAy*PAx);
// parallel!
if(denominator == 0)
{
if(numerator != 0) return nil;
// on same line somewhere
else
{
return [Ax, Ay];
}
}
// in parameter bounds?
var Y = 10000 * numerator/denominator;
if(!Inside(Y,0,10000)) return nil;
// we don't want division by zero...
if(BAy != 0) {
numerator = (PAy + Y*QPy/10000);
denominator = BAy;
}
else if(BAx != 0) {
numerator = (PAx + Y*QPx/10000);
denominator = BAx;
}
// in parameter bounds
var X = 10000*numerator / denominator;
if(!Inside(X,0,10000)) return nil;
// this is the point...
var x = Ax+X*(BAx)/10000;
var y = Ay+X*(BAy)/10000;
return [x, y];
}
local Name = "$Name$";
local Collectible = 1;

View File

@ -1 +0,0 @@
Name=Feuerglob

View File

@ -1 +0,0 @@
Name=Fire globe

View File

@ -1,55 +0,0 @@
material _missing_material_
{
receive_shadows off
technique
{
pass
{
ambient 0.1 0.1 0.1 1.0
diffuse 0.8 0.0 0.0 1.0
specular 0.5 0.5 0.5 1.0 12.5
emissive 0.3 0.3 0.3 1.0
}
}
}
// blender material: flightless_bird_material
material flightless_bird_material
{
receive_shadows on
technique
{
pass flightless_bird_material
{
ambient 0.800000011920929 0.800000011920929 0.800000011920929 0.0
diffuse 0.800000011920929 0.800000011920929 0.800000011920929 0.0
specular 0.0 0.0 0.0 0.0 12.5
emissive 0.0 0.0 0.0 0.0
alpha_to_coverage off
colour_write on
cull_hardware clockwise
depth_check on
depth_func less_equal
depth_write on
illumination_stage
light_clip_planes off
light_scissor off
lighting on
normalise_normals off
polygon_mode solid
scene_blend one zero
scene_blend_op add
shading gouraud
transparent_sorting on
texture_unit
{
texture color.png
tex_address_mode wrap
scale 1.0 1.0
colour_op alpha_blend
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 KiB

View File

@ -1,17 +0,0 @@
Information for developers:
This folder should contain all experimental objects which may be used
throughout different scenario's. This aids object designers, cause they
may then combine new and old objects more easily, not having to move
objects around from scenario to scenario. Please abide this rule if you
plan to put experimental objects into the repository. Note that scenario
specific objects may still be located in their respective scenario,
however, be sure that there will not be any reason to use them elsewhere.
Another decent thing to check before committing, are C4Script warnings
and errors. Also try to keep runtime errors at a minimum. This to prevent
other developers from having to fix objects they don't know the details
of, in order to develop their own objects.
Finished objects may be moved to Objects.ocd, though make sure beforehand
that these objects do not break anything. Also they shouldn't cause any
C4Script warnings or errors, or runtime errors.

View File

@ -1,14 +0,0 @@
[DefCore]
id=LiftTower
Version=8,0
Category=C4D_Structure
Width=23
Height=68
Offset=-11,-10
Vertices=4
VertexX=-11,11,-11,11
VertexY=-10,-10,58,58
VertexFriction=50,50,100,100
Mass=4500
Exclusive=1
Construction=1

View File

@ -1,13 +0,0 @@
[DefCore]
id=LiftTower_Hook
Version=8,0
Category=C4D_Object
Width=8
Height=8
Offset=-4,-4
Vertices=3
VertexX=0,2,-2
VertexY=1,-1,-1
VertexFriction=50,50,50
Mass=4
Rotate=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 511 B

View File

@ -1,140 +0,0 @@
/*-- Hook --*/
local tower, rope;
/* Connection */
public func ControlUse(object clonk, int x, int y)
{
// Search for objects to connect with!
var connect = FindObjects(Find_Category(C4D_Vehicle), Find_AtPoint(), Find_Not(Find_Func("NoLiftTowerConnection")), Find_Not(Find_Func("IsEnvironment")));
if (!GetLength(connect)) return true;
if (GetLength(connect) == 1) return ConnectTo(connect[0]);
var menu = clonk->CreateRingMenu(GetID(), this);
for (var connect_object in connect)
menu->AddItem(connect_object);
menu->Show();
}
public func Selected(object menu, object selected)
{
return ConnectTo(selected->GetSymbol());
}
public func ConnectTo(object connect)
{
Hook();
/* rope->BreakRope(true);
SetRope(true);
rope->Connect(tower, connect);*/
rope->Reconnect(connect);
AddEffect("Connecting", this, 1, 1, this, nil, connect);
return true;
}
private func Hook()
{
if (Contained()) Exit();
this.Collectible = 0;
SetCategory(C4D_StaticBack);
}
private func Unhook()
{
this.Collectible = 1;
SetCategory(C4D_Object);
}
private func FxConnectingStart(object target, effect, int temp, object connect_object)
{
if (temp) return;
effect.connection = connect_object;
}
private func FxConnectingTimer(object target, effect)
{
if (!rope)
{
Unhook();
return -1;
}
if (!effect.connection)
{
Unhook();
rope->BreakRope(true);
SetRope();
return -1;
}
SetPosition(effect.connection->GetX(), effect.connection->GetY());
}
public func Connected()
{
return GetEffect("Connecting", this);
}
public func IsInteractable(object clonk)
{
return !this.Collectible && clonk->GetAction() == "Walk";
}
public func GetInteractionMetaInfo(object clonk)
{
return { IconID = LiftTower_Hook, Description = "$Unhook$" };
}
public func Interact(object clonk)
{
if(clonk->Collect(this))
{
RemoveEffect("Connecting", this);
Unhook();
rope->BreakRope(true);
SetRope();
return true;
}
return false;
}
/* Events */
protected func Hit()
{
Sound("Hits::Materials::Metal::LightMetalHit?");
}
func Construction(object constructor)
{
tower = constructor;
}
func Initialize()
{
AddTimer("Rotation", 2);
}
func SetRope(bool no_connect)
{
rope = CreateObjectAbove(LiftTower_Rope,0,0,NO_OWNER);
if (!no_connect) rope->Connect(tower, this);
tower->SetRope(rope);
return rope;
}
public func Destruction()
{
if(rope)
rope->HookRemoved();
}
protected func Rotation()
{
if (!rope) return;
SetR(rope->GetHookAngle());
}
public func NoLiftTowerConnection() { return true; }
local Name = "$Name$";
local Description = "$Description$";
local Collectible = 1;

View File

@ -1,3 +0,0 @@
Name=Haken
Description=Drücke [Benutzen] vor einem Fahrzeug oder einem anderen großen Gegenstand, um den Haken zu befestigen.
Unhook=Haken abnehmen.

View File

@ -1,3 +0,0 @@
Name=Hook
Description=Press [Use] in front of a vehicle or another big object to attach the hook.
Unhook=Unhook object.

View File

@ -1,8 +0,0 @@
[DefCore]
id=LiftTower_Rope
Version=8,0
Category=C4D_StaticBack
Vertices=2
Width=2
Height=12
Offset=-1,-6

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -1,255 +0,0 @@
/*
Lift Tower Rope
Author: Randrian, Clonkonaut
The rope used for the lift tower.
Connect(obj1, obj2) connects two objects
BreakRope() breaks the rope
*/
#include Library_Rope
static const Library_Rope_MAXLENGTH = 1000;
// Call this to break the rope.
public func BreakRope(bool silent)
{
if(lib_rope_length == -1) return;
lib_rope_length = -1;
var act1 = lib_rope_objects[0][0];
var act2 = lib_rope_objects[1][0];
SetAction("Idle");
// notify action targets.
if (act1 != nil && !silent)
act1->~OnRopeBreak();
if (act2 != nil && !silent)
act2->~OnRopeBreak();
RemoveRope();
RemoveObject();
return;
}
/* --------------------- Callbacks form the rope ---------------------- */
/* To be overloaded for special segment behaviour */
private func CreateSegment(int index, object previous)
{
if(index == 0) return;
var segment;
segment = CreateObjectAbove(LiftTower_Rope);
return segment;
}
/*-- Rope connecting --*/
// Connects two objects to the rope, but the length will vary on their positions.
public func Connect(object obj1, object obj2, int max_length)
{
StartRopeConnect(obj1, obj2);
if (!max_length) max_length = Library_Rope_MAXLENGTH;
SetMaxLength(max_length);
SetFixed(true, false);
SetAction("Hide");
AddEffect("IntHang", this, 1, 1, this);
return;
}
public func Reconnect(object reconnect)
{
lib_rope_objects[1][0] = reconnect;
}
public func GetConnectStatus() { return !lib_rope_length_auto; }
public func HookRemoved()
{
BreakRope();
}
func FxIntHangTimer() { TimeStep(); }
func UpdateLines()
{
var oldangle;
for(var i=1; i < lib_rope_particle_count; i++)
{
// Update the Position of the Segment
lib_rope_segments[i]->SetPosition(GetPartX(i), GetPartY(i));
// Calculate the angle to the previous segment
var angle = Angle(lib_rope_particles[i].x, lib_rope_particles[i].y, lib_rope_particles[i-1].x, lib_rope_particles[i-1].y);
// Draw the left line
var start = [lib_rope_particles[i-1].x, lib_rope_particles[i-1].y];
var end = [lib_rope_particles[i].x, lib_rope_particles[i].y];
if(i == 1 && lib_rope_particle_count > 2)
{
angle = Angle(lib_rope_particles[2].x, lib_rope_particles[2].y, lib_rope_particles[0].x, lib_rope_particles[0].y);
end = [lib_rope_particles[0].x, lib_rope_particles[0].y];
end[0] += -Sin(angle, 45*LIB_ROPE_Precision/10);
end[1] += +Cos(angle, 45*LIB_ROPE_Precision/10);
lib_rope_segments[i]->SetGraphics("Invis");
}
if(i == 2)
{
angle = Angle(lib_rope_particles[2].x, lib_rope_particles[2].y, lib_rope_particles[0].x, lib_rope_particles[0].y);
start = [lib_rope_particles[0].x, lib_rope_particles[0].y];
start[0] += -Sin(angle, 45*LIB_ROPE_Precision/10);
start[1] += +Cos(angle, 45*LIB_ROPE_Precision/10);
lib_rope_segments[i]->SetGraphics("Short");
}
var diff = Vec_Sub(end,start);
var point = Vec_Add(start, Vec_Div(diff, 2));
var diffangle = Vec_Angle(diff, [0,0]);
var length = Vec_Length(diff)*1000/LIB_ROPE_Precision/10;
if(i == lib_rope_particle_count-1)
{
var old = [lib_rope_particles[i-2].x, lib_rope_particles[i-2].y];
var old_diff = Vec_Sub(start,old);
var o_length = Vec_Length(old_diff)*1000/LIB_ROPE_Precision/10;
if(!o_length) diff = old_diff;
else diff = Vec_Div(Vec_Mul(old_diff, length),o_length);
diffangle = Vec_Angle(diff, [0,0]);
point = Vec_Add(start, Vec_Div(diff, 2));
}
lib_rope_segments[i]->SetGraphics(nil);
SetLineTransform(lib_rope_segments[i], -diffangle, point[0]*10-GetPartX(i)*1000,point[1]*10-GetPartY(i)*1000, length );
// Remember the angle
oldangle = angle;
}
}
public func GetHookAngle()
{
if(lib_rope_particle_count > 3)
return Angle(lib_rope_particles[-2].x, lib_rope_particles[-2].y, lib_rope_particles[-3].x, lib_rope_particles[-3].y)+180;
}
public func SetLineTransform(obj, int r, int xoff, int yoff, int length, int layer, int MirrorSegments) {
if(!MirrorSegments) MirrorSegments = 1;
var fsin=Sin(r, 1000), fcos=Cos(r, 1000);
// set matrix values
obj->SetObjDrawTransform (
+fcos*MirrorSegments, +fsin*length/1000, xoff,
-fsin*MirrorSegments, +fcos*length/1000, yoff,layer
);
}
/* Overload */
local pull_position, pull_faults, pull_frame;
// Altered to not just pull the objects into the rope's direction but
// if the object doesn't not move it is tried to shake it free by applying
// impulses to every direction
func ForcesOnObjects()
{
if(!lib_rope_length) return;
var redo = LengthAutoTryCount();
while(lib_rope_length_auto && redo)
{
var speed = Vec_Length(Vec_Sub([lib_rope_particles[-1].x, lib_rope_particles[-1].y], [lib_rope_particles[-1].oldx, lib_rope_particles[-1].oldy]));
if(lib_rope_length == GetMaxLength())
{
if(ObjContact(lib_rope_objects[1][0]))
speed = 40;
else speed = 100;
}
if(speed > 150) DoLength(1);
else if(speed < 50) DoLength(-1);
else redo = 0;
if(redo) redo --;
}
var j = 0;
if (PullObjects())
for (var i = 0; i < 2; i++)
{
if (i == 1) j = lib_rope_particle_count-1;
var obj = lib_rope_objects[i][0];
if (obj == nil || !lib_rope_objects[i][1]) continue;
if (obj->Contained())
obj = obj->Contained();
if (obj->GetAction() == "Walk" || obj->GetAction() == "Scale" || obj->GetAction() == "Hangle" || obj->GetAction() == "Climb")
obj->SetAction("Jump");
var xdir = BoundBy(lib_rope_particles[j].x-lib_rope_particles[j].oldx, -100, 100);
var ydir = lib_rope_particles[j].y-lib_rope_particles[j].oldy;
if (!obj->GetContact(-1))
ydir = BoundBy(ydir, -120, 120);
if (pull_position && pull_frame != FrameCounter() && !Distance(pull_position[0], pull_position[1], obj->GetX(), obj->GetY()))
{
if (!pull_faults)
{
ydir *= -1;
pull_faults++;
}
else
{
xdir *= -1;
pull_faults = 0;
}
}
else
{
pull_position = [obj->GetX(), obj->GetY()];
pull_faults = 0;
}
pull_frame = FrameCounter();
obj->SetXDir( xdir, LIB_ROPE_Precision);
obj->SetYDir( obj->GetYDir(LIB_ROPE_Precision) + ydir, LIB_ROPE_Precision);
}
}
// Altered to function in 'ConnectPull' mode
public func ConstraintObjects()
{
if(lib_rope_length < GetMaxLength()) // in the rope library this is
{
for (var i = 0, i2 = 0; i < 2; i++ || i2--)
SetParticleToObject(i2, i);
}
}
// This is called constantly by the lift tower as long as something is reeled in
// Altered so the rope will not get shorter than the distance between the tower
// and the hooked up object
public func DoLength(int dolength)
{
var obj = lib_rope_objects[0][0]; // First connected object
var obj2 = lib_rope_objects[1][0]; // Second connected object
// I guess this is not possible but just to be sure
if (!obj || !obj2) return _inherited(dolength);
if (obj->Contained()) obj = obj->Contained();
if (obj2->Contained()) obj2 = obj2->Contained();
// Line would be shorter than the distance? Do nothing
if (dolength < 0 && ObjectDistance(obj, obj2) > GetLineLength()/100) return;
return _inherited(dolength);
}
func Definition(def)
{
def.LineColors = [RGB(66,33,00), RGB(66,33,00)];
}
local ActMap = {
Hide = {
Prototype = Action,
Name = "Hide",
},
};
local Name = "$Name$";

View File

@ -1,14 +0,0 @@
material Material
{
receive_shadows on
technique
{
pass
{
ambient 0.500000 0.500000 0.500000 1.000000
diffuse 0.584337 0.584337 0.584337 1.000000
specular 0.500000 0.500000 0.500000 1.000000 12.500000
emissive 0.000000 0.000000 0.000000 1.000000
}
}
}

View File

@ -1,171 +0,0 @@
/*--
LiftTower
Authors: Clonkonaut
--*/
local hook, rope;
local hook_pos, anim_no, stopped, direction;
static const LIFTTOWER_HOOK_LOOSEDIST = 50;
public func Construction()
{
SetProperty("MeshTransformation",Trans_Rotate(RandomX(-20,20),0,1,0));
return _inherited(...);
}
protected func Initialize()
{
OnRopeBreak();
hook_pos = CreateArray();
anim_no = PlayAnimation("Turn", 10, Anim_Const(0));
stopped = true;
AddEffect("SpinWheel", this, 0, 5);
}
/* Rope */
func OnRopeBreak()
{
if (!hook)
hook = CreateObjectAbove(LiftTower_Hook, 0,0, NO_OWNER);
hook->Enter(this);
}
/* Interaction */
func IsInteractable(object clonk)
{
return GetCon() >= 100;
}
func GetInteractionMetaInfo()
{
if (!hook) OnRopeBreak();
if (hook->Contained() == this)
return { IconID = LiftTower_Hook, Description = "$TakeHook$" };
else
return { IconID = LiftTower_Hook, Description = "$Grab$" };
}
func Interact(object clonk)
{
if (!hook) OnRopeBreak();
if (hook->Contained() == this)
{
if (clonk->Collect(hook,nil,nil,true))
hook->SetRope();
}
else
{
clonk->ObjectCommand("Grab", this);
}
return true;
}
func SetRope(object rope_to_set)
{
rope = rope_to_set;
}
/* Control */
public func ControlUp(object clonk)
{
return DrawIn();
}
public func ControlStop(object clonk)
{
return RemoveEffect("DrawIn", this);
}
public func DrawIn()
{
if (!rope) return false;
if (!hook) OnRopeBreak();
if (hook->Contained() == this) return false;
if (ObjectDistance(hook) < LIFTTOWER_HOOK_LOOSEDIST) return false;
if (GetEffect("DrawIn", this)) return false;
rope->ConnectPull();
return AddEffect("DrawIn", this, 1, 1, this);
}
private func FxDrawInTimer(effect)
{
if (!rope) return -1;
if (!hook)
{
OnRopeBreak();
return -1;
}
rope->DoLength(-1);
if (ObjectDistance(hook) < LIFTTOWER_HOOK_LOOSEDIST) return -1;
}
private func FxDrawInStop(object target, effect, int temp)
{
if (temp) return;
if (!rope) return;
rope->ConnectLoose();
}
/* Animation */
protected func FxSpinWheelTimer()
{
if (!hook) return StopWheel();
if (hook->Contained() == this) return StopWheel();
if (hook->GetX() == hook_pos[0])
if (hook->GetY() == hook_pos[1])
return StopWheel();
stopped = false;
var new_direction = false;
if (!direction)
{
direction = 100;
new_direction = true;
}
if (Distance(GetX(),GetY(), hook->GetX(), hook->GetY()) < Distance(GetX(),GetY(), hook_pos[0], hook_pos[1]))
{
if (direction > 0)
{
direction = -100;
new_direction = true;
}
}
else if (direction < 0)
{
direction = 100;
new_direction = true;
}
hook_pos = [hook->GetX(), hook->GetY()];
if (!new_direction) return;
if (direction < 0)
anim_no = PlayAnimation("Turn", 10, Anim_Linear(GetAnimationPosition(anim_no), GetAnimationLength("Turn"), 0, 40, ANIM_Loop));
else
anim_no = PlayAnimation("Turn", 10, Anim_Linear(GetAnimationPosition(anim_no), 0, GetAnimationLength("Turn"), 40, ANIM_Loop));
}
private func StopWheel()
{
if (stopped) return;
var position = GetAnimationPosition(anim_no);
stopped = true;
direction = 0;
anim_no = PlayAnimation("Turn", 10, Anim_Const(position), Anim_Const(1000));
}
func Definition(def) {
SetProperty("PictureTransformation", Trans_Mul(Trans_Translate(2000,0,7000),Trans_Rotate(-20,1,0,0),Trans_Rotate(30,0,1,0)), def);
}
local Name = "$Name$";
local Description = "$Description$";
local Touchable = 2;
local ContainBlast = true;
local BlastIncinerate = 100;

View File

@ -1,4 +0,0 @@
Name=Hebeturm
Description=Um schwere Lasten zu heben.
TakeHook=Haken nehmen.
Grab=Anfassen

View File

@ -1,4 +0,0 @@
Name=Lift Tower
Description=For pulling heavy loads.
TakeHook=Take the hook.
Grab=Grab

View File

@ -1,14 +0,0 @@
[DefCore]
id=LiquidTank
Version=8,0
Category=C4D_Structure
Width=40
Height=72
Offset=-20,-36
Vertices=6
VertexX=-16,16,-18,18,-18,18
VertexY=35,35,0,0,-20,-20
VertexFriction=100,100,50,50,50,50
Mass=800
Exclusive=1
Construction=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,174 +0,0 @@
/**
Liquid Tank
Holds liquids of any type and can be opened to create a flood.
@author Maikel
*/
#include Library_Structure
#include Library_Ownable
#include Library_Tank
public func Initialize()
{
return _inherited(...);
}
public func Construction(object creator)
{
return _inherited(creator, ...);
}
public func IsHammerBuildable() { return true; }
/*-- Liquid Control --*/
// Only accept a single liquid at the same time, but accept any liquid type.
public func IsLiquidContainerForMaterial(string liquid)
{
for (var liquid_content in GetLiquidContents())
if (GetLiquidDef(liquid) != GetLiquidDef(liquid_content->GetID()))
return false;
return true;
}
public func GetLiquidContainerMaxFillLevel(liquid_name)
{
return this.LiquidCapacity;
}
// The liquid tank may have one drain and one source.
public func QueryConnectPipe(object pipe, bool do_msg)
{
if (GetDrainPipe() && GetSourcePipe())
{
if (do_msg) pipe->Report("$MsgHasPipes$");
return true;
}
else if (GetSourcePipe() && pipe->IsSourcePipe())
{
if (do_msg) pipe->Report("$MsgSourcePipeProhibited$");
return true;
}
else if (GetDrainPipe() && pipe->IsDrainPipe())
{
if (do_msg) pipe->Report("$MsgDrainPipeProhibited$");
return true;
}
else if (pipe->IsAirPipe())
{
if (do_msg) pipe->Report("$MsgPipeProhibited$");
return true;
}
return false;
}
// Set to source or drain pipe.
public func OnPipeConnect(object pipe, string specific_pipe_state)
{
if (PIPE_STATE_Source == specific_pipe_state)
{
SetSourcePipe(pipe);
pipe->SetSourcePipe();
}
else if (PIPE_STATE_Drain == specific_pipe_state)
{
SetDrainPipe(pipe);
pipe->SetDrainPipe();
}
else
{
if (!GetDrainPipe())
OnPipeConnect(pipe, PIPE_STATE_Drain);
else if (!GetSourcePipe())
OnPipeConnect(pipe, PIPE_STATE_Source);
}
pipe->Report("$MsgConnectedPipe$");
}
/*-- Interaction --*/
public func IsInteractable(object clonk)
{
if (GetCon() < 100)
return false;
return !Hostile(GetOwner(), clonk->GetOwner());
}
public func GetInteractionMetaInfo(object clonk)
{
if (GetEffect("FxDisperseLiquid", this))
return { Description = "$MsgCloseTank$", IconName = nil, IconID = Icon_Enter, Selected = false };
return { Description = "$MsgOpenTank$", IconName = nil, IconID = Icon_Exit, Selected = false };
}
public func Interact(object clonk)
{
var fx = GetEffect("FxDisperseLiquid", this);
if (fx)
{
fx->Remove();
return true;
}
CreateEffect(FxDisperseLiquid, 100, 2);
return true;
}
local FxDisperseLiquid = new Effect
{
Construction = func()
{
this.Interval = 2;
return FX_OK;
},
Timer = func()
{
var liquid = Target->Contents();
if (!liquid || !liquid->~IsLiquid())
return FX_OK;
if (liquid->GetLiquidAmount() <= Target.DispersionRate)
{
liquid->Exit();
liquid->SetPosition(Target->GetX(), Target->GetY());
liquid->Disperse(180, 40);
}
else
{
liquid->RemoveLiquid(nil, Target.DispersionRate);
liquid = liquid->GetID()->CreateLiquid(Target.DispersionRate);
liquid->SetPosition(Target->GetX(), Target->GetY());
liquid->Disperse(180, 40);
}
// TODO: Sound.
return FX_OK;
}
};
/*-- Contents Control --*/
public func IsContainer() { return true; }
protected func RejectCollect(id item, object obj)
{
// Accept liquids only.
if (obj->~IsLiquid())
return _inherited(item, obj, ...);
return true;
}
/*-- Properties --*/
local Name = "$Name$";
local Description ="$Description$";
local BlastIncinerate = 100;
local FireproofContainer = true;
local HitPoints = 90;
local Components = {Wood = 3, Metal = 2};
local LiquidCapacity = 10000;
local DispersionRate = 40;

View File

@ -1,11 +0,0 @@
Name=Tank
Description=Hier können Flüssigkeiten gespeichert werden, aber nur eine Art gleichzeitig.
MsgConnectedPipe=Rohr angeschlossen.
MsgPipeProhibited=Dieses Rohr kann nicht an den Tank angeschlossen werden.
MsgHasPipes=Der Tank hat schon ein Zu- und Abflussrohr.
MsgSourcePipeProhibited=Zuflussrohre können nicht an den Tank angeschlossen werden.
MsgDrainPipeProhibited=Abflussrohre können nicht an den Tank angeschlossen werden.
MsgOpenTank=Ventil öffnen
MsgCloseTank=Ventil schließen

View File

@ -1,11 +0,0 @@
Name=Liquid Tank
Description=Liquids can be stored here, but only one type of liquid at the same time.
MsgConnectedPipe=Connected pipe.
MsgPipeProhibited=This pipe cannot be connected to the liquid tank.
MsgHasPipes=Liquid tank already has a source and a drain pipe.
MsgSourcePipeProhibited=Unable to connect source pipe to the liquid tank.
MsgDrainPipeProhibited=Unable to connect drain pipe to the liquid tank.
MsgOpenTank=Open valve
MsgCloseTank=Close valve

View File

@ -1,6 +0,0 @@
[DefCore]
id=CableLine
Version=8,0
Category=C4D_StaticBack
Vertices=2
Line=1

View File

@ -1,106 +0,0 @@
/*-- Cable line --*/
func Initialize()
{
SetAction("Connect");
SetVertexXY(0, GetX(), GetY());
SetVertexXY(1, GetX(), GetY());
SetProperty("LineColors", [RGB(20, 20, 50), RGB(20, 20, 50)]);
}
public func IsCableLine() { return GetAction() == "Connect"; }
/** Returns whether this cable is connected to an object. */
public func IsConnectedTo(object obj)
{
return GetActionTarget(0) == obj || GetActionTarget(1) == obj;
}
/** Connects this cable to obj1 and obj2. */
public func SetConnectedObjects(obj1, obj2)
{
if (GetActionTarget(0)) GetActionTarget(0)->~CableDeactivation(activations);
if (GetActionTarget(1)) GetActionTarget(1)->~CableDeactivation(activations);
SetVertexXY(0, obj1->GetX(), obj1->GetY());
SetVertexXY(1, obj2->GetX(), obj2->GetY());
SetActionTargets(obj1, obj2);
obj1->AddCableConnection(this);
}
/** Returns the object which is connected to obj through this cable. */
public func GetConnectedObject(object obj)
{
if (GetActionTarget(0) == obj)
return GetActionTarget(1);
if (GetActionTarget(1) == obj)
return GetActionTarget(0);
}
/* Breaking */
func LineBreak(bool no_msg)
{
Sound("Objects::Connect");
if (GetActionTarget(0)) GetActionTarget(0)->~CableDeactivation(activations);
if (GetActionTarget(1)) GetActionTarget(1)->~CableDeactivation(activations);
if (!no_msg)
BreakMessage();
}
func BreakMessage()
{
var line_end = GetActionTarget(0);
if (line_end->GetID() != CableLorryReel)
line_end = GetActionTarget(1);
if (line_end->Contained()) line_end = line_end->Contained();
line_end->Message("$TxtLinebroke$");
}
/* Activation */
local activations = 0;
/** Called by cable cars whenever one proceeds onto this cable. Will be forwarded to connected objects.
count increases the activation value. Stations will stop animation only if all activations are deactivated. */
public func Activation(int count)
{
// Count must be > 0
if (count < 1) return FatalError("Cable Line: Activation() was called with count < 1.");
activations += count;
if (GetActionTarget(0)) GetActionTarget(0)->~CableActivation(count);
if (GetActionTarget(1)) GetActionTarget(1)->~CableActivation(count);
}
/** Called by cable cars whenever one proceeds off this cable. Will be forwarded to connected objects.
count decreases the activation value. Stations will stop animation only if all activations are deactivated. */
public func Deactivation(int count)
{
// Count must be > 0
if (count < 1) return FatalError("Cable Line: Deactivation() was called with count < 1.");
activations -= count;
if (GetActionTarget(0)) GetActionTarget(0)->~CableDeactivation(count);
if (GetActionTarget(1)) GetActionTarget(1)->~CableDeactivation(count);
}
/* Saving */
public func SaveScenarioObject(props)
{
if (!inherited(props, ...)) return false;
SaveScenarioObjectAction(props);
if (IsCableLine()) props->AddCall("Connection", this, "SetConnectedObjects", GetActionTarget(0), GetActionTarget(1));
return true;
}
local ActMap = {
Connect = {
Prototype = Action,
Name = "Connect",
Procedure = DFA_CONNECT,
NextAction = "Connect"
}
};
local Name = "$Name$";

View File

@ -1,2 +0,0 @@
TxtLinebroke=Seil gerissen
Name=Seilbahnseil

View File

@ -1,14 +0,0 @@
[DefCore]
id=CableLorryReel
Version=8,0
Category=C4D_Object
Width=8
Height=6
Offset=-4,-3
Vertices=3
VertexX=0,2,-2
VertexY=1,-1,-1
VertexFriction=50,50,50
Value=10
Mass=15
Picture=0,6,64,64

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -1,68 +0,0 @@
/*-- Cable reel --*/
protected func Hit()
{
Sound("Hits::Materials::Rock::RockHit?");
}
public func IsToolProduct() { return true; }
/*-- Line connection --*/
protected func ControlUse(object clonk, int x, int y)
{
// Is there an object which accepts power lines?
var obj = FindObject(Find_AtPoint(), Find_Func("IsCableCrossing"));
// No such object -> message.
if (!obj)
return clonk->Message("$TxtNoNewLine$");
// Is there a cable connected to this wire roll?
var line = FindObject(Find_CableLine());
// There already is a cable
if (line)
{
if (obj == line->GetActionTarget(0) || obj == line->GetActionTarget(1))
{
// Cable is already connected to obj -> remove line.
line->RemoveObject();
Sound("Objects::Connect");
clonk->Message("$TxtLineRemoval$");
return true;
}
else
{
// Connect existing power line to obj.
if(line->GetActionTarget(0) == this)
line->SetActionTargets(obj, line->GetActionTarget(1));
else if(line->GetActionTarget(1) == this)
line->SetActionTargets(line->GetActionTarget(0), obj);
else
return;
Sound("Objects::Connect");
obj->AddCableConnection(line);
clonk->Message("$TxtConnect$", obj->GetName());
//RemoveObject();
return true;
}
}
else // A new cable needs to be created.
{
line = CreateObjectAbove(CableLine, 0, 0, NO_OWNER);
line->SetActionTargets(this, obj);
Sound("Objects::Connect");
clonk->Message("$TxtConnect$", obj->GetName());
return true;
}
}
// Finds all power lines connected to obj (can be nil in local calls).
private func Find_CableLine(object obj)
{
if (!obj)
obj = this;
return [C4FO_Func, "IsConnectedTo", obj];
}
local Name = "$Name$";
local Description = "$Description$";
local Collectible = 1;

View File

@ -1,6 +0,0 @@
TxtConnectLine=Leitung verbinden
TxtNoNewLine=Hier kann keine neue Leitung verlegt werden.
TxtLineRemoval=Stromleitung abgenommen.
TxtConnect=Stromleitung verbunden|mit %s
Name=Kabelspule
Description=Drücke [Benutzen] vor einem Gebäude und ein weiteres Mal vor einem anderen Gebäude, um diese beiden mit einem Stromkabel zu verbinden.

View File

@ -1,6 +0,0 @@
TxtConnectLine=Connect line
TxtNoNewLine=Cannot create a new line here.
TxtLineRemoval=Power line disconnected.
TxtConnect=Power line connected|to %s
Name=Cable reel
Description=Press [Use] in front of a structure and another time in front of another structure to connect both with a power line.

View File

@ -1,4 +0,0 @@
[DefCore]
id=Library_CableCar
Version=8,0
Category=C4D_StaticBack

View File

@ -1,4 +0,0 @@
[DefCore]
id=GUI_DestinationSelectionMenu
Version=8,0
Category=C4D_StaticBack | C4D_Environment

View File

@ -1,193 +0,0 @@
/**
DestinationSelectionMenu
Handles the destination selection for cable cars.
@author Clonkonaut
*/
local Name = "$Name$";
local Description = "$Description$";
// used as a static function
public func CreateFor(object cursor, object car, object station)
{
if (!cursor) return;
if (!car) return;
if (!station) return;
var obj = CreateObject(GUI_DestinationSelectionMenu, AbsX(0), AbsY(0), cursor->GetOwner());
obj.Visibility = VIS_Owner;
obj->Init(cursor, car, station);
cursor->SetMenu(obj);
return obj;
}
// The Clonk whom the menu was opened for
local cursor;
// The menu id of the opened menu
local menu_id;
// The cable car which opened this menu
local cable_car;
// The station the cable car is hooked up to
local cable_station;
// A dummy object used to bring light to stations when previewed
local dummy;
public func Close() { return RemoveObject(); }
public func IsDestinationMenu() { return true; }
public func Show() { this.Visibility = VIS_Owner; return true; }
public func Hide() { this.Visibility = VIS_None; return true; }
// Called when the menu is open and the player clicks outside.
public func OnMouseClick() { return Close(); }
func Destruction()
{
if (menu_id)
GuiClose(menu_id);
if (dummy)
dummy->RemoveObject();
if (cursor)
SetPlrView(cursor->GetOwner(), cursor, true);
}
public func Init(object cursor, object car, object station)
{
this.cursor = cursor;
this.cable_car = car;
this.cable_station = station;
this.dummy = CreateObject(Dummy, AbsX(station->GetX()), AbsY(station->GetY()), GetOwner());
dummy.Visibility = VIS_Owner;
dummy->SetLightRange(5, 20);
var dest_list = station->GetDestinationList(nil);
var dest_menu = {
Target = this,
Decoration = GUI_MenuDeco,
BackgroundColor = RGB(0, 0, 0),
Bottom = "3em",
Left = "50% - 5em",
Right = "50% + 5em",
Priority = 1,
Player = cursor->GetOwner(),
caption = {
Text = "$SelectDestination$",
Bottom = "1em",
Priority = 2,
},
buttons = {
Top = "1em",
Style = GUI_GridLayout,
Priority = 999
}
};
FillDestinationButtons(dest_menu, dest_list);
GuiOpen(dest_menu);
}
func FillDestinationButtons(proplist menu, array list)
{
var priority = 1000;
// Left button
var left = {
Right = "2em",
Bottom = "2em",
Symbol = Icon_LibraryCableCar,
GraphicsName = "LeftGrey",
BackgroundColor = { Std = RGB(0, 0, 0), Hover = RGB(100, 30, 30) },
Priority = ++priority
};
if (list[3] > 3)
{
left.OnMouseIn = GuiAction_SetTag("Hover");
left.OnMouseOut = GuiAction_SetTag("Std");
left.GraphicsName = "Left";
left.OnClick = GuiAction_Call(this, "ShiftSelection", list[0]);
}
// List buttons
var list_button = {
Right = "2em",
Bottom = "2em",
BackgroundColor = { Std = RGB(0, 0, 0), Hover = RGB(100, 30, 30) },
OnMouseOut = GuiAction_SetTag("Std")
};
var buttons = CreateArray(3);
for (var i = 0; i < 3; i++)
{
if (list[i])
{
buttons[i] = new list_button{
Symbol = list[i],
Tooltip = Format("$SendTo$", list[i]->GetName()),
OnMouseIn = [GuiAction_SetTag("Hover"), GuiAction_Call(this, "PreviewDestination", list[i])],
OnClick = GuiAction_Call(this, "SelectDestination", list[i]),
Priority = ++priority
};
} else {
buttons[i] = new list_button {};
}
}
// Right button
var right = {
Right = "2em",
Bottom = "2em",
Symbol = Icon_LibraryCableCar,
GraphicsName = "Grey",
BackgroundColor = { Std = RGB(0, 0, 0), Hover = RGB(100, 30, 30) },
Priority = ++priority
};
if (list[3] > 3)
{
right.OnMouseIn = GuiAction_SetTag("Hover");
right.OnMouseOut = GuiAction_SetTag("Std");
right.GraphicsName = nil;
right.OnClick = GuiAction_Call(this, "ShiftSelection", list[2]);
}
// Assemble
menu.buttons.left = left;
menu.buttons.first = buttons[0];
menu.buttons.second = buttons[1];
menu.buttons.third = buttons[2];
menu.buttons.right = right;
}
func PreviewDestination(object to_preview, int plr, int menu_id, int submenu_id, object target)
{
if (to_preview == nil) return;
if (dummy == nil)
{
dummy = CreateObject(Dummy, AbsX(to_preview->GetX()), AbsY(to_preview->GetY()), GetOwner());
dummy.Visibility = VIS_Owner;
dummy->SetLightRange(5, 20);
}
SetPlrView(plr, to_preview, true);
dummy->SetPosition(to_preview->GetX(), to_preview->GetY());
}
func ShiftSelection(object new_middle, int plr, int menu_id, int submenu_id, object target)
{
if (!cable_station) return;
if (!menu_id) return;
var update = { buttons = { } };
var list = cable_station->GetDestinationList(new_middle);
FillDestinationButtons(update, list);
GuiUpdate(update, menu_id);
Sound("UI::Click", true, nil, plr);
}
func SelectDestination(object target, int plr, int menu_id, int submenu_id, object target)
{
if (target == nil) return;
if (!cable_car) return;
cable_car->SetDestination(target);
Sound("UI::Click", true, nil, plr);
RemoveObject();
}

View File

@ -1,4 +0,0 @@
Name=Destination Selection Menu
Description=
SelectDestination=Select a destination:
SendTo=Send the cable car to %s

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 B

View File

@ -1,8 +0,0 @@
[DefCore]
id=Icon_LibraryCableCar
Version=8,0
Category=C4D_StaticBack
Picture=0,0,32,32
Width=32
Height=22
Offset=-16,-16

View File

@ -1,392 +0,0 @@
/**
Cable Car
Library object for the cable car.
@author Randrian, Clonkonaut, Maikel
Cable cars must set up a movement speed using SetCableSpeed(x);
Cable cars handle movement on their own. In order to move along a rail, cable cars must call DoMovement() regularly.
E.g. using AddTimer("DoMovement", 1);
*/
// The speed with which the car travels along rails
local lib_ccar_speed;
// The rail (cable or crossing) that is currently traveled along or stayed at
local lib_ccar_rail;
// The direction (0 or 1) the rail is travelled along, translates into the cable's action targets (of which there should be two!)
local lib_ccar_direction;
// The travel progress on the current rail
local lib_ccar_progress;
// The length of the rail
local lib_ccar_max_progress;
// This target point for pathfinding
local lib_ccar_destination;
// Current delivery the car is on, array: [starting station, target station, requested objects, amount]
local lib_ccar_delivery;
/*--- Overloads ---*/
// Overload these functions as you feel fit
// Called after the car is attached to a rail
func Engaged() {}
// Called after the car is detached from the rail
func Disengaged() {}
// To offset the position on the cable from the object's center
// position is a 2-value-array [x,y]
// prec is nil or a value to multiply your calculations with
func GetCableOffset(array position, int prec) {}
// To add custom interaction menu entries after the regular cable car entries
// custom_entry is a prototype for proper spacing of buttons
// Use priorities > 2000 just to be sure
func GetCableCarExtraMenuEntries(array menu_entries, proplist custom_entry, object clonk) {}
// Whenever movement is about to begin
// Movement data like lib_ccar_direction is still nil at this moment
func OnStart() {}
// Whenever the car stops its movement
// failed is true if the movement to a destination was cancelled (usually because the path broke in the meantime)
func OnStop(bool failed) {}
/*--- Interface ---*/
// Sets the speed of the cable car
public func SetCableSpeed(int value)
{
lib_ccar_speed = value;
}
// Positioning of the car along the cable
// This should be called regularly, see header comment!
public func DoMovement()
{
if (!GetRailTarget()) return;
if (lib_ccar_destination == nil) return;
if (lib_ccar_direction == nil) return;
var start = 1;
var end = 0;
if (lib_ccar_direction == 1)
{
start = 0;
end = 1;
}
lib_ccar_progress += lib_ccar_speed;
var position = CreateArray(2);
if (lib_ccar_progress >= lib_ccar_max_progress)
{
lib_ccar_rail->~Deactivation(1);
lib_ccar_rail = lib_ccar_rail->GetActionTarget(end);
lib_ccar_rail->GetCablePosition(position);
GetCableOffset(position);
SetPosition(position[0], position[1]);
lib_ccar_direction = nil;
CrossingReached();
return;
}
var prec = 100;
var origin = CreateArray(2), ending = CreateArray(2);
lib_ccar_rail->GetActionTarget(start)->GetCablePosition(origin, prec);
lib_ccar_rail->GetActionTarget(end)->GetCablePosition(ending, prec);
position[0] = origin[0] + (ending[0] - origin[0]) * lib_ccar_progress/lib_ccar_max_progress;
position[1] = origin[1] + (ending[1] - origin[1]) * lib_ccar_progress/lib_ccar_max_progress;
GetCableOffset(position, prec);
SetPosition(position[0], position[1], 1, prec);
}
/*--- Status ---*/
public func IsCableCar() { return true; }
public func GetRailTarget() { return lib_ccar_rail; }
public func IsTravelling() { return lib_ccar_destination; }
/* Interaction */
// Provides an own interaction menu.
public func HasInteractionMenu() { return true; }
// Show settins in interaction menu
public func GetInteractionMenus(object clonk)
{
var menus = _inherited(clonk, ...) ?? [];
var cablecar_menu =
{
title = "$CableCarOptions$",
entries_callback = this.GetCableCarMenuEntries,
callback = nil,
callback_hover = "OnCableCarHover",
callback_target = this,
BackgroundColor = RGB(0, 0, 50),
Priority = 20
};
PushBack(menus, cablecar_menu);
return menus;
}
public func GetCableCarMenuEntries(object clonk)
{
var control_prototype =
{
BackgroundColor = { Std = 0, Selected = RGB(100, 30, 30) },
OnMouseIn = GuiAction_SetTag("Selected"),
OnMouseOut = GuiAction_SetTag("Std"),
Right = "2em"
};
var custom_entry =
{
Right = "3em", Bottom = "2em",
image = { Prototype = control_prototype },
icon = { Left = "2em" }
};
var menu_entries = [];
// Clickable buttons
if (!GetRailTarget())
{
// Engaging onto a rail
var stations = FindObjects(Find_AtPoint(), Find_Func("IsCableStation"));
var i = 0;
for (var station in stations)
{
var engage = new custom_entry {
Priority = 1000 + i,
Tooltip = "$TooltipEngage$",
OnClick = GuiAction_Call(this, "EngageRail", station),
image = { Prototype = custom_entry.image, Symbol = station },
icon = { Prototype = custom_entry.icon, Symbol = Icon_LibraryCableCar, GraphicsName = "Engage" }
};
PushBack(menu_entries, { symbol = station, extra_data = "Engage", custom = engage });
i++;
}
// No station present
if (i == 0)
{
var search = {
Priority = 1000,
Right = "100%", Bottom = "2em",
text = { Text = "$NoStation$", Style = GUI_TextVCenter | GUI_TextHCenter}
};
PushBack(menu_entries, { symbol = this, extra_data = "NoStation", custom = search });
}
} else {
// Start the trip
if (!IsTravelling())
{
var go = new custom_entry {
Priority = 1000,
Tooltip = "$TooltipGo$",
OnClick = GuiAction_Call(this, "OpenDestinationSelection", clonk),
image = { Prototype = custom_entry.image, Symbol = Icon_Play }
};
PushBack(menu_entries, { symbol = this, extra_data = "Go", custom = go });
var disengage = new custom_entry {
Priority = 1001,
Tooltip = "$TooltipDisengage$",
OnClick = GuiAction_Call(this, "DisengageRail"),
image = { Prototype = custom_entry.image, Symbol = GetRailTarget() },
icon = { Prototype = custom_entry.icon, Symbol = Icon_LibraryCableCar, GraphicsName = "Disengage" }
};
PushBack(menu_entries, { symbol = GetRailTarget(), extra_data = "Disengage", custom = disengage });
}
}
// Add custom entries
GetCableCarExtraMenuEntries(menu_entries, custom_entry, clonk);
return menu_entries;
}
public func OnCableCarHover(symbol, extra_data, desc_menu_target, menu_id)
{
if (symbol == nil) return;
var text = "";
if (extra_data == "Engage")
text = Format("$DescEngage$", GetName(), symbol->GetName());
if (extra_data == "Go")
text = "$DescGo$";
GuiUpdate({ Text = text }, menu_id, 1, desc_menu_target);
}
/*--- Travelling ---*/
// Attach the car onto a crossing
public func EngageRail(object crossing, bool silent)
{
if (! crossing->~IsCableCrossing()) return false;
var position = CreateArray(2);
crossing->GetCablePosition(position);
GetCableOffset(position);
SetPosition(position[0], position[1]);
SetSpeed(0,0);
SetR(0);
SetRDir(0);
SetComDir(COMD_None);
lib_ccar_rail = crossing;
lib_ccar_direction = nil;
if (!silent) Sound("Objects::Connect");
UpdateInteractionMenus(this.GetCableCarMenuEntries);
Engaged();
lib_ccar_rail->OnCableCarEngaged(this);
}
// Detach the car from its current holding point (cable or crossing, does not matter)
public func DisengageRail()
{
lib_ccar_rail = nil;
lib_ccar_direction = nil;
lib_ccar_progress = 0;
lib_ccar_max_progress = 0;
lib_ccar_destination = nil;
UpdateInteractionMenus(this.GetCableCarMenuEntries);
Disengaged();
if (lib_ccar_rail) lib_ccar_rail->OnCableCarDisengaged(this);
}
// Sets a target point for travelling and starts the movement process
public func SetDestination(dest)
{
if(GetType(dest) == C4V_Int)
{
dest = FindObjects(Find_Func("IsCableCrossing"))[dest];
if (!dest) return;
}
lib_ccar_destination = dest;
if(lib_ccar_direction == nil)
{
OnStart();
CrossingReached();
if (lib_ccar_rail)
lib_ccar_rail->~OnCableCarDeparture(this);
}
}
// Whenever a crossing is reached it must be queried for the next crossing to go to
func CrossingReached()
{
var target;
if(lib_ccar_destination != lib_ccar_rail)
{
if(target = lib_ccar_rail->GetNextWaypoint(lib_ccar_destination))
MoveTo(target);
else
DestinationFailed();
}
// Destination reached
else {
DestinationReached();
}
}
// When the current destination is reached
func DestinationReached()
{
lib_ccar_destination = nil;
lib_ccar_direction = nil;
lib_ccar_progress = 0;
lib_ccar_max_progress = 0;
OnStop(false);
if (lib_ccar_rail)
{
if (lib_ccar_delivery)
FinishedRequest(lib_ccar_rail);
lib_ccar_rail->OnCableCarArrival(this);
}
}
// When the way to the current destination has vanished somehow
func DestinationFailed()
{
lib_ccar_destination = nil;
lib_ccar_direction = nil;
lib_ccar_progress = 0;
lib_ccar_max_progress = 0;
OnStop(true);
}
// Setup movement process
func MoveToIndex(int dest)
{
var dest_obj = FindObjects(Find_Func("IsCableCrossing"))[dest];
if (dest_obj) return MoveTo(dest_obj);
}
public func MoveTo(object dest)
{
var rail = 0;
for(var test_rail in FindObjects(Find_Func("IsConnectedTo", lib_ccar_rail)))
{
if(test_rail->IsConnectedTo(dest))
{
rail = test_rail;
break;
}
}
if(!rail)
return DestinationFailed(); // Shouldn't happen
// Target the first or second action target?
if(rail->GetActionTarget(0) == dest)
lib_ccar_direction = 0;
else
lib_ccar_direction = 1;
lib_ccar_progress = 0;
var origin = CreateArray(2), ending = CreateArray(2);
rail->GetActionTarget(0)->GetCablePosition(origin);
rail->GetActionTarget(1)->GetCablePosition(ending);
rail->~Activation(1);
lib_ccar_max_progress = Distance(origin[0], origin[1], ending[0], ending[1]);
lib_ccar_rail = rail;
}
/* Destination selection */
public func OpenDestinationSelection(object clonk)
{
if (!clonk) return;
if (!GetRailTarget()) return;
var plr = clonk->GetOwner();
// Close interaction menu
if (clonk->GetMenu())
if (!clonk->TryCancelMenu())
return;
GUI_DestinationSelectionMenu->CreateFor(clonk, this, GetRailTarget());
}
/*-- Delivery --*/
public func AddRequest(proplist requested, int amount, proplist target, proplist source)
{
lib_ccar_delivery = [source, target, requested, amount];
SetDestination(target);
}
func FinishedRequest(object station)
{
if (station && lib_ccar_delivery)
station->RequestArrived(this, lib_ccar_delivery[2], lib_ccar_delivery[3]);
lib_ccar_delivery = nil;
}

View File

@ -1,9 +0,0 @@
CableCarOptions=Seilbahneinstellungen
TooltipEngage=Das Fahrzeug auf das Seil aufsetzen.
DescEngage=%s bei %s auf das Seil aufsetzen.
TooltipGo=Wähle ein Ziel für das Fahrzeug.
DescGo=Öffnet das Zielwahl-Menü für dieses Fahrzeug. Das Fahrzeug fährt los, sobald ein Ziel ausgewählt wurde.
NoStation=Schiebe das Fahrzeug vor eine Station, um es auf ein Seil zu setzen.

View File

@ -1,9 +0,0 @@
CableCarOptions=Cable Car Options
TooltipEngage=Put the car on the rail
DescEngage=Put %s on the rail at %s.
TooltipGo=Select a destination for the car.
DescGo=Opens the destination selection menu for this cable car. When you select a destination, the car will start going there.
NoStation=Push the cable car in front of a station to set it up.

View File

@ -1,8 +0,0 @@
[DefCore]
id=Library_CableStation
Version=8,0
Category=C4D_StaticBack
Width=20
Height=20
Offset=-10,-10
Picture=0,0,64,64

View File

@ -1,497 +0,0 @@
/**
Cable Station
Library for cable stations and crossings. This is included by
cable crossings, and should be included by structures which
want to make use of the cable network.
@author Randrian, Clonkonaut, Maikel
*/
/*--- Overloads ---*/
// Overload these functions as you feel fit
// This function is called whenever a change in the cable network occured, i.e. destinations have been added / removed.
private func DestinationsUpdated() { }
// Called by cable lines whenever a car starts travelling along a connected cable.
// Can be used to start animation or sounds or similar.
// count is a value indicating the amount of activations.
public func CableActivation(int count) { }
// Called likewise as Activation() whenever a car leaves the cable.
// count is a value indicating the amount of deactivations (e.g. a cable with more than one car broke).
public func CableDeactivation(int count) { }
// Called by arriving cable cars if this station is the final stop
public func OnCableCarArrival(object car) { }
// Called by departing cable cars if it just starts a new journey
public func OnCableCarDeparture(object car) { }
// Called by a cable car that has been hooked up to the rail at this station
public func OnCableCarEngaged(object car) { }
// Called by a cable car that has been taken off the rail at this station
public func OnCableCarDisengaged(object car) { }
// Called when a cable car with a requested delivery arrives
public func OnCableCarDelivery(object car, id requested, int amount) { }
// Called by other stations to check if a certain object and amount are available for delivery at this station.
// Return true if there are means to collect the required amount.
public func IsAvailable(proplist requested, int amount)
{
return false;
}
/*--- Callbacks ---*/
// Be sure to always call these via _inherited(...);
func Initialize()
{
destination_list = [];
request_queue = [];
return _inherited(...);
}
/* Removes this crossing from the network
It first clears every waypoint from the network and then renews the whole information.
Optimisation welcome!
*/
func Destruction()
{
for (var connection in FindObjects(Find_Func("IsConnectedTo", this)))
{
if (! connection->~IsCableLine()) continue;
var other_crossing = connection->~GetConnectedObject(this);
if (! other_crossing->~IsCableCrossing()) continue;
other_crossing->ClearConnections(this);
}
for (var connection in FindObjects(Find_Func("IsConnectedTo", this)))
{
if (! connection->~IsCableLine()) continue;
var other_crossing = connection->~GetConnectedObject(this);
if (! other_crossing->~IsCableCrossing()) continue;
other_crossing->RenewConnections(this);
}
return _inherited(...);
}
/*--- Status ---*/
local lib_crossing_is_station;
/** This object is a cable crossing.
E.g. checked by whatever object wants to connect a cable.
Does not mean that there actually is a cable connected to this crossing.
*/
public func IsCableCrossing() { return true; }
/** This function should return true if this crossing is considered a station.
A station is selectable as a target if a lorry is sent its way.
Functional buildings should always be a station, the 'crossing' building only if set to.
*/
public func IsCableStation() { return lib_crossing_is_station; }
/*--- Interface ---*/
// For switching the station status
public func SetCableStation(bool station)
{
lib_crossing_is_station = station;
}
// Returns the cable hookup position for proper positioning of a car along the line.
public func GetCablePosition(array coordinates, int prec)
{
if (!prec) prec = 1;
coordinates[0] = GetX(prec);
coordinates[1] = GetY(prec);
if (this.LineAttach)
{
coordinates[0] += this.LineAttach[0] * prec;
coordinates[1] += this.LineAttach[1] * prec;
}
}
// Usually called by cable cars to retrieve selectable destinations for the destination selection menu.
// Returns an array of three objects and one int, one station before and one station after the middle one and the middle one.
// The int (fourth array value) is the overall amount of stations found.
// If middle is not a station (anymore), the first three found objects are returned.
public func GetDestinationList(object middle)
{
var list = CreateArray();
var ret = CreateArray(4);
for (var destination in destination_list)
if (destination[const_finaldestination]->IsCableStation())
PushBack(list, destination[const_finaldestination]);
if (GetLength(list) == 0) return ret;
if (GetLength(list) == 1) return [nil, list[0], nil, 1];
if (GetLength(list) == 2) return [list[0], list[1], nil, 2];
if (GetLength(list) == 3) return [list[0], list[1], list[2], 3];
var middle_index = GetIndexOf(list, middle);
if (middle_index == -1) middle_index = 1;
var left_index = middle_index - 1;
if (left_index < 0) left_index = GetLength(list) - 1;
var right_index = middle_index + 1;
if (right_index >= GetLength(list)) right_index = 0;
ret[0] = list[left_index];
ret[1] = list[middle_index];
ret[2] = list[right_index];
ret[3] = GetLength(list);
return ret;
}
/*--- Maintaining the destination list ---*/
/* Functions:
GetDestinations()
AddCableConnection(object cable)
AddCableDestinations(array new_list, object crossing)
AddCableDestination(object new_destination, object crossing, int distance_add)
ClearConnections(object crossing)
RenewConnections(object crossing)
*/
/** Returns the destination array so it can be used by other crossings.
*/
public func GetDestinations()
{
return destination_list[:];
}
// Stores the next crossing (waypoint) to take when advancing to a certain final point
// Scheme (2D array): [Desired final point, Next waypoint to take, Distance (not airline!) until final point]
local destination_list;
// Constants for easier script reading
// These correspond to the aforementioned values of destination_list
local const_finaldestination = 0; // :D
local const_nextwaypoint = 1;
local const_distance = 2;
/** Adds a new connection via the cable \a cable to this crossing
Does nothing if the other connected object of the cable is not a cable crossing
@param cable The newly connected cable
*/
public func AddCableConnection(object cable)
{
// Failsafe
if (!cable || ! cable->~IsCableLine())
return false;
// Line setup finished?
var other_crossing = cable->~GetConnectedObject(this);
if (! other_crossing->~IsCableCrossing())
return false;
// Acquire destinations of the other crossing, all these are now in reach
AddCableDestinations(other_crossing->GetDestinations(), other_crossing);
// Send own destinations, now in reach for the other one
other_crossing->AddCableDestinations(destination_list[:], this);
// Awesome, more power to the network!
DestinationsUpdated();
return true;
}
/** Adds a whole list of destinations to the crossing
* @param new_list The new destination list, formated like a crossing's normal destination list
* @param crossing The crossing where this list comes from
*/
public func AddCableDestinations(array new_list, object crossing)
{
// Append crossing to the list
if (crossing)
{
new_list[GetLength(new_list)] = [crossing, crossing];
// This value is to be added to every distance
var distance_add = ObjectDistance(crossing);
}
else
return false; // Does not compute
// Check every new destination
for (var list_item in new_list)
{
if (!list_item) continue;
// Destination is this
if (list_item[const_finaldestination] == this) continue;
// Check whether the destination is already in reach
var handled = false;
for (var i = 0, destination = false; i < GetLength(destination_list); i++)
{
if (!destination_list[i]) continue;
destination = destination_list[i];
if (destination[const_finaldestination] == list_item[const_finaldestination])
{
// Already known destination, check whether the new path is shorter
handled = true;
if (destination[const_distance] > list_item[const_distance] + distance_add)
{
// It is shorter, replace, route through crossing
destination_list[i] = [list_item[const_finaldestination], crossing, list_item[const_distance] + distance_add];
// Inform the destination
list_item[const_finaldestination]->UpdateCableDestination(this, crossing, distance_add);
}
}
}
// Destination is replaced or to be dismissed (because the new path would be longer), do nothing
if (handled) continue;
// Destination is a new one, add to the list
destination_list[GetLength(destination_list)] = [list_item[const_finaldestination], crossing, list_item[const_distance] + distance_add];
// Add me to the new destination (the way to me is the same than to crossing)
if (list_item[const_finaldestination] != crossing)
list_item[const_finaldestination]->AddCableDestination(this, crossing, distance_add);
}
DestinationsUpdated();
return true;
}
/** Adds a single destination \a new_destination. The link is \a crossing; \a crossing should already be known, otherwise it returns false.
* @param new_destination The destination to add
* @param crossing The crossing which links to the new destination
* @param distance_add The distance between crossing and new_destination
*/
public func AddCableDestination(object new_destination, object crossing, int distance_add)
{
// Failsafe
if (!new_destination || !crossing) return false;
if (new_destination == this) return false;
// Find the entry of crossing to get the next waypoint and the distance
var crossing_item;
for (var list_item in destination_list)
{
if (!list_item) continue;
if (list_item[const_finaldestination] == crossing)
{
crossing_item = list_item;
break;
}
}
// Failsafe
if (!crossing_item) return false;
// Save the new destination
destination_list[GetLength(destination_list)] = [new_destination, crossing_item[const_nextwaypoint], crossing_item[const_distance] + distance_add];
DestinationsUpdated();
return true;
}
/** Updates the path to \a known_destination via \a crossing (e.g. because the path is shorter through \a crossing)
* @param known_destination The destination to update
* @param crossing The crossing which links to the destination
* @param distance_add The distance between crossing and known_destination
*/
public func UpdateCableDestination(object known_destination, object crossing, int distance_add)
{
// Failsafe
if (!known_destination || !crossing) return false;
if (known_destination == crossing) return false;
// Find the entries of crossing and known_destination
var crossing_item, destination_item, i = 0;
for (var list_item in destination_list)
{
if (!list_item) continue;
if (list_item[const_finaldestination] == crossing)
crossing_item = list_item;
if (list_item[const_finaldestination] == known_destination)
destination_item = i;
i++;
}
// Failsafe
if (!crossing_item || !destination_item) return false;
// Save the updated path
destination_list[destination_item][const_nextwaypoint] = crossing_item[const_nextwaypoint];
destination_list[destination_item][const_distance] = crossing_item[const_distance] + distance_add;
DestinationsUpdated();
return true;
}
local clearing;
/* Called automatically by Destruction, see description there
* @param crossing The calling crossing
*/
public func ClearConnections(object crossing)
{
if (clearing) return;
clearing = true;
destination_list = [];
for (var connection in FindObjects(Find_Func("IsConnectedTo", this)))
{
if (! connection->~IsCableLine()) continue;
var other_crossing = connection->~GetConnectedObject(this);
if (! other_crossing->~IsCableCrossing()) continue;
other_crossing->ClearConnections();
}
}
/* Called automatically by Destruction, see description there
* @param crossing The calling crossing
*/
public func RenewConnections(object crossing)
{
if (!clearing) return;
clearing = false;
for(var connection in FindObjects(Find_Func("IsConnectedTo", this)))
{
if (! connection->~IsCableLine()) continue;
var other_crossing = connection->~GetConnectedObject(this);
if (! other_crossing->~IsCableCrossing()) continue;
if (other_crossing == crossing) continue;
destination_list[GetLength(destination_list)] = [other_crossing, other_crossing, ObjectDistance(other_crossing)];
AddCableDestinations(other_crossing->GetDestinations(), other_crossing);
}
}
/*--- Pathfinding ---*/
/* Functions:
GetNextWaypoint(object end)
GetLengthToTarget(object end)
*/
/** Returns the waypoint to take next for the desired final point \a end
* @param end The final destination for the information is queried
*/
public func GetNextWaypoint(object end)
{
if (!destination_list) return nil;
for (var item in destination_list)
{
if (!item) continue;
if (item[const_finaldestination] == end)
return item[const_nextwaypoint];
}
return nil;
}
/** Returns the actual traveling distance for the desired final point \a end
* This is not the airline distance but the length of all cables to take via traveling
* @param end The final destination for the information is queried
*/
public func GetLengthToTarget(object end)
{
if (!destination_list) return nil;
for (var item in destination_list)
{
if (!item) continue;
if (item[const_finaldestination] == end)
return item[const_distance];
}
return nil;
}
/*-- Auto production --*/
local request_queue;
// Add a new acquiring order
public func AddRequest(proplist requested_id, int amount)
{
if (!requested_id) return false;
if (!amount) amount = 1;
// First of all check if a similar request already is on the line
// Similar requests will be dismissed, even if they are technically new
for (var request in request_queue)
if (request[0] == requested_id)
if (request[1] == amount)
return true; // The request is considered handled
var source = CheckAvailability(requested_id, amount);
if (!source)
return false; // Items are not available
var car = source->GetAvailableCableCar(requested_id, amount, this);
if (!car)
return false; // No cable car is available for delivery
// Great. Start working immediately
PushBack(request_queue, [requested_id, amount]);
car->AddRequest(requested_id, amount, this, source);
return true;
}
// Check all connected stations for available objects
func CheckAvailability(proplist requested, int amount)
{
var nearest_station;
var length_to;
for (var destination in destination_list)
{
if (destination[const_finaldestination]->IsAvailable(requested, amount))
{
var station = destination[const_finaldestination];
if (!nearest_station)
{
nearest_station = station;
length_to = GetLengthToTarget(nearest_station);
}
else {
// Storages (like chests) are always preferred over other producer because the items
// might be stored in another producer to produce something
if (station->~IsStorage() && !nearest_station->~IsStorage())
{
nearest_station = station;
length_to = GetLengthToTarget(nearest_station);
}
else if (nearest_station->~IsStorage() && !station->~IsStorage())
continue;
// Otherwise the shorter the path, the better
else if (GetLengthToTarget(station) < length_to)
{
nearest_station = station;
length_to = GetLengthToTarget(nearest_station);
}
}
}
}
return nearest_station;
}
// Check if there is a cable car ready for delivery
public func GetAvailableCableCar(proplist requested, int amount, proplist requesting_station)
{
}
// A delivery has arrived, remove it from the queue and handle the request
public func RequestArrived(proplist car, proplist requested_id, int amount)
{
if (!HasRequest(requested_id, amount))
return;
OnCableCarDelivery(car, requested_id, amount);
RemoveRequest(requested_id, amount);
}
public func HasRequest(id requested, int amount)
{
for (var i = 0; i < GetLength(request_queue); i++)
{
if (request_queue[i][0] != requested)
continue;
if (request_queue[i][1] != amount)
continue;
return true;
}
return false;
}
public func RemoveRequest(id requested, int amount)
{
for (var i = 0; i < GetLength(request_queue); i++)
{
if (request_queue[i][0] != requested)
continue;
if (request_queue[i][1] != amount)
continue;
break;
}
if (i >= GetLength(request_queue))
return false;
RemoveArrayIndex(request_queue, i, true);
return true;
}

View File

@ -1,15 +0,0 @@
[DefCore]
id=CableCrossing
Version=8,0
Category=C4D_Structure
Width=18
Height=26
Offset=-9,-13
Vertices=5
VertexX=6,0,-6,0,6
VertexY=-9,0,12,12,12
VertexFriction=50,50,100,100,100
Value=40
Mass=5
Exclusive=1
Construction=1

View File

@ -1,8 +0,0 @@
[DefCore]
id=CableCrossing_Icons
Version=8,0
Category=C4D_StaticBack
Picture=0,0,64,64
Width=64
Height=64
Offset=-32,-32

View File

@ -1,87 +0,0 @@
material CableCarStation
{
receive_shadows on
technique
{
pass
{
ambient 0.9 0.9 0.9 1.0
diffuse 0.9 0.9 0.9 1.0
specular 0.0 0.0 0.0 1.0 12.5
emissive 0.0 0.0 0.0 1.0
texture_unit
{
texture CableCarStation.png
tex_address_mode wrap
filtering trilinear
}
}
}
}
material CableCarStation_Sign
{
receive_shadows on
technique
{
pass
{
ambient 1.0 1.0 1.0 1.0
diffuse 1.0 1.0 1.0 1.0
specular 0.0 0.0 0.0 1.0 12.5
emissive 1.0 1.0 1.0 1.0
texture_unit
{
texture CableCarStation_sign.png
tex_address_mode wrap
filtering trilinear
}
}
}
}
material CableCarStation_SignStation
{
receive_shadows on
technique
{
pass
{
ambient 1.0 1.0 1.0 1.0
diffuse 1.0 1.0 1.0 1.0
specular 0.0 0.0 0.0 1.0 12.5
emissive 1.0 1.0 1.0 1.0
texture_unit
{
texture CableCarStation_station.png
tex_address_mode wrap
filtering trilinear
}
}
}
}
material CableCarStation_SignDropOff
{
receive_shadows on
technique
{
pass
{
ambient 1.0 1.0 1.0 1.0
diffuse 1.0 1.0 1.0 1.0
specular 0.0 0.0 0.0 1.0 12.5
emissive 1.0 1.0 1.0 1.0
texture_unit
{
texture CableCarStation_dropoff.png
tex_address_mode wrap
filtering trilinear
}
}
}
}

View File

@ -1,334 +0,0 @@
/*--
Cable Crossing
The standard crossing for the cable network.
The crossing will automatically be a station if it is at the end of the cable line (i.e. only one cable connected).
But the crossing can also manually be set to function as a station.
Author: Clonkonaut
--*/
#include Library_CableStation
// Animation
local turn_anim;
// Settings
local setting_dropoff = false;
// Combined building
local connected_building;
// Array of all cable cars currently idling at this station
local arrived_cars;
func Initialize()
{
turn_anim = PlayAnimation("Engine", 1, Anim_Const(0), Anim_Const(1000));
arrived_cars = [];
SetCategory(GetCategory() | C4D_StaticBack);
return _inherited(...);
}
// Prevents the automatic change of the station status when manually set to station mode
local manual_setting = false;
/* Library functions: Cable Station */
public func DestinationsUpdated()
{
// Do nothing if set manually
if (manual_setting) return;
if (GetLength(FindObjects(Find_Func("IsConnectedTo", this))) == 1)
SetCableStation(true);
else
SetCableStation(false);
CheckStationStatus();
}
public func IsAvailable(proplist requested, int amount)
{
// Check connected buildings for contents
if (connected_building)
if (connected_building->ContentsCount(requested) >= amount)
return true;
// Check cable cars idling at this station
if (GetLength(arrived_cars))
{
for (var car in arrived_cars)
{
if (car->~IsAvailable(requested, amount))
return true;
}
}
return false;
}
public func GetAvailableCableCar(proplist requested, int amount, proplist requesting_station)
{
// Check cars that are idling at this station
var best;
for (var car in arrived_cars)
{
if (!car->~IsReadyForDelivery(requested, amount, requesting_station))
continue;
if (!best)
best = car;
// A car might want to override the search for an available car, mainly because it holds the container
// which holds the requested items
else if (car->~OverridePriority(requested, amount, requesting_station, best))
best = car;
}
if (best)
return best;
// Check cars that are idling at the requesting station
if (requesting_station != this)
if (best = requesting_station->~GetAvailableCableCar(requested, amount, requesting_station))
return best;
return nil;
}
public func OnCableCarDelivery(object car, id requested, int amount)
{
// Transfer the requested material to the connected producer
if (!connected_building)
return;
car = car->~GetAttachedVehicle() ?? car;
for (var i = 0; i < amount; i++)
{
var item = car->FindContents(requested);
if (!item)
break;
item->Enter(connected_building);
}
}
/* Construction */
public func IsHammerBuildable() { return true; }
public func ConstructionCombineWith() { return "IsNoCableStationConnected"; }
public func ConstructionCombineDirection(object other)
{
return CONSTRUCTION_STICK_Left | CONSTRUCTION_STICK_Right;
}
public func ConstructionCombineOffset(proplist other)
{
if (!other)
return;
// Make sure the station preview is on the same ground level than the other building
var ret = [0,0];
ret[1] = other->GetObjHeight()/2 - this->GetDefHeight()/2;
return ret;
}
public func CombineWith(object stick_to)
{
if (!stick_to) return;
if (stick_to->~IsProducer())
{
connected_building = stick_to;
stick_to->ConnectCableStation(this);
}
}
/* Interaction */
// Provides an own interaction menu.
public func HasInteractionMenu() { return true; }
// Show settings in interaction menu
public func GetInteractionMenus(object clonk)
{
var menus = _inherited(clonk, ...) ?? [];
var crossing_menu =
{
title = "$StationSettings$",
entries_callback = this.GetSettingsMenuEntries,
callback = nil,
callback_hover = "OnSettingsHover",
callback_target = this,
BackgroundColor = RGB(0, 0, 50),
Priority = 20
};
PushBack(menus, crossing_menu);
return menus;
}
public func GetSettingsMenuEntries()
{
var control_prototype =
{
BackgroundColor = { Std = 0, Selected = RGB(100, 30, 30) },
OnMouseIn = GuiAction_SetTag("Selected"),
OnMouseOut = GuiAction_SetTag("Std")
};
var custom_entry =
{
Right = "3em", Bottom = "2em",
image = { Prototype = control_prototype }
};
var menu_entries = [];
// Clickable buttons
var station = new custom_entry {
Priority = 1000,
Tooltip = "$TooltipToggleStation$",
OnClick = GuiAction_Call(this, "ToggleStation", false),
image = { Prototype = custom_entry.image }
};
station.image.Symbol = CableCrossing_Icons;
station.image.GraphicsName = "Station";
PushBack(menu_entries, { symbol = CableCrossing_Icons, extra_data = "Station", custom = station });
var drop_off = new custom_entry {
Priority = 1001,
Tooltip = "$TooltipToggleDropOff$",
OnClick = GuiAction_Call(this, "ToggleDropOff", false),
image = { Prototype = custom_entry.image }
};
drop_off.image.Symbol = CableCrossing_Icons;
drop_off.image.GraphicsName = "DropOff";
PushBack(menu_entries, { symbol = CableCrossing_Icons, extra_data = "DropOff", custom = drop_off });
return menu_entries;
}
public func OnSettingsHover(symbol, extra_data, desc_menu_target, menu_id)
{
if (symbol == nil) return;
var text = "";
if (extra_data == "Station")
text = "$DescToggleStation$";
if (extra_data == "DropOff")
text = "$DescToggleDropOff$";
GuiUpdate({ Text = text }, menu_id, 1, desc_menu_target);
}
/* Settings */
public func ToggleStation(bool silent)
{
SetCableStation(!IsCableStation());
if (!manual_setting)
manual_setting = true;
if (!silent)
Sound("UI::Click2");
CheckStationStatus();
}
public func ToggleDropOff(bool silent)
{
if (!setting_dropoff)
{
if (!IsCableStation())
ToggleStation(true);
setting_dropoff = true;
} else {
setting_dropoff = false;
}
if (!silent)
Sound("UI::Click2");
CheckStationStatus();
}
/* Cable Car Management */
public func OnCableCarArrival(object car)
{
// Apply all settings to the arriving car
if (setting_dropoff)
if (car)
car->~DropContents(this);
// Save the car
PushBack(arrived_cars, car);
}
public func OnCableCarDeparture(object car)
{
RemoveArrayValue(arrived_cars, car, true);
}
public func OnCableCarEngaged(object car)
{
PushBack(arrived_cars, car);
}
public func OnCableCarDisengaged(object car)
{
RemoveArrayValue(arrived_cars, car, true);
}
/* Visuals */
func CheckStationStatus()
{
if (IsCableStation())
{
// In order of priority
if (setting_dropoff)
{
SetMeshMaterial("CableCarStation_SignDropOff", 1);
} else {
SetMeshMaterial("CableCarStation_SignStation", 1);
}
}
else
SetMeshMaterial("CableCarStation_Sign", 1);
}
local activations = 0;
func CableActivation(int count)
{
if (activations <= 0)
SetAnimationPosition(turn_anim, Anim_Linear(GetAnimationPosition(turn_anim), 0, GetAnimationLength("Engine"), 175, ANIM_Loop));
activations += count;
}
func CableDeactivation(int count)
{
activations -= count;
if (activations <= 0)
SetAnimationPosition(turn_anim, Anim_Const(GetAnimationPosition(turn_anim)));
}
public func NoConstructionFlip() { return true; }
/* Saving */
func SaveScenarioObject(props)
{
if (!inherited(props, ...)) return false;
if (IsCableStation() && manual_setting)
props->AddCall("StationSetting", this, "ToggleStation", true);
if (!IsCableStation() && manual_setting)
props->AddCall("ManualSetting", this, "SetManual");
if (connected_building)
props->AddCall("Combination", this, "CombineWith", connected_building);
return true;
}
public func SetManual() { manual_setting = true; return true; }
/* Properties */
local Name = "$Name$";
local BlastIncinerate = 50;
local LineAttach = [6,-9];

View File

@ -1,7 +0,0 @@
Name=Seilbahnkreuzung
StationSettings=Seilbahneinstellungen
TooltipToggleStation=Bahnhofs-Status umstellen.
DescToggleStation=Diese Kreuzung von Hand zu einem Bahnhof oder wieder zu einer Kreuzung umschalten. Nur Bahnhöfe sind als Ziel wählbar und nur am Bahnhöfen können Fahrzeuge aufgesetzt werden.

View File

@ -1,9 +0,0 @@
Name=Cable Crossing
StationSettings=Cable crossing settings
TooltipToggleStation=Toggle station status
TooltipToggleDropOff=Toggle item dropping status
DescToggleStation=Manually set or unset this crossing to be a cable station. Cable stations are selectable as targets when engaging a cable car onto the cable.
DescToggleDropOff=All arriving vehicle are emptied upon arrival at this station (giving it is the final stop). Will also be set as a cable station.

View File

@ -1,14 +0,0 @@
[DefCore]
id=CableHoist
Version=8,0
Category=C4D_Vehicle
Width=26
Height=18
Offset=-13,-9
Vertices=5
VertexX=0,-8,8,-9,9
VertexY=-6,-5,-5,7,7
VertexCNAT=5,6,9,10
VertexFriction=50,80,80,30,30
Value=20
Mass=150

View File

@ -1,21 +0,0 @@
material CableHoist
{
receive_shadows on
technique
{
pass
{
ambient 1.0 1.0 1.0 1.0
diffuse 1.0 1.0 1.0 1.0
specular 0.5 0.5 0.5 1.0 12.5
emissive 0.0 0.0 0.0 1.0
texture_unit
{
texture cable_hoist.png
tex_address_mode wrap
filtering trilinear
}
}
}
}

View File

@ -1,219 +0,0 @@
/*-- Cable Hoist --*/
#include Library_CableCar
local pickup;
/* Creation */
func Construction()
{
SetProperty("MeshTransformation",Trans_Rotate(13,0,1,0));
SetCableSpeed(1);
}
/* Engine Callbacks */
func Damage(int change, int cause)
{
if (cause == FX_Call_DmgBlast)
{
// Explosions knock the hoist off the rail
if (GetAction() == "OnRail")
DisengageRail();
if (pickup)
DropVehicle();
}
}
/* Status */
public func IsToolProduct() { return true; }
/* Cable Car Library */
func GetCableOffset(array position, int prec)
{
if (!prec) prec = 1;
position[1] += 5 * prec;
}
func Engaged()
{
SetAction("OnRail");
}
func Disengaged()
{
SetAction("Idle");
if (pickup)
DropVehicle();
}
func GetCableCarExtraMenuEntries(array menu_entries, proplist custom_entry, object clonk)
{
if (IsTravelling()) return;
if (!pickup && GetRailTarget())
{
// Picking up vehicles
var vehicles = FindObjects(Find_AtPoint(), Find_Category(C4D_Vehicle), Find_Not(Find_Func("RejectCableHoistPickup", this)), Find_Exclude(this), Find_Func(pickup));
var i = 0;
for (var vehicle in vehicles)
{
if (GetEffect("CableHoistPickup", vehicle)) continue;
var to_pickup = new custom_entry {
Priority = 2000 + i,
Tooltip = "$TooltipPickup$",
OnClick = GuiAction_Call(this, "PickupVehicle", vehicle),
image = { Prototype = custom_entry.image, Symbol = vehicle },
icon = { Prototype = custom_entry.icon, Symbol = Icon_LibraryCableCar, GraphicsName = "Engage" }
};
PushBack(menu_entries, { symbol = vehicle, extra_data = "Pickup", custom = to_pickup });
i++;
}
} else if (pickup && GetRailTarget()) {
// Drop the vehicle
var drop = new custom_entry {
Priority = 2000,
Tooltip = "$TooltipDrop$",
OnClick = GuiAction_Call(this, "DropVehicle"),
image = { Prototype = custom_entry.image, Symbol = pickup },
icon = { Prototype = custom_entry.icon, Symbol = Icon_LibraryCableCar, GraphicsName = "Disengage" }
};
PushBack(menu_entries, { symbol = pickup, extra_data = "Drop", custom = drop });
}
}
/* Picking up vehicles */
public func PickupVehicle(object vehicle)
{
if (!vehicle) return;
if (GetEffect("CableHoistPickup", vehicle)) return;
var width = vehicle->GetObjWidth() / 2;
var height = vehicle->GetObjHeight() / 2;
if (!Inside(GetX(), vehicle->GetX() - width, vehicle->GetX() + width))
if (!Inside(GetY(), vehicle->GetY() - height, vehicle->GetY() + height))
return;
AddEffect("CableHoistPickup", vehicle, 1, 1, this);
UpdateInteractionMenus(this.GetCableCarMenuEntries);
}
public func DropVehicle()
{
if (!pickup) return;
RemoveEffect("CableHoistPickup", pickup);
UpdateInteractionMenus(this.GetCableCarMenuEntries);
}
func FxCableHoistPickupStart(object vehicle, proplist effect)
{
vehicle->SetPosition(GetX(), GetY()+4);
vehicle->SetSpeed(0,0);
vehicle->SetR(GetR());
vehicle->SetRDir(0);
pickup = vehicle;
}
func FxCableHoistPickupTimer(object vehicle, proplist effect)
{
vehicle->SetPosition(GetX(), GetY()+4);
vehicle->SetSpeed(0,0);
}
func FxCableHoistPickupStop(object vehicle, proplist effect)
{
pickup = nil;
}
/* Actions */
func OnRail()
{
DoMovement();
}
local ActMap = {
OnRail = {
Prototype = Action,
Name = "OnRail",
Procedure = DFA_FLOAT,
Directions = 2,
FlipDir = 1,
Length = 1,
Delay = 1,
X = 0,
Y = 0,
Wdt = 26,
Hgt = 18,
EndCall = "OnRail",
NextAction = "OnRail",
},
};
/* Callbacks */
public func GetAttachedVehicle()
{
return pickup;
}
// Calls from the stations will mostly be forwarded to the attached vehicle
public func DropContents(proplist station)
{
if (pickup)
pickup->DropContents(station);
}
// Check for available contents
public func IsAvailable(proplist requested, int amount)
{
// So far only do something if a lorry is connected, all other vehicles are considered off-limits
if (pickup && pickup->~IsLorry())
if (pickup->ContentsCount(requested) >= amount)
return true;
return false;
}
// Called when a station has asked to make a delivery
public func IsReadyForDelivery(proplist requested, int amount, proplist requesting_station)
{
// Only if a lorry is connected
if (pickup && pickup->~IsLorry())
{
// Lorry must have enough space left...
if (pickup->ContentsCount() + amount <= pickup.MaxContentsCount)
return true;
// ...or contain the requested objects
if (pickup->ContentsCount(requested) >= amount)
return true;
}
return false;
}
// Called when searching for a better option to deliver something
public func OverridePriority(proplist requested, int amount, proplist requesting_station, proplist best)
{
// Check if the connected vehicle holds the requested objects and if yes, override the selection
if (pickup && pickup->ContentsCount(requested) >= amount)
return true;
return false;
}
/* Definition */
func Definition(def)
{
SetProperty("PictureTransformation",Trans_Mul(Trans_Rotate(-25,1,0,0),Trans_Rotate(40,0,1,0)),def);
}
local Name = "$Name$";
local Description = "$Description$";
local Touchable = 1;
local BorderBound = C4D_Border_Sides;

View File

@ -1,5 +0,0 @@
Name=Schlitten
Description=Zum Aufsatz auf Kabel. Transportiert Fahrzeuge.
TooltipPickup=Dieses Fahrzeug an den Schlitten anhängen.
TooltipDrop=Dieses Fahrzeug vom Schlitten abnehmen.

View File

@ -1,5 +0,0 @@
Name=Hoist
Description=To use on a cable. Transports vehicles.
TooltipPickup=Attach this vehicle to the hoist.
TooltipDrop=Drop this vehicle from the hoist.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 KiB

View File

@ -1,18 +0,0 @@
[DefCore]
id=CableLorry
Version=8,0
Category=C4D_Vehicle
Width=22
Height=16
Offset=-11,-8
Vertices=4
VertexX=-8,7,-8,7
VertexY=-6,-6,7,7
VertexCNAT=5,6,9,10
VertexFriction=80,80,10,10
Value=20
Mass=75
Collection=-12,-8,24,10
GrabPutGet=C4D_GrabGet|C4D_GrabPut
Rotate=30
UprightAttach=0

View File

@ -1,21 +0,0 @@
material Lorry2
{
receive_shadows on
technique
{
pass
{
ambient 1 1 1 1.0
diffuse 0.9 0.9 0.9 1.0
specular 0.5 0.5 0.5 1.0 12.5
emissive 0.0 0.0 0.0 1.0
texture_unit
{
texture lorry_new.png
tex_address_mode wrap
filtering trilinear
}
}
}
}

View File

@ -1,303 +0,0 @@
/**
Lorry
Transportation and storage for up to 50 objects.
@authors Maikel
*/
#include Library_ElevatorControl
local drive_anim;
local empty_anim;
/*-- Engine Callbacks --*/
func Construction()
{
SetProperty("MeshTransformation", Trans_Rotate(13, 0, 1, 0));
}
func Initialize()
{
drive_anim = PlayAnimation("Drive", 1, Anim_X(0,0, GetAnimationLength("Drive"), 30), Anim_Const(1000));
empty_anim = PlayAnimation("Empty", 2, Anim_Const(0), Anim_Const(0));
}
func Hit3()
{
Sound("Hits::Materials::Metal::DullMetalHit?");
}
func RejectCollect(id object_id, object obj)
{
// Collection maybe blocked if this object was just dumped.
if (!obj->Contained() && GetEffect("BlockCollectionByLorry", obj))
return true;
// Objects can still be collected.
if (ContentsCount() < MaxContentsCount)
{
Sound("Objects::Clonk");
return false;
}
// The object cannot be collected, notify carrier?
if (obj->Contained())
Message("$TxtLorryisfull$");
else
{
// If not carried, objects slide over the lorry.
if (Abs(obj->GetXDir()) > 5)
{
obj->SetYDir(-2);
obj->SetRDir(0);
Sound("Hits::SoftHit*");
}
}
// Reject collection.
return true;
}
// Automatic unloading in buildings.
func Entrance(object container)
{
// Only in buildings
if (container->GetCategory() & (C4D_StaticBack | C4D_Structure))
// Not if the building prohibits this action.
if (!container->~NoLorryEjection(this))
// Empty lorry.
container->GrabContents(this);
}
func ContactLeft()
{
if (Stuck() && !Random(5))
SetRDir(RandomX(-7, +7));
}
func ContactRight()
{
if (Stuck() && !Random(5))
SetRDir(RandomX(-7, +7));
}
func Damage(int change, int cause, int by_player)
{
// Only explode the lorry on blast damage.
if (cause != FX_Call_DmgBlast)
return _inherited(change, cause, by_player, ...);
// Explode the lorry when it has taken to much damage.
if (GetDamage() > 100)
{
// Only exit objects and parts if this lorry is not contained.
if (!Contained())
{
// First eject the contents in different directions.
for (var obj in FindObjects(Find_Container(this)))
{
var speed = RandomX(3, 5);
var angle = Random(360);
var dx = Cos(angle, speed);
var dy = Sin(angle, speed);
obj->Exit(RandomX(-4, 4), RandomX(-4, 4), Random(360), dx, dy, RandomX(-20, 20));
obj->SetController(by_player);
}
// Toss around some fragments with particles attached.
for (var i = 0; i < 6; i++)
{
var fragment = CreateObject(LorryFragment, RandomX(-4, 4), RandomX(-4, 4), GetOwner());
var speed = RandomX(40, 60);
var angle = Random(360);
var dx = Cos(angle, speed);
var dy = Sin(angle, speed);
fragment->SetXDir(dx, 10);
fragment->SetYDir(dy, 10);
fragment->SetR(360);
fragment->SetRDir(RandomX(-20, 20));
// Set the controller of the fragments to the one causing the blast for kill tracing.
fragment->SetController(by_player);
// Incinerate the fragments.
fragment->Incinerate(100, by_player);
}
}
// Remove the lorry itself, eject possible contents as they might have entered again.
// Or let the engine eject the contents if it is inside a container.
return RemoveObject(true);
}
return _inherited(change, cause, by_player, ...);
}
/*-- Callbacks --*/
public func IsLorry() { return true; }
public func IsVehicle() { return true; }
public func IsContainer() { return true; }
// Called upon arrival at a cable station
public func DropContents(proplist station)
{
// Drop everything in a few seconds
SetAnimationWeight(empty_anim, Anim_Const(1000));
SetAnimationPosition(empty_anim, Anim_Linear(0,0, GetAnimationLength("Empty"), 35, ANIM_Hold));
ScheduleCall(this, "Empty", 35);
}
func Empty()
{
// Exit everything at once (as opposed to manual dumping below)
while (Contents())
{
var content = Contents();
AddEffect("BlockCollectionByLorry", content, 100, 16, this);
content->Exit(RandomX(-5,5), RandomX(-2,2), Random(360));
}
SetAnimationWeight(empty_anim, Anim_Linear(1000,1000, 0, 35, ANIM_Hold));
SetAnimationPosition(empty_anim, Anim_Linear(GetAnimationLength("Empty"), GetAnimationLength("Empty"), 0, 35, ANIM_Hold));
}
/*-- Usage --*/
public func HoldingEnabled() { return true; }
public func ControlUseStart(object clonk, int x, int y)
{
var direction = DIR_Left;
if (x > 0)
direction = DIR_Right;
if (!GetEffect("DumpContents", this))
AddEffect("DumpContents", this, 100, 1, this, nil, direction);
return true;
}
public func ControlUseHolding(object clonk, int x, int y)
{
var direction = DIR_Left;
if (x > 0)
direction = DIR_Right;
var effect = GetEffect("DumpContents", this);
if (effect)
effect.dump_dir = direction;
return true;
}
public func ControlUseStop(object clonk, int x, int y)
{
RemoveEffect("DumpContents", this);
return true;
}
public func ControlUseCancel(object clonk, int x, int y)
{
RemoveEffect("DumpContents", this);
return true;
}
public func FxDumpContentsStart(object target, proplist effect, int temp, int direction)
{
if (temp)
return FX_OK;
// The time it takes to dump the contents depends on the mass of the lorry.
effect.dump_strength = BoundBy(1000 / GetMass(), 3, 8);
effect.dump_dir = direction;
// Rotate the lorry into the requested direction.
var rdir = -effect.dump_strength;
if (effect.dump_dir == DIR_Right)
rdir = effect.dump_strength;
SetRDir(rdir);
// Start dump sounds together.
Sound("Objects::Lorry::Dump1", false, 100, nil, +1);
Sound("Objects::Lorry::Dump2", false, 100, nil, +1);
return FX_OK;
}
public func FxDumpContentsTimer(object target, proplist effect, int time)
{
// Rotate the lorry into the requested direction.
var rdir = -effect.dump_strength;
if (effect.dump_dir == DIR_Right)
rdir = effect.dump_strength;
SetRDir(rdir);
// Dump one item every some frames if the angle is above 45 degrees. Only do this if the effect is at least active
// for 10 frames to prevent an accidental click while holding the lorry to dump some of its contents.
if (time >= 10 && ((effect.dump_dir == DIR_Left && GetR() < -45) || (effect.dump_dir == DIR_Right && GetR() > 45)))
{
if (!Random(3))
{
var x = RandomX(6, 8) * Sign(GetR());
var xdir = RandomX(70, 90) * Sign(GetR());
var random_content = FindObjects(Find_Container(this), Sort_Random());
if (GetLength(random_content) >= 1)
{
random_content = random_content[0];
random_content->Exit(x, RandomX(2, 3), Random(360), 0, 0, RandomX(-5, 5));
random_content->SetXDir(xdir, 100);
// Assume the controller of the lorry is also the one dumping the contents.
random_content->SetController(GetController());
AddEffect("BlockCollectionByLorry", random_content, 100, 8, this);
if (random_content->~IsLiquid())
{
random_content->SetPosition(GetX(), GetY());
random_content->Disperse(GetR() + 10 * Sign(GetR()));
}
}
}
}
return FX_OK;
}
public func FxDumpContentsStop(object target, proplist effect, int reason, bool temp)
{
if (temp)
return FX_OK;
// Stop rotating the lorry.
SetRDir(0);
// Stop dump sounds.
Sound("Objects::Lorry::Dump1", false, 100, nil, -1);
Sound("Objects::Lorry::Dump2", false, 100, nil, -1);
return FX_OK;
}
public func FxBlockCollectionByLorryTimer() { return FX_Execute_Kill; }
/*-- Production --*/
public func IsToolProduct() { return true; }
/*-- Actions --*/
local ActMap = {
Drive = {
Prototype = Action,
Name = "Drive",
Procedure = DFA_NONE,
Directions = 2,
FlipDir = 1,
Length = 20,
Delay = 2,
X = 0,
Y = 0,
Wdt = 22,
Hgt = 16,
NextAction = "Drive",
//Animation = "Drive",
},
};
/*-- Display --*/
public func Definition(proplist def)
{
SetProperty("PictureTransformation", Trans_Mul(Trans_Rotate(-25, 1, 0, 0), Trans_Rotate(40, 0, 1, 0)), def);
}
/*-- Properties --*/
local Name = "$Name$";
local Description = "$Description$";
local Touchable = 1;
local BorderBound = C4D_Border_Sides;
local ContactCalls = true;
local Components = {Metal = 2, Wood = 1};
local MaxContentsCount = 50;

View File

@ -1,5 +0,0 @@
TxtControl=Steuerung
TxtLorryisfull=Lore ist|voll.
TxtLoadUp=Einladen
Name=Lore
Description=Erleichtert den Transport größerer Materialmengen. Fasst bis zu 50 Objekte.

Some files were not shown because too many files have changed in this diff Show More