Remove folders from planet/ which aren't part of the release
|
@ -1,5 +0,0 @@
|
|||
[DefCore]
|
||||
id=Ambience
|
||||
Version=8,0
|
||||
Category=C4D_StaticBack | C4D_Rule
|
||||
Picture=0,0,128,128
|
Before Width: | Height: | Size: 14 KiB |
|
@ -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;
|
|
@ -1,2 +0,0 @@
|
|||
Name=Ambiente
|
||||
Description=Regelt die Geraeuschkulisse.
|
|
@ -1,3 +0,0 @@
|
|||
Name=Ambience
|
||||
Description=Controls environmental sounds and music.
|
||||
|
|
@ -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
|
Before Width: | Height: | Size: 5.8 KiB |
|
@ -1,7 +0,0 @@
|
|||
[DefCore]
|
||||
id=VisualPath
|
||||
Version=8,0
|
||||
Category=C4D_StaticBack
|
||||
Width=1
|
||||
Height=1
|
||||
Picture=0,0,1,1
|
Before Width: | Height: | Size: 851 B |
|
@ -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";
|
|
@ -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;
|
|
@ -1 +0,0 @@
|
|||
Name=Feuerglob
|
|
@ -1 +0,0 @@
|
|||
Name=Fire globe
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 525 KiB |
|
@ -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.
|
|
@ -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
|
|
@ -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
|
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 511 B |
|
@ -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;
|
|
@ -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.
|
|
@ -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.
|
|
@ -1,8 +0,0 @@
|
|||
[DefCore]
|
||||
id=LiftTower_Rope
|
||||
Version=8,0
|
||||
Category=C4D_StaticBack
|
||||
Vertices=2
|
||||
Width=2
|
||||
Height=12
|
||||
Offset=-1,-6
|
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 767 B |
Before Width: | Height: | Size: 4.0 KiB |
|
@ -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$";
|
|
@ -1 +0,0 @@
|
|||
Name=Seil
|
|
@ -1 +0,0 @@
|
|||
Name=Rope
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -1,4 +0,0 @@
|
|||
Name=Hebeturm
|
||||
Description=Um schwere Lasten zu heben.
|
||||
TakeHook=Haken nehmen.
|
||||
Grab=Anfassen
|
|
@ -1,4 +0,0 @@
|
|||
Name=Lift Tower
|
||||
Description=For pulling heavy loads.
|
||||
TakeHook=Take the hook.
|
||||
Grab=Grab
|
|
@ -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
|
Before Width: | Height: | Size: 2.4 KiB |
|
@ -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;
|
|
@ -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
|
|
@ -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
|
|
@ -1,6 +0,0 @@
|
|||
[DefCore]
|
||||
id=CableLine
|
||||
Version=8,0
|
||||
Category=C4D_StaticBack
|
||||
Vertices=2
|
||||
Line=1
|
Before Width: | Height: | Size: 141 B |
|
@ -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$";
|
|
@ -1,2 +0,0 @@
|
|||
TxtLinebroke=Seil gerissen
|
||||
Name=Seilbahnseil
|
|
@ -1,2 +0,0 @@
|
|||
TxtLinebroke=Line broke
|
||||
Name=Cable line
|
|
@ -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
|
Before Width: | Height: | Size: 6.8 KiB |
|
@ -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;
|
|
@ -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.
|
|
@ -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.
|
|
@ -1,4 +0,0 @@
|
|||
[DefCore]
|
||||
id=Library_CableCar
|
||||
Version=8,0
|
||||
Category=C4D_StaticBack
|
|
@ -1,4 +0,0 @@
|
|||
[DefCore]
|
||||
id=GUI_DestinationSelectionMenu
|
||||
Version=8,0
|
||||
Category=C4D_StaticBack | C4D_Environment
|
|
@ -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();
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
Name=Zielwahlmenü
|
||||
Description=
|
|
@ -1,4 +0,0 @@
|
|||
Name=Destination Selection Menu
|
||||
Description=
|
||||
SelectDestination=Select a destination:
|
||||
SendTo=Send the cable car to %s
|
Before Width: | Height: | Size: 154 B |
|
@ -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
|
Before Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 3.9 KiB |
|
@ -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;
|
||||
}
|
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
Before Width: | Height: | Size: 154 B |
|
@ -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;
|
||||
}
|
Before Width: | Height: | Size: 1.5 MiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 25 KiB |
|
@ -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
|
|
@ -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
|
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 7.2 KiB |
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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];
|
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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.
|
|
@ -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.
|
Before Width: | Height: | Size: 191 KiB |
|
@ -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
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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.
|