Library: Switch, SwitchTarget

Standardized behavior for switches
install-platforms
Mark 2017-11-25 22:16:47 +01:00
parent c50d3b84a2
commit 41d45db9c2
29 changed files with 417 additions and 240 deletions

View File

@ -40,7 +40,7 @@ protected func Initialize()
DrawMaterialQuad("Tunnel-brickback", 688, 542, 688, 544, 696, 544, 696, 542);
gate->DoDamage(80); // Middle doors even easier
wheel = CreateObjectAbove(SpinWheel, 660, 552, NO_OWNER);
wheel->SetStoneDoor(gate);
wheel->SetSwitchTarget(gate);
gate = CreateObjectAbove(StoneDoor, lwidth - 364, 448, NO_OWNER);
DrawMaterialQuad("Tunnel-brickback", lwidth - 361, 446, lwidth - 361, 448, lwidth - 365, 448, lwidth - 365, 446);
@ -53,7 +53,7 @@ protected func Initialize()
DrawMaterialQuad("Tunnel-brickback", lwidth - 689, 542, lwidth - 689, 544, lwidth - 697, 544, lwidth - 697, 542);
gate->DoDamage(80); // Middle doors even easier
wheel = CreateObjectAbove(SpinWheel, lwidth - 660, 552, NO_OWNER);
wheel->SetStoneDoor(gate);
wheel->SetSwitchTarget(gate);
// Chests with weapons.
var chest;

View File

