rewritten elevator case to be less hacky and adjusted its power-consumption-behavior

David Dormagen 2012-11-03 16:17:30 +01:00
parent b985dcc931
commit f509d052e3
8 changed files with 614 additions and 280 deletions

View File

@ -56,8 +56,9 @@ public func FxElevatorControlStart(object vehicle, proplist effect, int temp, ob
public func FxElevatorControlTimer(object vehicle, proplist effect)
{
if (ObjectDistance(effect.case, vehicle) > 12)
return -1;
if(!effect.case) return -1;
if(effect.case->OutOfRange(vehicle)) return -1;
if (effect.controlled && !FindObject(Find_Action("Push"), Find_ActionTarget(vehicle)))
{
effect.case->ControlStop(vehicle, effect.controlled);

View File

@ -4,4 +4,9 @@ Version=5,2,0,1
Width=24
Height=45
Offset=-12,-26
Category=C4D_StaticBack
Category=C4D_StaticBack
# for attachment
Vertices=1
VertexX=-12
VertexY=-2
VertexFriction=0

View File

@ -3,4 +3,20 @@
func Initialize()
{
//SetProperty("MeshTransformation", Trans_Mul(Trans_Scale(800), Trans_Translate(0, -2000)));
}
}
func AttachTargetLost()
{
RemoveObject();
}
local ActMap = {
Attach = {
Prototype = Action,
Name = "Attach",
Procedure = DFA_ATTACH,
Directions = 1,
FacetBase = 1,
NextAction = "Attach"
}
};

View File

@ -4,4 +4,10 @@ Version=5,2,0,1
Width=24
Height=34
Offset=-12,-17
Category=C4D_StaticBack
Category=C4D_StaticBack
# for attachment
Vertices=1
VertexX=-12
VertexY=-5
VertexFriction=0

View File

@ -5,4 +5,20 @@ local Plane = 505;
func Initialize()
{
//SetProperty("MeshTransformation", Trans_Scale(800));
}
}
func AttachTargetLost()
{
RemoveObject();
}
local ActMap = {
Attach = {
Prototype = Action,
Name = "Attach",
Procedure = DFA_ATTACH,
Directions = 1,
FacetBase = 1,
NextAction = "Attach"
}
};

View File

@ -5,11 +5,13 @@ Category=C4D_Vehicle
Width=24
Height=26
Offset=-12,-13
Vertices=4
VertexX=-12,11,-12,11
VertexY=-10,-10,10,10
VertexCNAT=5,6,9,10
VertexFriction=100,100,100,100
# important: 4 vertices (5 to 8) are used in script!
# if you change the number of vertices, make sure to adjust the script
Vertices=8
VertexX=-12,11,-12,11, -12,11,-12,11
VertexY=-10,-10,9,9, -10,-10,9,9
VertexCNAT=5,6,9,10, 5,6,9,10
VertexFriction=100,100,100,100, 100,100,100,100
Value=0
Mass=30
Components=Wood=1
@ -18,4 +20,5 @@ TopFace=0,0,24,26,0,0
Picture=24,0,152,128
HorizontalFix=1
NoPushEnter=1
ContactCalls=1
ContactCalls=1

View File

@ -3,18 +3,49 @@
#include Library_Structure
#include Library_PowerConsumer
local elevator;
local slave, partner, no_connection;
static const ElevatorCase_move_speed = 20;
static const ElevatorCase_up = -1;
static const ElevatorCase_down = 1;
// if you change the vertices in the defcore make sure to adjust this
static const ElevatorCase_additional_vertex_index_begin = 4;
static const ElevatorCase_normal_vertex_index_begin = 0;
static const ElevatorCase_additional_vertex_count = 4;
// Meshes
local front, back;
local elevator;
local partner, partner_was_synced, is_master;
// can be changed from outside
// standard: ElevatorCase_move_speed, 2 * ElevatorCase_move_speed
local case_speed; // when user controls case
local case_speed_automatic; // when case goes to user
/* Callbacks */
func GetDrillSpeed()
{
return ElevatorCase_move_speed / 2;
}
func Initialize()
{
AddTimer("Movement", 1);
AddEffect("CheckAutoMoveTo", this, 1, 30, this);
AddEffect("ElevatorUpperLimitCheck", this, 1, 1, this);
AddEffect("FetchVehicles", this, 1, 10, this);
case_speed = ElevatorCase_move_speed;
case_speed_automatic = 2 * case_speed;
partner_was_synced = false;
front = CreateObject(Elevator_Case_Front, 0,13, GetOwner());
back = CreateObject(Elevator_Case_Back, 0,13, GetOwner());
front->SetAction("Attach", this);
back->SetAction("Attach", this);
}
// Called by the elevator
@ -22,225 +53,135 @@ func Connect(object connect_to)
{
elevator = connect_to;
SetComDir(COMD_None);
SetAction("Drive");
SetAction("DriveIdle");
}
// request power
MakePowerConsumer(50);
func Destruction()
{
if(partner)
partner->LoseConnection();
if(elevator)
elevator->LostCase();
for(var i = 0; i < 3; ++i)
{
var wood = CreateObject(Wood, 0, 0, NO_OWNER);
wood->Incinerate();
wood->SetXDir(RandomX(-10, 10));
wood->SetYDir(RandomX(-2, 0));
}
}
func LostElevator()
{
// die x.x
RemoveObject();
}
// Called by the elevator in case a partner elevator was constructed
func StartConnection(object elevator)
func StartConnection(object case)
{
partner = elevator.case;
partner.partner = this;
// We are not yet connected
no_connection = true;
partner.no_connection = true;
partner = case;
partner_was_synced = false;
if(case.partner != this)
{
case->StartConnection(this);
is_master = true;
AddEffect("TryToSync", this, 1, 1, this);
}
else // is slave
{
is_master = false;
MoveTo(nil, 0, case);
}
}
// Called when the other elevator is destroyed or moved
func LoseConnection()
{
partner = nil;
no_connection = false;
slave = false;
}
/* Energy */
// for the position
func GetActualPowerConsumer()
{
return elevator;
}
// the lift may not need power when not used
func QueryWaivePowerRequest()
{
if(!movement && !drill)
return 10;
else return 0;
}
func OnNotEnoughPower()
{
// Stop movement if moving
is_master = nil;
partner_was_synced = false;
if(GetEffect("TryToSync", this))
RemoveEffect("TryToSync", this);
SetPartnerVertices(0, 0);
SetActionData(0);
Halt();
movement = 0;
ClearMoveTo();
if (drill)
{
SetAction("Drive");
Sound("ElevatorDrilling", nil, nil, nil, -1);
drill = false;
}
return _inherited(...);
}
func OnEnoughPower()
// slave loses attach to master?
func AttachTargetLost()
{
return _inherited(...);
LoseConnection();
}
/* Movement behaviour */
local move_to, // Y-coordinate to move to on its own
move_to_delay, // Delay before moving
move_to_target; // Target to move to
func Movement()
func ExecuteSync()
{
// Move back and front
front->SetPosition(GetX(), GetY()-3);
back->SetPosition(GetX(), GetY()-5);
if(!is_master) FatalError("ExecuteSync() called on slave elevator case!");
partner_was_synced = true;
partner.partner_was_synced = true;
ForceSync();
SetPartnerVertices(partner->GetX() - GetX(), partner->GetY() - GetY());
// reset power usage
UnmakePowerConsumer();
partner->UnmakePowerConsumer();
// can now attach partner on one of the new vertices
partner->SetAction("Attach", this);
var vertex_data = (ElevatorCase_normal_vertex_index_begin << 8) + ElevatorCase_additional_vertex_index_begin;
partner->SetActionData(vertex_data);
Sound("Click");
}
// No elevator?!
if (!elevator)
// sets additional vertices to partner's position
func SetPartnerVertices(int off_x, int off_y)
{
var update_mode = 2; // force immediate update and store information
for(var i = 0; i < ElevatorCase_additional_vertex_count; ++i)
{
// Elevator crash, oh the horror!
if (!ActIdle()) SetAction("Idle");
return;
SetVertex(ElevatorCase_additional_vertex_index_begin + i, VTX_X, GetVertex(ElevatorCase_normal_vertex_index_begin + i, VTX_X) + off_x, update_mode);
SetVertex(ElevatorCase_additional_vertex_index_begin + i, VTX_Y, GetVertex(ElevatorCase_normal_vertex_index_begin + i, VTX_Y) + off_y, update_mode);
}
}
// Fetch vehicles
for (var vehicle in FindObjects(Find_InRect(-5, -5, 10, 10), Find_Category(C4D_Vehicle), Find_NoContainer(), Find_Func("FitsInElevator")))
func IsMaster() { return partner && is_master && partner_was_synced; }
func IsSlave() { return partner && !is_master && partner_was_synced; }
func FxTryToSyncTimer(object target, effect, int time)
{
var diff = Abs(partner->GetY() - GetY());
if(diff > 5) return 1;
ExecuteSync();
return -1;
}
func FxCheckAutoMoveToTimer(object target, effect, int time)
{
if(!elevator) return -1;
if(IsSlave()) return 1;
if(!CheckIdle()) return 1;
if(GetEffect("MoveTo", this)) return 1;
// look for Clonks at shaft
var additional = 20;
var x = GetX() - additional;
var w = GetX() + additional;
var y = elevator->GetY();
var h = LandscapeHeight();
if(IsMaster())
{
if (GetEffect("ElevatorControl", vehicle)) continue;
vehicle->SetPosition(GetX(), GetY() + 12 - vehicle->GetObjHeight()/2 );
vehicle->SetSpeed();
vehicle->SetR();
AddEffect("ElevatorControl", vehicle, 30, 5, vehicle, nil, this);
x = Min(x, partner->GetX() - additional);
w = Max(w, partner->GetX() + additional);
}
// I'm a slave
if (slave) return elevator->CheckSlavery();
// Check for partner connection
if (partner && no_connection)
if (Inside(partner->GetY(), GetY()-1, GetY()+1))
{
no_connection = false;
partner.no_connection = false;
partner->SetPosition(partner->GetX(), GetY());
}
// Slave moved away?
if (HasReadyPartner())
if (partner->GetY() != GetY() && !drill) // This does crazy stuff when drilling
partner->SetPosition(partner->GetX(), GetY());
// no power?
if (!CurrentlyHasPower())
return;
// Slave has no power?
if (HasReadyPartner())
if (!partner->CurrentlyHasPower())
return;
// Start or stop drilling
if (drill && GetAction() == "Drive")
{
SetAction("Drill");
Sound("ElevatorDrilling", nil, nil, nil, 1);
if (HasReadyPartner())
partner->SetAction("Drill");
}
if (!drill && GetAction() == "Drill")
{
SetAction("Drive");
Sound("ElevatorDrilling", nil, nil, nil, -1);
if (HasReadyPartner())
partner->SetAction("Drive");
}
// Stop if at upmost position
if (GetY() - 20 <= elevator->GetY() && movement < 0)
{
if (GetYDir() < 0) Halt();
movement = 0;
SetPosition(GetX(), elevator->GetY() + 20);
ClearMoveTo();
if (HasReadyPartner()) partner->SetPosition(partner->GetX(), GetY());
return;
}
// Move or stop
if (movement && GetYDir() != this.Speed * movement)
{
if (movement < 0 && GetContact(-1) & CNAT_Top)
{
movement = 0;
} else if (movement > 0 && GetContact(-1) & CNAT_Bottom)
{
movement = 0;
} else
{
if (Abs(GetYDir()) == 1) elevator->StartEngine();
SetYDir(GetYDir() + movement);
if (HasReadyPartner()) partner->SetYDir(GetYDir());
return;
}
}
if (!movement && !move_to && GetYDir())
{
Halt();
}
// Idle?
if (!CheckIdle()) return;
// Move-to job?
if (move_to)
{
if (move_to_delay)
{
move_to_delay--;
if (move_to_target)
{
if (HasReadyPartner())
{
if (move_to_target->GetComDir() != COMD_Stop)
return ClearMoveTo();
if (AbsX(GetX() - move_to_target->GetX()) > 20)
if (AbsX(partner->GetX() - move_to_target->GetX()) > 20)
return ClearMoveTo();
}
else
{
if (move_to_target->GetComDir() != COMD_Stop || AbsX(GetX() - move_to_target->GetX()) > 20)
return ClearMoveTo();
}
}
if (!move_to_delay) move_to_target = nil;
return;
}
if (Inside(move_to, GetY()-2, GetY()+2))
{
ClearMoveTo();
Halt();
return;
}
if (move_to < GetY() && GetYDir() > -this.RushSpeed)
SetYDir(GetYDir() - 1);
if (move_to > GetY() && GetYDir() < this.RushSpeed)
SetYDir(GetYDir() + 1);
if (Abs(GetYDir()) == 1) elevator->StartEngine();
if (HasReadyPartner()) partner->SetYDir(GetYDir());
return;
}
// Search for waiting clonks
var clonk, best;
var in_rect = Find_InRect(-20, AbsY(elevator->GetY()), 40, LandscapeHeight() - elevator->GetY());
if (HasReadyPartner())
{
if (partner->GetX() < GetX())
in_rect = Find_InRect(-44, AbsY(elevator->GetY()), 56, LandscapeHeight() - elevator->GetY());
else
in_rect = Find_InRect(-20, AbsY(elevator->GetY()), 56, LandscapeHeight() - elevator->GetY());
}
for (clonk in FindObjects(in_rect, Find_OCF(OCF_CrewMember), Find_OCF(OCF_Alive), Find_NoContainer(), Find_Allied(GetOwner()), Sort_Distance(), Sort_Reverse()))
for (clonk in FindObjects(Find_InRect(x - GetX(), y - GetY(), w - x, h - y), Find_OCF(OCF_CrewMember), Find_OCF(OCF_Alive), Find_NoContainer(), Find_Allied(GetOwner()), Sort_Distance(), Sort_Reverse()))
{
var proc = clonk.Action.Procedure;
if (clonk->GetComDir() != COMD_Stop && !((proc == "SWIM") && Inside(clonk->GetXDir(), -5, 5)))
@ -252,7 +193,11 @@ func Movement()
if (clonk->GetY() > GetY() + 7)
if (!PathFree(GetX(), GetY() + 16, GetX(), clonk->GetY()))
continue;
if (clonk->GetY() > GetY() && GetContact(-1) & CNAT_Bottom) continue;
if ((clonk->GetY() > GetY()) && GetContact(-1, CNAT_Bottom)) continue;
// do not move to very close Clonks
if(Abs(GetY() - clonk->GetY()) < 5) continue;
// Priority rules: Cursor is better than no cursor, nearer is better than farer (Sort_Distance() & Sort_Reverse() do this)
// So unlike in CR's elevator, no distance check has to be done because later cycles are always nearer clonks
if (!best) best = clonk;
@ -261,31 +206,275 @@ func Movement()
else if (GetCursor(best->GetController()) != best)
best = clonk;
}
if (best) return MoveTo(best->GetY(), 35, best);
// Stop, why do you move?
Halt();
if (best)
MoveTo(best->GetY(), 10, best);
return 1;
}
func Halt(bool no_partner_call)
func FxElevatorUpperLimitCheckTimer(target, effect, time)
{
if (!elevator) return;
if (GetYDir() && !slave) elevator->StopEngine();
if(!elevator) return -1;
if(IsSlave()) return -1;
var d = GetY() - (elevator->GetY() + 20);
// HOW COULD THIS HAPPEN :C
if(d <= 0)
{
if(GetYDir() < 0)
{
SetPosition(GetX(), GetY() - d);
ForceSync();
ContactTop();
}
else
if(GetYDir() == 0)
SetPosition(GetX(), GetY() - d);
effect.Interval = 1;
return 1;
}
// everything okay, adjust timer accordingly
// check less often if far away from elevator
// note: d > 0
var t = BoundBy(d / 3, 1, 20);
effect.Interval = t;
return 1;
}
// for vehicle control
func OutOfRange(object vehicle)
{
if(Abs(GetY() - vehicle->GetY()) > 10) return true;
var min_x = GetX() - 12;
var max_x = GetX() + 12;
if(IsMaster())
{
min_x = Min(min_x, partner->GetX() - 12);
max_x = Max(max_x, partner->GetX() + 12);
}
if(vehicle->GetX() < min_x) return true;
if(vehicle->GetX() > max_x) return true;
return false;
}
func FxFetchVehiclesTimer(target, effect, time)
{
if(!elevator) return -1;
if(IsSlave()) return 1;
// look for vehicles
var additional = -5;
var x = GetX() - 12 - additional;
var w = GetX() + 12 + additional;
var y = GetY() - 12;
var h = GetY() + 15;
if(IsMaster())
{
x = Min(x, partner->GetX() - 12 - additional);
w = Max(w, partner->GetX() + 12 + additional);
}
// Fetch vehicles
for (var vehicle in FindObjects(Find_InRect(x - GetX(), y - GetY(), w - x, h - y), Find_Category(C4D_Vehicle), Find_NoContainer(), Find_Func("FitsInElevator")))
{
if (GetEffect("ElevatorControl", vehicle)) continue;
vehicle->SetPosition(vehicle->GetX(), GetY() + 12 - vehicle->GetObjHeight()/2);
vehicle->SetSpeed();
vehicle->SetR();
AddEffect("ElevatorControl", vehicle, 30, 5, vehicle, nil, this);
}
return 1;
}
/* Energy */
func GetNeededPower()
{
var p = Elevator_needed_power;
if(partner_was_synced) p = 2 * p;
return p;
}
// for the position
func GetActualPowerConsumer()
{
return elevator;
}
// the lift may not need power when not used
func QueryWaivePowerRequest()
{
// no clonk on elevator? must be automatic
if(CheckIdle()) return 20;
return 0;
}
func OnNotEnoughPower()
{
_inherited(...); // on purpose before the rest
if(GetYDir())
StoreMovementData();
else; // already has data stored
if(GetAction() != "DriveIdle")
Halt(false, true);
}
func OnEnoughPower()
{
_inherited(...); // on purpose before the rest
RestoreMovementData();
}
func StoreMovementData(int y_dir, string action, bool user_requested)
{
y_dir = y_dir ?? GetYDir();
action = action ?? GetAction();
user_requested = user_requested ?? !CheckIdle();
var e = GetEffect("StoredMovementData", this);
if(!e) e = AddEffect("StoredMovementData", this, 1, 0, this);
e.y_dir = y_dir;
e.action = action;
e.user_requested = user_requested;
}
func RestoreMovementData()
{
var e = GetEffect("StoredMovementData", this);
if(!e) return;
var drill = false;
if(e.action == "Drill")
drill = true;
SetMoveDirection(BoundBy(e.y_dir, -1, 1), e.user_requested, drill);
RemoveEffect(nil, this, e);
}
func SetMoveDirection(int dir, bool user_requested, bool drill)
{
if(IsSlave())
return partner->SetMoveSpeed(dir, user_requested, drill);
if(user_requested) StopAutomaticMovement();
var e;
if(e = GetEffect("StopPowerConsumption", this))
RemoveEffect(nil, this, e);
// no change?
if((dir < 0) && (GetYDir() < 0)) return;
if((dir > 0) && (GetYDir() > 0)) return;
// already reached top/bottom?
if(GetContact(-1, CNAT_Bottom) && (dir > 0) && !drill)
return;
if(GetContact(-1, CNAT_Top) && (dir < 0))
return;
if(dir == 0) return Halt();
var speed = case_speed;
// note: can not move down with full speed because of solidmask problem
// todo..
if(!user_requested && dir < 0) speed = case_speed_automatic;
var action = "Drive";
if(drill)
{
action = "Drill";
speed = GetDrillSpeed();
}
if(CurrentlyHasPower())
{
SetYDir(dir * speed);
SetAction(action);
ForceSync();
Sound("ElevatorStart");
elevator->StartEngine();
}
else
{
StoreMovementData(dir * speed, action);
MakePowerConsumer(GetNeededPower());
}
}
func Halt(bool user_requested, bool power_out)
{
if(IsSlave()) return;
StopAutomaticMovement();
if(GetYDir())
{
if(elevator)
elevator->StopEngine();
Sound("ElevatorStop");
}
// clear speed
SetAction("DriveIdle");
SetYDir();
if (no_partner_call && HasReadyPartner()) return SetPosition(GetX(), partner->GetY());
if (HasReadyPartner()) partner->Halt(true);
ForceSync();
if(user_requested)
{
UnmakePowerConsumer();
}
else
{
// if not stopped because of lack of power, stop consuming power
if(!power_out)
AddEffect("StopPowerConsumption", this, 1, 40, this);
}
}
func FxStopPowerConsumptionTimer(object target, effect, int time)
{
UnmakePowerConsumer();
return -1;
}
func ForceSync()
{
if(!IsMaster()) return;
// clear rounding errors
SetPosition(GetX(), GetY());
// adjust partner
partner->SetPosition(partner->GetX(), GetY());
partner->SetYDir(0);
}
func ContactTop()
{
Halt();
Sound("WoodHit*");
}
func ContactBottom()
{
// try to dig free
if(GetAction() == "Drill")
{
Drilling();
// wee!
if(!GetContact(-1, CNAT_Bottom))
{
SetYDir(GetDrillSpeed());
return;
}
}
Halt();
movement = 0;
drill = false;
ClearMoveTo();
Sound("WoodHit*");
}
// Checks whether the elevator should not move because someone's holding it
@ -293,10 +482,10 @@ func ContactBottom()
func CheckIdle()
{
// I have no mind of my own
if (slave) return true;
if(IsSlave()) return;
var in_rect = Find_InRect(-13, -13, 26, 26);
if (partner && !no_connection)
if (IsMaster())
{
if (partner->GetX() < GetX())
in_rect = Find_InRect(-39, -13, 52, 26);
@ -307,7 +496,8 @@ func CheckIdle()
{
if (pusher->GetActionTarget() == this) return false;
if (GetEffect("ElevatorControl", pusher->GetActionTarget()) && GetEffect("ElevatorControl", pusher->GetActionTarget()).case == this) return false;
if (partner && !no_connection)
if (IsMaster())
{
if (pusher->GetActionTarget() == partner) return false;
if (GetEffect("ElevatorControl", pusher->GetActionTarget()) && GetEffect("ElevatorControl", pusher->GetActionTarget()).case == partner) return false;
@ -316,88 +506,148 @@ func CheckIdle()
return true;
}
func StopAutomaticMovement()
{
var done = false;
if(GetEffect("MoveTo", this))
{
RemoveEffect("MoveTo", this);
done = true;
}
// todo: check if sensible
if(done) Halt();
}
// Moves the case to the specific y-coordinate
// delay in frames, so the elevator does not freak out
// target will be checked again for COMD_Stop and distance after delay run out
func MoveTo(int y, int delay, object target)
func MoveTo(int y, int delay, object target, bool user_requested)
{
// Not idle?
if (!CheckIdle()) return false;
if (!CheckIdle() && !user_requested) return false;
Halt();
move_to = BoundBy(y, elevator->GetY() + 20, LandscapeHeight());
move_to_delay = delay;
move_to_target = target;
var e = AddEffect("MoveTo", this, 1, 2, this);
e.delay = delay;
e.move_to_y = y;
e.target = target;
e.user_requested = user_requested;
return true;
}
func ClearMoveTo()
func FxMoveToTimer(target, effect, time)
{
move_to = nil;
move_to_target = nil;
move_to_delay = nil;
if(time < effect.delay) return 1;
// what would take more than 10 seconds?
if((time - effect.delay) / 36 > 10) return -1;
var y = effect.move_to_y;
if(effect.target) y = effect.target->GetY();
// target dead?
if(y == nil)
{
Halt();
return -1;
}
// target moves away from elevator shaft, finish movement but stop following
if(effect.target)
if(Abs(GetX() - effect.target->GetX()) > 100)
{
effect.move_to_y = effect.target->GetY();
effect.target = nil;
}
// destination reached
if(Abs(GetY() - y) < 5)
{
Halt();
return -1;
}
var dir = ElevatorCase_up;
if(y > GetY()) dir = ElevatorCase_down;
SetMoveDirection(dir, effect.user_requested, false);
return 1;
}
func HasReadyPartner()
func StartDrilling()
{
return partner && !no_connection;
SetAction("Drill");
}
func StopDrilling()
{
SetAction("Drive");
}
func Drilling()
{
var additional_y = 1;
var rect = Rectangle(GetX() - 12, GetY() - 13 - additional_y, GetX() + 12, GetY() + 13 + additional_y);
if(IsMaster())
{
rect.x = Min(rect.x, partner->GetX() - 12);
rect.y = Min(rect.y, partner->GetY() - 13 - additional_y);
rect.w = Max(rect.w, partner->GetX() + 12);
rect.h = Max(rect.h, partner->GetY() + 13 + additional_y);
}
DigFreeRect(rect.x, rect.y, rect.w - rect.x, rect.h - rect.y);
}
/* Controls */
local movement, drill;
func ControlUseStart(object clonk) // Drilling
func ControlUseStart(object clonk, int x, int y) // send elevator to position
{
if (slave) return Control2Master("ControlUseStart", clonk);
ClearMoveTo();
drill = true;
movement = 1;
return true;
if (IsSlave()) return Control2Master("ControlUseStart", clonk, x, y);
MoveTo(GetY() + y, 60, nil, true);
Sound("Click", nil, nil, clonk->GetOwner());
// does not want UseStop-callback
return false;
}
func ControlUseStop(object clonk)
{
if (slave) return Control2Master("ControlUseStop", clonk);
drill = false;
movement = 0;
return true;
}
func ControlDown(object clonk)
{
if (slave) return Control2Master("ControlDown", clonk);
ClearMoveTo();
if (!drill)
movement = 1;
if (IsSlave()) return Control2Master("ControlDown", clonk);
// pressing down when already on ground results in drilling
var drill = !!GetContact(-1, CNAT_Bottom);
SetMoveDirection(ElevatorCase_down, true, drill);
return true;
}
func ControlUp(object clonk)
{
if (slave) return Control2Master("ControlUp", clonk);
ClearMoveTo();
if (!drill)
movement = -1;
if (IsSlave()) return Control2Master("ControlUp", clonk);
// what is that player even doing
if(GetY() <= elevator->GetY() + 20)
{
Sound("Click", nil, nil, clonk->GetOwner());
return true;
}
SetMoveDirection(ElevatorCase_up, true, false);
return true;
}
func ControlStop(object clonk, int control)
{
if (slave) return Control2Master("ControlStop", clonk, control);
if (control == CON_Up || control == CON_Down)
{
if (!drill)
movement = 0;
return true;
}
if (IsSlave()) return Control2Master("ControlStop", clonk, control);
if(control == CON_Up && GetYDir() <= 0)
Halt(true);
else if(control == CON_Down && GetYDir() >= 0)
Halt(true);
return true;
}
func Control2Master(string call, object clonk, int control)
func Control2Master(string call, object clonk)
{
if (no_connection) return false;
return partner->Call(call, clonk, control);
if (!IsSlave()) return false;
return partner->Call(call, clonk, ...);
}
local ActMap = {
@ -410,7 +660,19 @@ local ActMap = {
Y = 0,
Wdt = 24,
Hgt = 26,
NextAction = "Drive"
NextAction = "Drive",
Sound = "ElevatorMoving"
},
DriveIdle = {
Prototype = Action,
Name = "DriveIdle",
Procedure = DFA_FLOAT,
Directions = 1,
X = 0,
Y = 0,
Wdt = 24,
Hgt = 26,
NextAction = "DriveIdle",
},
Drill = {
Prototype = Action,
@ -421,14 +683,27 @@ local ActMap = {
Y = 0,
Wdt = 24,
Hgt = 26,
Delay = 1,
Length = 1,
PhaseCall = "Drilling",
NextAction = "Drill",
Sound = "ElevatorDrilling",
DigFree = 1
},
Attach = {
Prototype = Action,
Name = "Attach",
Procedure = DFA_ATTACH,
Directions = 1,
X = 0,
Y = 0,
Wdt = 24,
Hgt = 26,
NextAction = "Attach"
}
};
local Name = "$Name$";
local Description = "$Description$";
local Touchable = 2;
local Speed = 15;
local RushSpeed = 20; // When moving on its own
local HitPoints = 50;

View File

@ -3,6 +3,9 @@
#include Library_Structure
#include Library_Ownable
// used in the elevator case
static const Elevator_needed_power = 50;
local case, rope;
local partner, slave;
@ -27,6 +30,7 @@ func Construction(object creator)
func Initialize()
{
SetCategory(C4D_StaticBack);
CreateCase();
CreateRope();
@ -36,7 +40,6 @@ func Initialize()
{
partner->LetsBecomeFriends(this);
slave = true; // Note: This is liberal slavery
case.slave = true; // I guess this is not so liberal
SetPosition(GetX(), partner->GetY());
}
else
@ -61,10 +64,19 @@ func CreateRope()
func Destruction()
{
rope->RemoveObject();
if(rope) rope->RemoveObject();
if(case) case->LostElevator();
if (partner) partner->LoseCombination();
}
func LostCase()
{
if(partner) partner->LoseCombination();
if(rope) rope->RemoveObject();
DoCon(-1);
}
/* Effects */
func StartEngine()
@ -119,7 +131,7 @@ func CombineWith(object other)
func LetsBecomeFriends(object other)
{
partner = other;
if (case) case->StartConnection(other);
if (case) case->StartConnection(other.case);
}
// Partner was destroyed or moved