@ -5,7 +5,10 @@
@author Maikel
*/
local target_door, y_position;
#include Library_Switch
local y_position;
local up_action, down_action;
public func Initialize()
@ -42,26 +45,18 @@ public func CheckObjects()
{
if (desired_y == 0)
{
if (target_door)
target_door->CloseDoor();
SetSwitchState(false);
UserAction->EvaluateAction(up_action, this);
}
else if (desired_y == this.MoveDownDistance)
{
if (target_door)
target_door->OpenDoor();
SetSwitchState(true);
UserAction->EvaluateAction(down_action, this);
}
}
return;
}
public func SetStoneDoor(object door)
{
target_door = door;
return true;
}
public func SetActions(new_up_action, new_down_action)
{
up_action = new_up_action;
@ -75,7 +70,6 @@ public func SetActions(new_up_action, new_down_action)
public func SaveScenarioObject(proplist props)
{
if (!inherited(props, ...)) return false;
if (target_door) props->AddCall("Target", this, "SetStoneDoor", target_door);
if (up_action || down_action) props->AddCall("Action", this, "SetActions", up_action, down_action);
return true;
}
@ -86,7 +80,6 @@ public func SaveScenarioObject(proplist props)
public func Definition(proplist def)
{
if (!def.EditorProps) def.EditorProps = {};
def.EditorProps.target_door = { Name = "$Target$", Type = "object", Filter = "IsSwitchTarget" };
def.EditorProps.up_action = new UserAction.Prop { Name="$UpAction$" };
def.EditorProps.down_action = new UserAction.Prop { Name="$DownAction$" };
return _inherited(def, ...);
@ -99,4 +92,4 @@ local Name = "$Name$";
local Description = "$Description$";
local Plane = 200;
local SwitchMass = 100;
local MoveDownDistance = 3;
local MoveDownDistance = 3;

View File

@ -1,5 +1,4 @@
Name=Bodenschalter
Description=Antiker Gewichtssensor.
Target=Ziel
UpAction=Aktion 'Hoch'
DownAction=Aktion 'Runter'
Name=Bodenschalter
Description=Antiker Gewichtssensor.
UpAction=Aktion 'Hoch'
DownAction=Aktion 'Runter'

View File

@ -1,5 +1,4 @@
Name=Floor Switch
Description=Ancient weight sensor.
Target=Target
UpAction='Up' action
DownAction='Down' action
Name=Floor Switch
Description=Ancient weight sensor.
UpAction='Up' action
DownAction='Down' action

View File

@ -5,13 +5,14 @@
@author Maikel
*/
#include Library_Switch
// Background colors for hovering and bars and description.
static const KEYPADMENU_BackgroundColor = 0x77000000;
static const KEYPADMENU_HoverColor = 0x99888888;
static const KEYPADMENU_BarColor = 0x99888888;
local code, correct_code;
local target_door;
local correct_code_action, wrong_code_action;
local replacement_images;
local menu, menu_id, menu_target, menu_controller;
@ -39,26 +40,16 @@ public func SetKeypadCode(string to_code)
return;
}
public func SetStoneDoor(object door)
public func GiveAccess(object clonk)
{
target_door = door;
return true;
}
public func OpenDoor(object clonk)
{
SetPlrView(clonk->GetController(), target_door);
var y_off = target_door->~GetFloorOffset();
Global->CreateLight(target_door->GetX(), target_door->GetY() + y_off, 30, Fx_Light.LGT_Temp, clonk->GetController(), 30, 50);
target_door->OpenDoor();
SetSwitchState(true, clonk);
return;
}
public func OnCorrectCodeEntered(object clonk)
{
// Open door if specified.
if (target_door)
OpenDoor(clonk);
// Open door/switch on if specified.
GiveAccess(clonk);
// Perform user action last; it may delete the door/clonk/etc.
UserAction->EvaluateAction(correct_code_action, this, clonk);
return;
@ -126,7 +117,6 @@ public func SaveScenarioObject(proplist props)
{
if (!_inherited(props, ...)) return false;
if (correct_code) props->AddCall("Code", this, "SetKeypadCode", Format("%v", correct_code));
if (target_door) props->AddCall("Target", this, "SetStoneDoor", target_door);
if (correct_code_action || wrong_code_action) props->AddCall("Action", this, "SetCodeActions", correct_code_action, wrong_code_action);
if (replacement_images) props->AddCall("Replacements", this, "SetReplacementImages", replacement_images);
return true;
@ -140,7 +130,6 @@ public func Definition(proplist def)
if (!def.EditorProps)
def.EditorProps = {};
def.EditorProps.correct_code = { Name = "$KeypadCode$", Type = "string", Set="SetKeypadCode", EditorHelp = "$HelpKeypadCode$" };
def.EditorProps.target_door = { Name = "$KeypadTarget$", Type = "object", Filter = "IsSwitchTarget", EditorHelp = "$HelpKeypadTarget$" };
def.EditorProps.correct_code_action = new UserAction.Prop { Name = "$OnCorrectCodeAction$", EditorHelp = "$HelpOnCorrectCodeAction$" };
def.EditorProps.wrong_code_action = new UserAction.Prop { Name = "$OnWrongCodeAction$", EditorHelp = "$HelpOnWrongCodeAction$" };
return;

View File

@ -1,29 +1,28 @@
Name=Ziffernblock
Description=Richtiger Kennzahl eingeben um ein Ereignis aus zu lösen.
MsgEnterCode=Kennzahl eingeben:
MsgEnterNewCode=Neue Kennzahl:
MsgConfirmCode=Kennzahl bestätigen:
MsgNoCode=<c ffff00>Ziffernblock hat kein Kennzahl!</c>
MsgCorrectCode=<c 00ff00>Richtiger Kennzahl!</c>
MsgWrongCode=<c ff0000>Falscher Kennzahl!</c>
MsgCodeReset=<c 00ff00>Kennzahl wurde zurück gesetzt!</c>
MsgCodeConfirmed=<c 00ff00>Kennzahl bestätigt, jetzt zurücksetzen.</c>
TooltipDigit=Gebe Nummer ein.
TooltipCheck=Kontrolliere die eingebene Kennzahl.
TooltipClose=Schließe das Ziffernblock.
TooltipClearLast=Entferne die letzte Nummer.
TooltipClearCode=Eingegebene Kennzahl löschen.
TooltipResetCode=Die Kennzahl des Ziffernblocks zurücksetzen.
KeypadCode=Kennzahl
KeypadTarget=Ziel
OnCorrectCodeAction=Aktion 'richtige Kennzahl'
OnWrongCodeAction=Aktion 'falsche Kennzahl'
HelpKeypadCode=Gib den Kennzahl ein der vom Spieler eingetippt werden muss (darf nur Zahlen enthalten).
HelpKeypadTarget=Tür die geöffnet wird wenn den richtigen Kennzahl eingegeben wird.
HelpOnCorrectCodeAction=Aktion die ausgeführt wird wenn die richtige Kennzahl eingegeben wird.
HelpOnWrongCodeAction=Aktion die ausgeführt wird wenn eine falsche Kennzahl eingegeben wird.
WarningKeypadCodeNonDigit=WARNUNG: Kennzahl vom Ziffernblock (%s) enthält Charaktere die nicht Zahlen sind, Kennzahl wird nicht gesetzt.
Name=Ziffernblock
Description=Richtiger Kennzahl eingeben um ein Ereignis aus zu lösen.
MsgEnterCode=Kennzahl eingeben:
MsgEnterNewCode=Neue Kennzahl:
MsgConfirmCode=Kennzahl bestätigen:
MsgNoCode=<c ffff00>Ziffernblock hat kein Kennzahl!</c>
MsgCorrectCode=<c 00ff00>Richtiger Kennzahl!</c>
MsgWrongCode=<c ff0000>Falscher Kennzahl!</c>
MsgCodeReset=<c 00ff00>Kennzahl wurde zurück gesetzt!</c>
MsgCodeConfirmed=<c 00ff00>Kennzahl bestätigt, jetzt zurücksetzen.</c>
TooltipDigit=Gebe Nummer ein.
TooltipCheck=Kontrolliere die eingebene Kennzahl.
TooltipClose=Schließe das Ziffernblock.
TooltipClearLast=Entferne die letzte Nummer.
TooltipClearCode=Eingegebene Kennzahl löschen.
TooltipResetCode=Die Kennzahl des Ziffernblocks zurücksetzen.
KeypadCode=Kennzahl
OnCorrectCodeAction=Aktion 'richtige Kennzahl'
OnWrongCodeAction=Aktion 'falsche Kennzahl'
HelpKeypadCode=Gib den Kennzahl ein der vom Spieler eingetippt werden muss (darf nur Zahlen enthalten).
HelpKeypadTarget=Tür die geöffnet wird wenn den richtigen Kennzahl eingegeben wird.
HelpOnCorrectCodeAction=Aktion die ausgeführt wird wenn die richtige Kennzahl eingegeben wird.
HelpOnWrongCodeAction=Aktion die ausgeführt wird wenn eine falsche Kennzahl eingegeben wird.
WarningKeypadCodeNonDigit=WARNUNG: Kennzahl vom Ziffernblock (%s) enthält Charaktere die nicht Zahlen sind, Kennzahl wird nicht gesetzt.
WarningKeypadCodeLong=WARNUNG: Kennzahl vom Ziffernblock ist zu lang, nur %s wird gesetzt.

View File

@ -1,29 +1,28 @@
Name=Keypad
Description=Enter the correct code to trigger an event.
MsgEnterCode=Enter code:
MsgEnterNewCode=New code:
MsgConfirmCode=Confirm code:
MsgNoCode=<c ffff00>Keypad has no code!</c>
MsgCorrectCode=<c 00ff00>Correct code!</c>
MsgWrongCode=<c ff0000>Wrong code!</c>
MsgCodeReset=<c 00ff00>Code has been reset!</c>
MsgCodeConfirmed=<c 00ff00>Code confirmed, reset now.</c>
TooltipDigit=Enter digit.
TooltipCheck=Check the entered code.
TooltipClose=Close the keypad.
TooltipClearLast=Delete the last digit.
TooltipClearCode=Clear the entered code.
TooltipResetCode=Reset the keypad code.
KeypadCode=Code
KeypadTarget=Target
OnCorrectCodeAction=Action 'correct code'
OnWrongCodeAction=Action 'wrong code'
HelpKeypadCode=Enter the keypad code the player must type in (must be digits only).
HelpKeypadTarget=Target door that will be opened when the correct has been entered.
HelpOnCorrectCodeAction=Action to be executed when the correct code has been entered.
HelpOnWrongCodeAction=Action to be executed when a wrong code has been entered.
WarningKeypadCodeNonDigit=WARNING: keypad code (%s) contains some non-digit characters, code will not be set.
Name=Keypad
Description=Enter the correct code to trigger an event.
MsgEnterCode=Enter code:
MsgEnterNewCode=New code:
MsgConfirmCode=Confirm code:
MsgNoCode=<c ffff00>Keypad has no code!</c>
MsgCorrectCode=<c 00ff00>Correct code!</c>
MsgWrongCode=<c ff0000>Wrong code!</c>
MsgCodeReset=<c 00ff00>Code has been reset!</c>
MsgCodeConfirmed=<c 00ff00>Code confirmed, reset now.</c>
TooltipDigit=Enter digit.
TooltipCheck=Check the entered code.
TooltipClose=Close the keypad.
TooltipClearLast=Delete the last digit.
TooltipClearCode=Clear the entered code.
TooltipResetCode=Reset the keypad code.
KeypadCode=Code
OnCorrectCodeAction=Action 'correct code'
OnWrongCodeAction=Action 'wrong code'
HelpKeypadCode=Enter the keypad code the player must type in (must be digits only).
HelpKeypadTarget=Target door that will be opened when the correct has been entered.
HelpOnCorrectCodeAction=Action to be executed when the correct code has been entered.
HelpOnWrongCodeAction=Action to be executed when a wrong code has been entered.
WarningKeypadCodeNonDigit=WARNING: keypad code (%s) contains some non-digit characters, code will not be set.
WarningKeypadCodeLong=WARNING: keypad code is too long, only %s will be set.

View File

@ -1,6 +1,8 @@
/*-- Switch --*/
local target, handle, last_controlling_clonk;
#include Library_Switch
local handle, last_controlling_clonk;
public func Initialize()
{
@ -12,7 +14,6 @@ public func Initialize()
public func SaveScenarioObject(props)
{
if (!inherited(props, ...)) return false;
if (target) props->AddCall("Target", this, "SetTarget", target);
if (handle)
{
var pos = GetHandlePosition();
@ -22,12 +23,6 @@ public func SaveScenarioObject(props)
return true;
}
public func SetTarget(object trg)
{
target = trg;
return true;
}
public func SetActions(new_left_action, new_right_action)
{
left_action = new_left_action;
@ -35,14 +30,6 @@ public func SetActions(new_left_action, new_right_action)
return true;
}
public func ConnectNearestDoor()
{
// EditCursor helper command: Connect to nearest door. Return connected door.
var door = FindObject(Find_ID(StoneDoor), Sort_Distance());
if (door) SetTarget(door);
return door;
}
public func ControlUp(object clonk)
{
var dir = Rot2Dir(0,-1);
@ -73,7 +60,7 @@ public func ControlRight(object clonk)
private func ControlSwitchDir(object clonk, int dir)
{
if (!handle || (!target && !right_action && !left_action))
if (!handle || (!GetSwitchTarget() && !right_action && !left_action))
{
Sound("Structures::SwitchStuck");
Message("$MsgStuck$");
@ -128,7 +115,7 @@ public func SetR(int to_r)
private func SwitchingTimer(int dir)
{
if (!handle || (!target && !right_action && !left_action))
if (!handle || (!GetSwitchTarget() && !right_action && !left_action))
{
Sound("Structures::SwitchStuck");
return SetAction("Idle");
@ -154,17 +141,7 @@ private func DoSwitchFlip(object clonk, int dir)
if (dir > 0)
{
// Open/close should be aligned to vertical component of direction
if (target)
{
if (GetR() < 0)
{
target->~OpenDoor(this);
}
else
{
target->~CloseDoor(this);
}
}
SetSwitchState(GetR() < 0, clonk); // switch on if rotation < 0
// Action last; it may delete the door/clonk/etc.
if (right_action)
UserAction->EvaluateAction(right_action, this, clonk);
@ -172,17 +149,7 @@ private func DoSwitchFlip(object clonk, int dir)
else
{
// Open/close should be aligned to vertical component of direction
if (target)
{
if (GetR() < 0)
{
target->~CloseDoor(this);
}
else
{
target->~OpenDoor(this);
}
}
SetSwitchState(GetR() >= 0, clonk); // switch off if rotation < 0
// Action last; it may delete the door/clonk/etc.
if (left_action)
UserAction->EvaluateAction(left_action, this, clonk);
@ -226,19 +193,21 @@ local Components = { Rock = 3, Metal=1 };
local left_action, right_action; // Custom editor-selected actions on switch handling
local EditorActions = {
SwitchLeft = { Name = "$SwitchLeft$", Command = "ControlSwitchDir(nil, -1)" },
SwitchRight = { Name = "$SwitchRight$", Command = "ControlSwitchDir(nil, +1)" },
ConnectClosestDoor = { Name = "$ConnectNearestDoor$", Command = "ConnectNearestDoor()" },
Rotate = { Name = "$Rotate$", Command = "SetR((GetR()+135)/90*90)" }
};
func Definition(def)
{
// Graphics
SetProperty("PictureTransformation", Trans_Mul(Trans_Scale(800), Trans_Translate(0,0,0),Trans_Rotate(-20,1,0,0),Trans_Rotate(-30,0,1,0)), def);
SetProperty("MeshTransformation", Trans_Rotate(-13,0,1,0), def);
// Editor properties
if (!def.EditorProps) def.EditorProps = {};
def.EditorProps.target = { Name = "$Target$", Type = "object", Filter = "IsSwitchTarget" };
def.EditorProps.left_action = new UserAction.Prop { Name="$LeftAction$" };
def.EditorProps.right_action = new UserAction.Prop { Name="$RightAction$" };
// Actions
if (!def.EditorActions) def.EditorActions = {};
def.EditorActions.SwitchLeft = { Name = "$SwitchLeft$", Command = "ControlSwitchDir(nil, -1)" };
def.EditorActions.SwitchRight = { Name = "$SwitchRight$", Command = "ControlSwitchDir(nil, +1)" };
def.EditorActions.Rotate = { Name = "$Rotate$", Command = "SetR((GetR()+135)/90*90)" };
return _inherited(def, ...);
}

View File

@ -1,10 +1,8 @@
Name=Schalter
Description=Öffnet oder schließt Türen und andere Dinge. Bedienung mit Anfassen und Richtungstasten.
MsgStuck=Klemmt :(
SwitchLeft=Schalter links
SwitchRight=Schalter rechts
ConnectNearestDoor=Tuer verbinden
Rotate=Drehen
Target=Ziel
LeftAction=Aktion links
RightAction=Aktion rechts
Name=Schalter
Description=Öffnet oder schließt Türen und andere Dinge. Bedienung mit Anfassen und Richtungstasten.
MsgStuck=Klemmt :(
SwitchLeft=Schalter links
SwitchRight=Schalter rechts
Rotate=Drehen
LeftAction=Aktion links
RightAction=Aktion rechts

View File

@ -1,10 +1,8 @@
Name=Switch
Description=Opens and closes doors and other things. Grab and hit direction keys to control.
MsgStuck=Stuck :(
SwitchLeft=Switch left
SwitchRight=Switch right
ConnectNearestDoor=Connect door
Rotate=Rotate
Target=Target
LeftAction=Action left
RightAction=Action right
Name=Switch
Description=Opens and closes doors and other things. Grab and hit direction keys to control.
MsgStuck=Stuck :(
SwitchLeft=Switch left
SwitchRight=Switch right
Rotate=Rotate
LeftAction=Action left
RightAction=Action right

View File

@ -141,11 +141,11 @@ func InitializeObjects()
StoneDoor003->DoDamage(170);
var SpinWheel001 = CreateObjectAbove(SpinWheel, 961, 672);
SpinWheel001->SetStoneDoor(StoneDoor001);
SpinWheel001->SetSwitchTarget(StoneDoor001);
var SpinWheel002 = CreateObjectAbove(SpinWheel, 1367, 527);
SpinWheel002->SetStoneDoor(StoneDoor002);
SpinWheel002->SetSwitchTarget(StoneDoor002);
var SpinWheel003 = CreateObjectAbove(SpinWheel, 1384, 471);
SpinWheel003->SetStoneDoor(StoneDoor003);
SpinWheel003->SetSwitchTarget(StoneDoor003);
CreateObject(Column, 1197, 551);
CreateObject(Column, 1218, 463);

View File

@ -139,7 +139,7 @@ func InitializeObjects()
StoneDoor001->SetComDir(COMD_Down);
var SpinWheel001 = CreateObjectAbove(SpinWheel, 571, 1263);
SpinWheel001->SetStoneDoor(StoneDoor001);
SpinWheel001->SetSwitchTarget(StoneDoor001);
g_windmill = CreateObjectAbove(Windmill, 665, 351);
g_windmill->SetCategory(C4D_StaticBack);

View File

@ -541,33 +541,33 @@ func InitializeObjects()
var SpinWheel001 = CreateObjectAbove(SpinWheel, 589, 457);
SpinWheel001->SetMeshMaterial("SpinWheelGearRed", 0);
SpinWheel001->SetStoneDoor(StoneDoor001);
SpinWheel001->SetSwitchTarget(StoneDoor001);
var SpinWheel002 = CreateObjectAbove(SpinWheel, 611, 456);
SpinWheel002->SetMeshMaterial("SpinWheelGearBlue", 0);
SpinWheel002->SetStoneDoor(StoneDoor002);
SpinWheel002->SetSwitchTarget(StoneDoor002);
var SpinWheel003 = CreateObjectAbove(SpinWheel, 619, 410);
SpinWheel003->SetMeshMaterial("SpinWheelBaseAlt", 1);
SpinWheel003->SetStoneDoor(StoneDoor003);
SpinWheel003->SetSwitchTarget(StoneDoor003);
var SpinWheel004 = CreateObject(SpinWheel, 1223, 1545);
SpinWheel004->SetStoneDoor(StoneDoor005);
SpinWheel004->SetSwitchTarget(StoneDoor005);
var SpinWheel005 = CreateObjectAbove(SpinWheel, 1117, 1048);
SpinWheel005->SetStoneDoor(StoneDoor006);
SpinWheel005->SetSwitchTarget(StoneDoor006);
var SpinWheel006 = CreateObjectAbove(SpinWheel, 2761, 690);
SpinWheel006->SetMeshMaterial("SpinWheelBaseAlt", 1);
SpinWheel006->SetStoneDoor(StoneDoor008);
SpinWheel006->SetSwitchTarget(StoneDoor008);
var SpinWheel007 = CreateObjectAbove(SpinWheel, 1850, 1463);
SpinWheel007->SetMeshMaterial("SpinWheelGearRed", 0);
SpinWheel007->SetMeshMaterial("SpinWheelBaseAlt", 1);
SpinWheel007->SetStoneDoor(StoneDoor004);
SpinWheel007->SetSwitchTarget(StoneDoor004);
var SpinWheel008 = CreateObjectAbove(SpinWheel, 2793, 1521);
SpinWheel008->SetMeshMaterial("SpinWheelGearRed", 0);
SpinWheel008->SetMeshMaterial("SpinWheelBaseAlt", 1);
SpinWheel008->SetStoneDoor(StoneDoor007);
SpinWheel008->SetSwitchTarget(StoneDoor007);
var SpinWheel009 = CreateObjectAbove(SpinWheel, 830, 735);
SpinWheel009->SetStoneDoor(StoneDoor009);
SpinWheel009->SetSwitchTarget(StoneDoor009);
var SpinWheel010 = CreateObjectAbove(SpinWheel, 703, 352);
SpinWheel010->SetMeshMaterial("SpinWheelBaseAlt", 1);
SpinWheel010->SetStoneDoor(StoneDoor010);
SpinWheel010->SetSwitchTarget(StoneDoor010);
var Column002 = CreateObject(Column, 779, 488);
Column002->SetR(180);

View File

@ -0,0 +1,5 @@
[DefCore]
id=Library_Switch
Version=8,0
Category=C4D_StaticBack
HideInCreator=true

View File

@ -0,0 +1,119 @@
/**
Switch
Library for switches. Contains basic functionality:
- setting the object that gets operated
- switching the object on/off as a basic term for describing the operation
Needs to call _inherited in the following functions:
* Construction()
Additionally, if you define editor actions, define them in the Definition()
call. Otherwise, you will overwrite the editor actions that this library
defines, namely:
* connect nearest switch target
@author Marky
*/
local lib_switch;
// Legacy function, so that possible errors are avoided for now
private func SetStoneDoor(object target)
{
SetSwitchTarget(target);
return true;
}
/*-- Engine callbacks --*/
public func Construction(object by_object)
{
_inherited(by_object, ...);
lib_switch = {
switch_target = nil,
invert_signal = false, // setting this to true inverts the signal
};
}
/*-- Public Interface --*/
// Sets the object that is operated by this switch
public func SetSwitchTarget(object target)
{
lib_switch.switch_target = target;
}
// Gets the object that is operated by this switch
public func GetSwitchTarget()
{
return lib_switch.switch_target;
}
/*
Switches the object on or off. Does nothing if the object
is not connected to a switch.
Forwards the user = the object that is controlling the switch
and the switch to the switch target.
*/
public func SetSwitchState(bool state, object by_user)
{
if (GetSwitchTarget())
{
// Invert the state?
var actual_state = state != lib_switch.invert_signal;
// Forward to the target
GetSwitchTarget()->SetInputSignal(by_user, this, actual_state);
}
}
/*
Determines whether the switch signal should be inverted.
@par invert true: logic is inverted. SetSwitchState(true) switches the target off.
false: logic is as usual. SetSwitchState(true) switches the target on.
*/
public func SetInvertSwitchState(bool invert)
{
lib_switch.invert_signal = invert;
}
/*-- Saving --*/
public func SaveScenarioObject(proplist props)
{
if (!inherited(props, ...)) return false;
if (GetSwitchTarget()) props->AddCall("Target", this, "SetSwitchTarget", GetSwitchTarget());
if (lib_switch.invert_signal) props->AddCall("Invert", this, "SetInvertSwitchState", lib_switch.invert_signal);
return true;
}
/*-- Editor --*/
public func Definition(proplist def)
{
// Properties
if (!def.EditorProps) def.EditorProps = {};
def.EditorProps.switch_target = { Name = "$SwitchTarget$", Type = "object", Filter = "IsSwitchTarget" };
def.EditorProps.invert_signal = { Name = "$InvertSignal$", EditorHelp="$InvertSignalDesc$", Type="bool", Set="SetInvertSwitchState" };
// Actions
if (!def.EditorActions) def.EditorActions = {};
def.EditorActions.ConnectClosestSwitchTarget = { Name = "$ConnectClosestSwitchTarget$", Command = "ConnectClosestSwitchTarget()" };
return _inherited(def, ...);
}
func ConnectClosestSwitchTarget()
{
// EditCursor helper command: Connect to nearest switch target. Return connected target.
var target = FindObject(Find_Func("IsSwitchTarget"), Sort_Distance());
if (target) SetSwitchTarget(target);
return target;
}

View File

@ -0,0 +1,4 @@
SwitchTarget=Ziel des Schalters
InvertSignal=Schaltungslogik invertieren
InvertSignalDesc=Wenn ein Schalter ein Eingangssignal seinem Ziel setzt, dann übernimmt das Ziel stattdessen den invertierten Wert.
ConnectClosestSwitchTarget=Ziel verbinden

View File

@ -0,0 +1,4 @@
SwitchTarget=Target for the switch
InvertSignal=Invert switch logic
InvertSignalDesc=When a switch sets the input signal of its target the target instead uses the inverted value of the signal.
ConnectClosestSwitchTarget=Connect switch target

View File

@ -0,0 +1,5 @@
[DefCore]
id=Library_SwitchTarget
Version=8,0
Category=C4D_StaticBack
HideInCreator=true

View File

@ -0,0 +1,111 @@
/**
Mechanism
A mechanism is something that can be controlled via input signals.
* the input signal is sent by another object, which is usually a switch
* for simplicity, we currently allow one input signal
* for simplicity, we currently allow only boolean input signal
Needs to call _inherited in the following functions:
* Construction()
@author Marky
*/
local lib_mechanism;
/*-- Engine callbacks --*/
public func Construction(object by_object)
{
_inherited(by_object, ...);
lib_mechanism = {
old_signal = nil, // the last received signal
set_plr_view = true, // sets the player view to this object when the input signal changes
temp_light = nil, // temporary light, so that the player can see something when the object is being operated
};
}
/*-- Public Interface --*/
/*
Sets the input signal of this mechanism.
The function issues two callbacks to the object:
a) OnInputSignalChanged(operator, sender, value) => gets called only if the value changes
b) OnInputSignalSet(operator, sender, value) => gets called every time the signal is set
Use these callbacks to activate or deactivate certain functions in the mechanism.
For example, the stone door opens if you pass 'true', and closes if you pass 'false'
Usually only the signal changed callback should be relevant, but who knows. Callback b)
can be removed at any time if it turns out to be unnecessary.
@par operator this object is operating the mechanism or the object that sent the signal-
@par sender this object sent the signal - this is usually a switch.
@par value this value is sent.
*/
public func SetInputSignal(object operator, object sender, bool new_signal)
{
var self = this;
// Callback type 1: rising/falling edge
if (lib_mechanism.old_signal != new_signal)
{
this->~OnInputSignalChanged(operator, sender, new_signal);
lib_mechanism.old_signal = new_signal;
// Show the object being operated
if (self && operator && lib_mechanism.set_plr_view)
{
SetPlrView(operator->GetController(), this);
if (lib_mechanism.temp_light)
{
lib_mechanism.temp_light->RemoveObject();
}
lib_mechanism.temp_light = Global->CreateLight(this->GetX(), this->GetY() + this->~GetFloorOffset(), 30, Fx_Light.LGT_Temp, operator->GetController(), 30, 50);
}
}
// Callback type 2: current signal
if (self)
{
this->~OnInputSignalSet(operator, sender, new_signal);
}
}
/*
Determines whether the object should show that it is
being operated when the signal changes.
By default this is set to true.
*/
public func SetPlrViewOnSignalChange(bool show)
{
lib_mechanism.set_plr_view = show;
}
/*-- Saving --*/
public func SaveScenarioObject(proplist props)
{
if (!inherited(props, ...)) return false;
if (lib_mechanism.set_plr_view) props->AddCall("PlrView", this, "SetPlrViewOnSignalChange", lib_mechanism.set_plr_view);
return true;
}
/*-- Editor --*/
public func Definition(proplist def)
{
if (!def.EditorProps) def.EditorProps = {};
def.EditorProps.set_plr_view = { Name = "$SetPlrView$", EditorHelp="$SetPlrViewDesc$", Type="bool", Set="SetPlrViewOnSignalChange" };
return _inherited(def, ...);
}
/*-- Properties --*/
public func IsSwitchTarget() { return true; }

View File

@ -0,0 +1,2 @@
SetPlrView=Aktion zeigen
SetPlrViewDesc=Wenn der Mechanismus über ein Eingangssignal durch einen Spieler bedient wird, zeigt sich das bediente Objekt dem Spieler.

View File

@ -0,0 +1,2 @@
SetPlrView=Show action
SetPlrViewDesc=When the mechanism is operated by a player the player view focuses on that object.

View File

@ -5,6 +5,8 @@
@authors Ringwaul, Maikel
*/
#include Library_SwitchTarget
protected func Initialize()
{
SetAction("Door");
@ -58,6 +60,23 @@ private func ForceDigFree()
SetSolidMask(0, 0, 8, 40);
}
/*-- Switch control --*/
// Reaction to operation by a switch: if open_door is true the door opens, otherwise it closes
public func OnInputSignalChanged(object operator, object switch, bool open_door)
{
if (open_door)
{
OpenDoor();
}
else
{
CloseDoor();
}
_inherited(operator, switch, open_door, ...);
}
/*-- Automatic movement --*/
// Overrules owner control and only let's the team through.
@ -187,7 +206,6 @@ private func EvalAct_CloseDoor(props, context)
/* Properties */
public func IsSwitchTarget() { return true; }
public func IsDoor() { return true; }
local ActMap = {

View File

@ -1,30 +1,17 @@
/*-- Spin Wheel --*/
local targetdoor, temp_light;
#include Library_Switch
public func Initialize()
{
SetAction("Still");
}
public func SetStoneDoor(object door)
{
targetdoor = door;
return true;
}
public func ControlUp(object clonk)
{
if (GetAction() == "Still" && targetdoor)
if (GetAction() == "Still" && GetSwitchTarget())
{
if (clonk)
{
SetPlrView(clonk->GetController(), targetdoor);
if (temp_light) temp_light->RemoveObject();
var y_off = targetdoor->~GetFloorOffset();
temp_light = Global->CreateLight(targetdoor->GetX(), targetdoor->GetY() + y_off, 30, Fx_Light.LGT_Temp, clonk->GetController(), 30, 50);
}
targetdoor->OpenDoor();
SetSwitchState(true, clonk);
SetAction("SpinLeft");
Sound("Structures::StoneGate::Chain");
}
@ -34,16 +21,9 @@ public func ControlUp(object clonk)
public func ControlDown(object clonk)
{
if (GetAction() == "Still" && targetdoor)
if (GetAction() == "Still" && GetSwitchTarget())
{
if (clonk)
{
SetPlrView(clonk->GetController(), targetdoor);
if (temp_light) temp_light->RemoveObject();
var y_off = targetdoor->~GetFloorOffset();
temp_light = Global->CreateLight(targetdoor->GetX(), targetdoor->GetY() + y_off, 30, Fx_Light.LGT_Temp, clonk->GetController(), 30, 50);
}
targetdoor->CloseDoor();
SetSwitchState(false, clonk);
SetAction("SpinRight");
Sound("Structures::StoneGate::Chain");
}
@ -54,7 +34,6 @@ public func ControlDown(object clonk)
public func SaveScenarioObject(props)
{
if (!inherited(props, ...)) return false;
if (targetdoor) props->AddCall("Target", this, "SetStoneDoor", targetdoor);
if (up_action || down_action) props->AddCall("Action", this, "SetActions", up_action, down_action);
return true;
}
@ -66,14 +45,6 @@ public func SetActions(new_up_action, new_down_action)
return true;
}
func ConnectNearestDoor()
{
// EditCursor helper command: Connect to nearest door. Return connected door.
var door = FindObject(Find_ID(StoneDoor), Sort_Distance());
if (door) SetStoneDoor(door);
return door;
}
local ActMap = {
Still = {
Prototype = Action,
@ -110,21 +81,18 @@ local Plane = 200;
local Components = {Wood = 3, Metal = 1};
local up_action, down_action; // Custom editor-selected actions on switch handling
local EditorActions = {
SwitchLeft = { Name = "$ControlUp$", Command = "ControlUp()" },
SwitchRight = { Name = "$ControlDown$", Command = "ControlDown()" },
ConnectClosestDoor = { Name = "$ConnectNearestDoor$", Command = "ConnectNearestDoor()" }
};
func Definition(def)
{
// Graphics
SetProperty("PictureTransformation", Trans_Mul(Trans_Scale(800), Trans_Translate(0,0,0),Trans_Rotate(-20,1,0,0),Trans_Rotate(-30,0,1,0)), def);
SetProperty("MeshTransformation", Trans_Rotate(-13,0,1,0), def);
// Editor properties
if (!def.EditorProps) def.EditorProps = {};
def.EditorProps.targetdoor = { Name = "$Target$", Type = "object", Filter = "IsSwitchTarget" };
def.EditorProps.up_action = new UserAction.Prop { Name="$UpAction$" };
def.EditorProps.down_action = new UserAction.Prop { Name="$DownAction$" };
// Editor actions
if (!def.EditorActions) def.EditorActions = {};
def.EditorActions.SwitchLeft = { Name = "$ControlUp$", Command = "ControlUp()" };
def.EditorActions.SwitchRight = { Name = "$ControlDown$", Command = "ControlDown()" };
return _inherited(def, ...);
}

View File

@ -1,8 +1,6 @@
Name=Winde
Description=Öffne oder schließe die verbundene Burgtür mit [Hoch] oder [Runter].
Target=Ziel
UpAction=Aktion 'Hoch'
DownAction=Aktion 'Runter'
ConnectNearestDoor=Tuer verbinden
ControlUp=Winde hoch
ControlDown=Winde runter

View File

@ -1,8 +1,6 @@
Name=Spin Wheel
Description=Open and close connected castle door with [Up] and [Down] respectively.
Target=Target
UpAction='Up' action
DownAction='Down' action
ConnectNearestDoor=Connect door
ControlUp=Wheel up
ControlDown=Wheel down

View File

@ -173,7 +173,7 @@ private func Doors()
var gate = CreateObjectAbove(StoneDoor, 865, 1195, NO_OWNER);
var wheel = CreateObjectAbove(SpinWheel, 1045, 1165, NO_OWNER);
wheel->SetStoneDoor(gate);
wheel->SetSwitchTarget(gate);
gate->CloseDoor();
AddEffect("SparklingAttention",wheel,100,100);
@ -188,48 +188,48 @@ private func Doors()
var gate = CreateObjectAbove(StoneDoor, 1875, 761, NO_OWNER);
var wheel = CreateObjectAbove(SpinWheel, 1752, 1148, NO_OWNER);
wheel->SetStoneDoor(gate);
wheel->SetSwitchTarget(gate);
gate->CloseDoor();
AddEffect("SparklingAttention",wheel,100,100);
var gate = CreateObjectAbove(StoneDoor, 1875, 864, NO_OWNER);
var wheel = CreateObjectAbove(SpinWheel, 1116, 1038, NO_OWNER);
wheel->SetStoneDoor(gate);
wheel->SetSwitchTarget(gate);
gate->CloseDoor();
AddEffect("SparklingAttention",wheel,100,100);
var gate = CreateObjectAbove(StoneDoor, 3115, 685, NO_OWNER);
var wheel = CreateObjectAbove(SpinWheel, 3140, 588, NO_OWNER);
wheel->SetStoneDoor(gate);
wheel->SetSwitchTarget(gate);
gate->CloseDoor();
AddEffect("SparklingAttention",wheel,100,100);
var gate = CreateObjectAbove(StoneDoor, 585, 915, NO_OWNER);
var wheel = CreateObjectAbove(SpinWheel, 853, 681, NO_OWNER);
wheel->SetStoneDoor(gate);
wheel->SetSwitchTarget(gate);
gate->CloseDoor();
AddEffect("SparklingAttention",wheel,100,100);
var gate = CreateObjectAbove(StoneDoor, 345, 740, NO_OWNER);
var wheel = CreateObjectAbove(SpinWheel, 60, 644, NO_OWNER);
wheel->SetStoneDoor(gate);
wheel->SetSwitchTarget(gate);
gate->CloseDoor();
AddEffect("SparklingAttention",wheel,100,100);
var gate = CreateObjectAbove(StoneDoor, 1935, 558, NO_OWNER);
var wheel = CreateObjectAbove(SpinWheel, 1900, 565, NO_OWNER);
wheel->SetStoneDoor(gate);
wheel->SetSwitchTarget(gate);
gate->CloseDoor();
AddEffect("SparklingAttention",wheel,100,100);
var gate = CreateObjectAbove(StoneDoor, 2965, 316, NO_OWNER);
var wheel = CreateObjectAbove(SpinWheel, 3260, 328, NO_OWNER);
wheel->SetStoneDoor(gate);
wheel->SetSwitchTarget(gate);
gate->CloseDoor();
var gate = CreateObjectAbove(StoneDoor, 3285, 1150, NO_OWNER);
var wheel = CreateObjectAbove(SpinWheel, 3220, 1200, NO_OWNER);
wheel->SetStoneDoor(gate);
wheel->SetSwitchTarget(gate);
gate->CloseDoor();
}

View File

@ -136,11 +136,11 @@ func InitializeObjects()
StoneDoor003->SetComDir(COMD_Down);
var SpinWheel001 = CreateObjectAbove(SpinWheel, 961, 672);
SpinWheel001->SetStoneDoor(StoneDoor001);
SpinWheel001->SetSwitchTarget(StoneDoor001);
var SpinWheel002 = CreateObjectAbove(SpinWheel, 1367, 527);
SpinWheel002->SetStoneDoor(StoneDoor002);
SpinWheel002->SetSwitchTarget(StoneDoor002);
var SpinWheel003 = CreateObjectAbove(SpinWheel, 1384, 471);
SpinWheel003->SetStoneDoor(StoneDoor003);
SpinWheel003->SetSwitchTarget(StoneDoor003);
CreateObject(Column, 1197, 551);
CreateObject(Column, 1218, 463);

View File

@ -115,7 +115,7 @@ private func InitVillageMain()
// Stone door to protect the village.
var door = CreateObjectAbove(StoneDoor, 1004, 376);
var wheel = CreateObjectAbove(SpinWheel, 972, 376);
wheel->SetStoneDoor(door);
wheel->SetSwitchTarget(door);
// A tree is blocking the path down in this round.
CreateObject(MovingBrick, 870, 396).Plane = 200;

View File

@ -94,7 +94,7 @@ private func InitVillageMain()
// Stone door to protect the village.
var door = CreateObjectAbove(StoneDoor, 1004, 376);
var wheel = CreateObjectAbove(SpinWheel, 972, 376);
wheel->SetStoneDoor(door);
wheel->SetSwitchTarget(door);
// Tools and armory down below.
CreateObjectAbove(ToolsWorkshop, 698, 504)->MakeInvincible();