summaryrefslogtreecommitdiffstats
path: root/Items.c4d/Sensors.c4d
diff options
context:
space:
mode:
Diffstat (limited to 'Items.c4d/Sensors.c4d')
-rw-r--r--Items.c4d/Sensors.c4d/Button.c4d/ActMap.txt6
-rw-r--r--Items.c4d/Sensors.c4d/Button.c4d/DefCore.txt19
-rw-r--r--Items.c4d/Sensors.c4d/Button.c4d/DescDE.txt1
-rw-r--r--Items.c4d/Sensors.c4d/Button.c4d/DescUS.txt1
-rw-r--r--Items.c4d/Sensors.c4d/Button.c4d/Graphics.pngbin0 -> 2832 bytes
-rw-r--r--Items.c4d/Sensors.c4d/Button.c4d/Names.txt2
-rw-r--r--Items.c4d/Sensors.c4d/Button.c4d/Script.c17
-rw-r--r--Items.c4d/Sensors.c4d/Button.c4d/StringTblDE.txt1
-rw-r--r--Items.c4d/Sensors.c4d/Button.c4d/StringTblUS.txt1
-rw-r--r--Items.c4d/Sensors.c4d/CardReader.c4d/DefCore.txt20
-rw-r--r--Items.c4d/Sensors.c4d/CardReader.c4d/Graphics.pngbin0 -> 2119 bytes
-rw-r--r--Items.c4d/Sensors.c4d/CardReader.c4d/GraphicsCard.pngbin0 -> 176 bytes
-rw-r--r--Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/DefCore.txt21
-rw-r--r--Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Graphics.pngbin0 -> 2238 bytes
-rw-r--r--Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Names.txt2
-rw-r--r--Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Overlay.pngbin0 -> 2580 bytes
-rw-r--r--Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Script.c109
-rw-r--r--Items.c4d/Sensors.c4d/CardReader.c4d/Names.txt2
-rw-r--r--Items.c4d/Sensors.c4d/CardReader.c4d/Overlay.pngbin0 -> 325 bytes
-rw-r--r--Items.c4d/Sensors.c4d/CardReader.c4d/OverlayCard.pngbin0 -> 174 bytes
-rw-r--r--Items.c4d/Sensors.c4d/CardReader.c4d/Script.c193
-rw-r--r--Items.c4d/Sensors.c4d/CardReader.c4d/StringTblDE.txt7
-rw-r--r--Items.c4d/Sensors.c4d/CardReader.c4d/StringTblUS.txt7
-rw-r--r--Items.c4d/Sensors.c4d/CodeInput.c4d/DefCore.txt19
-rw-r--r--Items.c4d/Sensors.c4d/CodeInput.c4d/Graphics.pngbin0 -> 3811 bytes
-rw-r--r--Items.c4d/Sensors.c4d/CodeInput.c4d/Names.txt2
-rw-r--r--Items.c4d/Sensors.c4d/CodeInput.c4d/Script.c138
-rw-r--r--Items.c4d/Sensors.c4d/CodeInput.c4d/StringTblDE.txt9
-rw-r--r--Items.c4d/Sensors.c4d/CodeInput.c4d/StringTblUS.txt9
-rw-r--r--Items.c4d/Sensors.c4d/FingerprintSensor.c4d/DefCore.txt19
-rw-r--r--Items.c4d/Sensors.c4d/FingerprintSensor.c4d/Graphics.pngbin0 -> 3430 bytes
-rw-r--r--Items.c4d/Sensors.c4d/FingerprintSensor.c4d/Names.txt2
-rw-r--r--Items.c4d/Sensors.c4d/FingerprintSensor.c4d/Script.c172
-rw-r--r--Items.c4d/Sensors.c4d/FingerprintSensor.c4d/StringTblDE.txt6
-rw-r--r--Items.c4d/Sensors.c4d/FingerprintSensor.c4d/StringTblUS.txt6
-rw-r--r--Items.c4d/Sensors.c4d/LiquidSensor.c4d/DefCore.txt19
-rw-r--r--Items.c4d/Sensors.c4d/LiquidSensor.c4d/Graphics.pngbin0 -> 4311 bytes
-rw-r--r--Items.c4d/Sensors.c4d/LiquidSensor.c4d/Names.txt2
-rw-r--r--Items.c4d/Sensors.c4d/LiquidSensor.c4d/Script.c45
-rw-r--r--Items.c4d/Sensors.c4d/LiquidSensor.c4d/StringTblDE.txt3
-rw-r--r--Items.c4d/Sensors.c4d/LiquidSensor.c4d/StringTblUS.txt3
-rw-r--r--Items.c4d/Sensors.c4d/LivingSensor.c4d/DefCore.txt18
-rw-r--r--Items.c4d/Sensors.c4d/LivingSensor.c4d/Graphics.pngbin0 -> 3709 bytes
-rw-r--r--Items.c4d/Sensors.c4d/LivingSensor.c4d/Names.txt2
-rw-r--r--Items.c4d/Sensors.c4d/LivingSensor.c4d/Script.c112
-rw-r--r--Items.c4d/Sensors.c4d/LivingSensor.c4d/StringTblDE.txt7
-rw-r--r--Items.c4d/Sensors.c4d/LivingSensor.c4d/StringTblUS.txt7
-rw-r--r--Items.c4d/Sensors.c4d/Names.txt2
-rw-r--r--Items.c4d/Sensors.c4d/ObjectSensor.c4d/ActMap.txt3
-rw-r--r--Items.c4d/Sensors.c4d/ObjectSensor.c4d/DefCore.txt19
-rw-r--r--Items.c4d/Sensors.c4d/ObjectSensor.c4d/Graphics.pngbin0 -> 4295 bytes
-rw-r--r--Items.c4d/Sensors.c4d/ObjectSensor.c4d/Names.txt2
-rw-r--r--Items.c4d/Sensors.c4d/ObjectSensor.c4d/Script.c292
-rw-r--r--Items.c4d/Sensors.c4d/ObjectSensor.c4d/StringTblDE.txt17
-rw-r--r--Items.c4d/Sensors.c4d/ObjectSensor.c4d/StringTblUS.txt15
-rw-r--r--Items.c4d/Sensors.c4d/RC.c4d/ActMap.txt4
-rw-r--r--Items.c4d/Sensors.c4d/RC.c4d/DefCore.txt21
-rw-r--r--Items.c4d/Sensors.c4d/RC.c4d/Graphics.pngbin0 -> 2347 bytes
-rw-r--r--Items.c4d/Sensors.c4d/RC.c4d/Graphics.svg311
-rw-r--r--Items.c4d/Sensors.c4d/RC.c4d/Names.txt2
-rw-r--r--Items.c4d/Sensors.c4d/RC.c4d/Script.c721
-rw-r--r--Items.c4d/Sensors.c4d/RC.c4d/StringTblDE.txt39
-rw-r--r--Items.c4d/Sensors.c4d/RC.c4d/StringTblUS.txt39
-rw-r--r--Items.c4d/Sensors.c4d/Sensor.c4d/DefCore.txt4
-rw-r--r--Items.c4d/Sensors.c4d/Sensor.c4d/Graphics.pngbin0 -> 126 bytes
-rw-r--r--Items.c4d/Sensors.c4d/Sensor.c4d/Script.c791
-rw-r--r--Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/ActMap.txt4
-rw-r--r--Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/DefCore.txt8
-rw-r--r--Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/Graphics.pngbin0 -> 129 bytes
-rw-r--r--Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/Script.c33
-rw-r--r--Items.c4d/Sensors.c4d/Sensor.c4d/StringTblDE.txt19
-rw-r--r--Items.c4d/Sensors.c4d/Sensor.c4d/StringTblUS.txt19
-rw-r--r--Items.c4d/Sensors.c4d/Switch.c4d/ActMap.txt3
-rw-r--r--Items.c4d/Sensors.c4d/Switch.c4d/DefCore.txt19
-rw-r--r--Items.c4d/Sensors.c4d/Switch.c4d/Graphics.pngbin0 -> 2872 bytes
-rw-r--r--Items.c4d/Sensors.c4d/Switch.c4d/Names.txt2
-rw-r--r--Items.c4d/Sensors.c4d/Switch.c4d/Script.c21
-rw-r--r--Items.c4d/Sensors.c4d/Switch.c4d/StringTblDE.txt4
-rw-r--r--Items.c4d/Sensors.c4d/Switch.c4d/StringTblUS.txt4
-rw-r--r--Items.c4d/Sensors.c4d/Timer.c4d/ActMap.txt7
-rw-r--r--Items.c4d/Sensors.c4d/Timer.c4d/DefCore.txt18
-rw-r--r--Items.c4d/Sensors.c4d/Timer.c4d/Graphics.pngbin0 -> 3860 bytes
-rw-r--r--Items.c4d/Sensors.c4d/Timer.c4d/Names.txt2
-rw-r--r--Items.c4d/Sensors.c4d/Timer.c4d/Script.c112
-rw-r--r--Items.c4d/Sensors.c4d/Timer.c4d/StringTblDE.txt8
-rw-r--r--Items.c4d/Sensors.c4d/Timer.c4d/StringTblUS.txt8
86 files changed, 3582 insertions, 0 deletions
diff --git a/Items.c4d/Sensors.c4d/Button.c4d/ActMap.txt b/Items.c4d/Sensors.c4d/Button.c4d/ActMap.txt
new file mode 100644
index 0000000..176c2e1
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Button.c4d/ActMap.txt
@@ -0,0 +1,6 @@
+[Action]
+Name=Pressed
+NextAction=Idle
+Delay=10
+Length=1
+Facet=0,4,10,4
diff --git a/Items.c4d/Sensors.c4d/Button.c4d/DefCore.txt b/Items.c4d/Sensors.c4d/Button.c4d/DefCore.txt
new file mode 100644
index 0000000..1e034e3
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Button.c4d/DefCore.txt
@@ -0,0 +1,19 @@
+[DefCore]
+id=BS7I
+Name=Button
+Version=4,9,5
+Category=C4D_Object|C4D_SelectMaterial|C4D_SelectKnowledge|C4D_SelectHomebase
+Width=10
+Height=4
+Offset=-5,-2
+Mass=10
+Value=5
+Components=METL=1;
+Picture=10,0,64,64
+Vertices=1
+VertexFriction=100
+Grab=2
+Collectible=1
+MaxUserSelect=10
+Rebuy=1
+NoPushEnter=1
diff --git a/Items.c4d/Sensors.c4d/Button.c4d/DescDE.txt b/Items.c4d/Sensors.c4d/Button.c4d/DescDE.txt
new file mode 100644
index 0000000..f888c1d
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Button.c4d/DescDE.txt
@@ -0,0 +1 @@
+Drücken zum Knopfen. \ No newline at end of file
diff --git a/Items.c4d/Sensors.c4d/Button.c4d/DescUS.txt b/Items.c4d/Sensors.c4d/Button.c4d/DescUS.txt
new file mode 100644
index 0000000..eeda4e0
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Button.c4d/DescUS.txt
@@ -0,0 +1 @@
+Press to switch. \ No newline at end of file
diff --git a/Items.c4d/Sensors.c4d/Button.c4d/Graphics.png b/Items.c4d/Sensors.c4d/Button.c4d/Graphics.png
new file mode 100644
index 0000000..554a751
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Button.c4d/Graphics.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/Button.c4d/Names.txt b/Items.c4d/Sensors.c4d/Button.c4d/Names.txt
new file mode 100644
index 0000000..2d14836
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Button.c4d/Names.txt
@@ -0,0 +1,2 @@
+DE:Knopf
+US:Button \ No newline at end of file
diff --git a/Items.c4d/Sensors.c4d/Button.c4d/Script.c b/Items.c4d/Sensors.c4d/Button.c4d/Script.c
new file mode 100644
index 0000000..68dcaea
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Button.c4d/Script.c
@@ -0,0 +1,17 @@
+#strict 2
+#include SN7I
+
+func Triggers() { return [["$Press$"]];}
+
+func ControlThrow(object caller)
+{
+ SetAction("Pressed");
+ Sound("Grab");
+ Trigger(0, caller);
+ return ClearCom(caller);
+}
+func ControlThrowDouble() { return ControlThrow(...); }
+
+func EntranceCallback() { return "ControlThrow"; }
+
+func SensorCallbacks() { return [["$Press$", "ControlThrow"]]; }
diff --git a/Items.c4d/Sensors.c4d/Button.c4d/StringTblDE.txt b/Items.c4d/Sensors.c4d/Button.c4d/StringTblDE.txt
new file mode 100644
index 0000000..793a24a
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Button.c4d/StringTblDE.txt
@@ -0,0 +1 @@
+Press=Drücken
diff --git a/Items.c4d/Sensors.c4d/Button.c4d/StringTblUS.txt b/Items.c4d/Sensors.c4d/Button.c4d/StringTblUS.txt
new file mode 100644
index 0000000..690c11f
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Button.c4d/StringTblUS.txt
@@ -0,0 +1 @@
+Press=Press
diff --git a/Items.c4d/Sensors.c4d/CardReader.c4d/DefCore.txt b/Items.c4d/Sensors.c4d/CardReader.c4d/DefCore.txt
new file mode 100644
index 0000000..c202c8f
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CardReader.c4d/DefCore.txt
@@ -0,0 +1,20 @@
+[DefCore]
+id=CR7I
+Name=Card Reader
+Version=4,9,5
+Category=C4D_Object|C4D_SelectMaterial|C4D_SelectKnowledge|C4D_SelectHomebase
+Width=10
+Height=5
+Offset=-5,-2
+Mass=10
+Value=5
+Components=METL=1;
+Picture=0,5,64,64
+Vertices=1
+VertexFriction=100
+Grab=2
+Collectible=1
+MaxUserSelect=10
+Rebuy=1
+NoPushEnter=1
+ColorByOwner=1
diff --git a/Items.c4d/Sensors.c4d/CardReader.c4d/Graphics.png b/Items.c4d/Sensors.c4d/CardReader.c4d/Graphics.png
new file mode 100644
index 0000000..0fea303
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CardReader.c4d/Graphics.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/CardReader.c4d/GraphicsCard.png b/Items.c4d/Sensors.c4d/CardReader.c4d/GraphicsCard.png
new file mode 100644
index 0000000..9e67d34
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CardReader.c4d/GraphicsCard.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/DefCore.txt b/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/DefCore.txt
new file mode 100644
index 0000000..c626851
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/DefCore.txt
@@ -0,0 +1,21 @@
+[DefCore]
+id=KC7I
+Name=Keycard
+Version=4,9,5
+Category=C4D_Object|C4D_SelectMaterial|C4D_SelectKnowledge|C4D_SelectHomebase
+MaxUserSelect=10
+Width=8
+Height=5
+Offset=-4,-3
+Value=10
+Mass=10
+Components=METL=1;
+Picture=0,5,64,48
+Vertices=2
+VertexX=-4,4
+VertexY=0,0
+VertexFriction=60,60
+Rebuy=1
+Collectible=1
+Rotate=1
+ColorByOwner=1
diff --git a/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Graphics.png b/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Graphics.png
new file mode 100644
index 0000000..2d9c553
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Graphics.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Names.txt b/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Names.txt
new file mode 100644
index 0000000..ea9589e
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Names.txt
@@ -0,0 +1,2 @@
+DE:Schlüsselkarte
+US:Key card \ No newline at end of file
diff --git a/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Overlay.png b/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Overlay.png
new file mode 100644
index 0000000..acdeab5
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Overlay.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Script.c b/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Script.c
new file mode 100644
index 0000000..bd604c3
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CardReader.c4d/Keycard.c4d/Script.c
@@ -0,0 +1,109 @@
+#strict 2
+
+local readers;
+local color;
+
+func Initialize()
+{
+ readers = [];
+ ResetColor();
+}
+
+func ResetColor()
+{
+ SetColor(RGB(255, 255, 255));
+}
+
+func OnOwnerChanged()
+{
+ SetColorDw(color);
+}
+
+func HasReader(object reader)
+{
+ return GetIndexOf(reader, readers) != -1;
+}
+
+func CleanRemovedReaders()
+{
+ ArrayEraseItem(readers, 0, true);
+}
+
+func AddReader(object reader)
+{
+ if(!HasReader(reader))
+ {
+ readers[GetLength(readers)] = reader;
+ CleanRemovedReaders();
+ if(GetLength(readers) == 1)
+ {
+ SetColor(reader->GetColor());
+ }
+ }
+ return true;
+}
+
+func RemoveReader(object reader)
+{
+ ArrayEraseItem(readers, reader);
+ CleanRemovedReaders();
+ if(color == reader->GetColor())
+ {
+ if(GetLength(readers) > 0)
+ {
+ SetColor(readers[0]->GetColor());
+ }
+ else
+ {
+ ResetColor();
+ }
+ }
+ return true;
+}
+
+func SetColor(int newColor)
+{
+ color = newColor;
+ SetColorDw(newColor);
+}
+
+func Selection()
+{
+ if(GetLength(readers))
+ {
+ var first = true, descList = "";
+ for(var reader in readers)
+ {
+ if(reader)
+ {
+ Contained()->CreateSelectMark()->MarkObject(reader, 35);
+ var desc = reader->GetDescription() || "";
+ if(!first)
+ {
+ descList = Format("%s, ", descList);
+ }
+ descList = Format("%s<c %x>·</c> %s", descList, reader->GetColor(), desc);
+ first = false;
+ }
+ }
+ if(descList != "")
+ {
+ PlayerMessage(GetOwner(Contained()), "%s: %s", Contained(), SN7I->TargetText(), descList);
+ }
+ }
+}
+
+func Entrance(object container)
+{
+ if(GetOCF(container) & OCF_CrewMember)
+ {
+ Selection();
+ }
+}
+
+func GetColor()
+{
+ return color;
+}
+
+func IsAnvilProduct() { return true; }
diff --git a/Items.c4d/Sensors.c4d/CardReader.c4d/Names.txt b/Items.c4d/Sensors.c4d/CardReader.c4d/Names.txt
new file mode 100644
index 0000000..971f587
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CardReader.c4d/Names.txt
@@ -0,0 +1,2 @@
+DE:Kartenleser
+US:Card reader
diff --git a/Items.c4d/Sensors.c4d/CardReader.c4d/Overlay.png b/Items.c4d/Sensors.c4d/CardReader.c4d/Overlay.png
new file mode 100644
index 0000000..0112730
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CardReader.c4d/Overlay.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/CardReader.c4d/OverlayCard.png b/Items.c4d/Sensors.c4d/CardReader.c4d/OverlayCard.png
new file mode 100644
index 0000000..3e3205f
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CardReader.c4d/OverlayCard.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/CardReader.c4d/Script.c b/Items.c4d/Sensors.c4d/CardReader.c4d/Script.c
new file mode 100644
index 0000000..bdf4d62
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CardReader.c4d/Script.c
@@ -0,0 +1,193 @@
+#strict 2
+#include SN7I
+
+local color, controllingCard;
+
+func Init()
+{
+ SetColor(HSL(Random(255), 255, 127));
+ var card = CreateContents(KC7I);
+ card->AddReader(this);
+ Collection2(card);
+}
+
+func SetColor(int newColor)
+{
+ color = newColor;
+ SetColorDw(color);
+}
+
+func GetColor() { return color; }
+
+func OnOwnerChanged()
+{
+ SetColorDw(color);
+}
+
+func Triggers() { return [["$RightCard$"], ["$WrongCard$"]];}
+
+func ControlThrow(object caller)
+{
+ var card, success;
+ if(card = FindCard(caller, success))
+ {
+ if(!controllingCard)
+ {
+ ShowSuccess(success);
+ Trigger(!success, caller);
+ }
+ else
+ {
+ PlayerMessage(GetController(caller), "$CardLoaded$", this);
+ }
+ }
+ else if(controllingCard)
+ {
+ GetCard(0, caller);
+ }
+ return ClearCom(caller);
+}
+
+func ControlThrowDouble() { return ControlThrow(...); }
+
+func ShowSuccess(bool success)
+{
+ if(!success)
+ {
+ Sound("Error");
+ CreateParticle("PSpark", -5, -1, 0, 0, 50, RGB(192, 0, 0));
+ }
+ else
+ {
+ CreateParticle("PSpark", -5, -1, 0, 0, 50, RGB(0, 192, 0));
+ }
+}
+
+func Setup(object caller, int& menuIndex)
+{
+ if(controllingCard && Contained(controllingCard) == this)
+ {
+ AddMenuItem("$GetCard$", "GetCard", KC7I, caller, 0, caller, 0, C4MN_Add_ForceNoDesc | C4MN_Add_ImgObject, controllingCard);
+ ++menuIndex;
+ var success, card = FindCard(caller, success);
+ if(card && !card->HasReader(this))
+ {
+ selectCaller = caller;
+ AddMenuItem("$AddReader$", "AddReader", KC7I, caller, 0, card, 0, C4MN_Add_ForceNoDesc | C4MN_Add_ImgObject, card);
+ ++menuIndex;
+ }
+ if(ObjectCount2(Find_ID(KC7I), Find_Func("HasReader", this), Find_Exclude(controllingCard)))
+ {
+ AddMenuItem("$RemoveReader$", "RemoveReader", KC7I, caller, 0, caller, 0, C4MN_Add_ForceNoDesc | C4MN_Add_ImgObject, controllingCard);
+ ++menuIndex;
+ }
+ }
+ else
+ {
+ var success;
+ FindCard(caller, success);
+ if(success)
+ {
+ AddMenuItem("$LoadCard$", "LoadCard", KC7I, caller, 0, caller, 0, C4MN_Add_ForceNoDesc | C4MN_Add_ImgColor, RGB(255, 255, 255));
+ ++menuIndex;
+ }
+ }
+ return true;
+}
+
+func GetCard(id id, object caller)
+{
+ if(controllingCard)
+ {
+ Exit(controllingCard);
+ caller->Collect(controllingCard);
+ }
+}
+
+func LoadCard(id id, object caller)
+{
+ var success;
+ var card = FindCard(caller, success);
+ if(success)
+ {
+ Enter(this, card);
+ }
+ _Setup(caller);
+ SelectMenuItem(2, caller);
+}
+
+func AddReader(id id, object card)
+{
+ card->AddReader(this);
+}
+
+func RemoveReader(id id, object caller)
+{
+ if(controllingCard)
+ {
+ controllingCard->RemoveReader(this);
+ GetCard(id, caller);
+ }
+}
+
+func FindCard(object container, bool& success)
+{
+ var card;
+ success = false;
+ for(var i = 0; i < ContentsCount(0, container); ++i)
+ {
+ var content = Contents(i, container);
+ if(GetID(content) == KC7I)
+ {
+ if(content->HasReader(this))
+ {
+ card = content;
+ success = true;
+ break;
+ }
+ else if(!card)
+ {
+ card = content;
+ }
+ }
+ }
+ return card;
+}
+
+func Collection2(object obj)
+{
+ if(!controllingCard && obj->GetID() == KC7I && obj->HasReader(this))
+ {
+ controllingCard = obj;
+ SetGraphics("Card", this, GetID(), GFX_Overlay, GFXOV_MODE_Base);
+ SetClrModulation(obj->GetColor(), this, GFX_Overlay);
+ }
+}
+
+func ContentsDestruction(object obj) { return Ejection(obj); }
+
+func Ejection(object obj)
+{
+ if(obj == controllingCard)
+ {
+ SetGraphics(0, this, 0, GFX_Overlay);
+ controllingCard = 0;
+ }
+}
+
+func SetupCondition(object caller)
+{
+ if(controllingCard)
+ {
+ return true;
+ }
+
+ var success;
+ FindCard(caller, success);
+ return success;
+}
+
+func CalcDefValue()
+{
+ return Value(GetID()) + GetValue(0, KC7I);
+}
diff --git a/Items.c4d/Sensors.c4d/CardReader.c4d/StringTblDE.txt b/Items.c4d/Sensors.c4d/CardReader.c4d/StringTblDE.txt
new file mode 100644
index 0000000..07d8964
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CardReader.c4d/StringTblDE.txt
@@ -0,0 +1,7 @@
+RightCard=Richtige Karte
+WrongCard=Falsche Karte
+GetCard=Karte herausnehmen
+AddReader=Leser in die Karte schreiben
+RemoveReader=Leser aus Karte löschen
+LoadCard=Karte hineinstecken
+CardLoaded=Es steckt bereits eine Karte!
diff --git a/Items.c4d/Sensors.c4d/CardReader.c4d/StringTblUS.txt b/Items.c4d/Sensors.c4d/CardReader.c4d/StringTblUS.txt
new file mode 100644
index 0000000..84c5a17
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CardReader.c4d/StringTblUS.txt
@@ -0,0 +1,7 @@
+RightCard=Right card
+WrongCard=Wrong card
+GetCard=Take card
+AddReader=Add reader to card
+RemoveReader=Remove reader from card
+LoadCard=Put card in
+CardLoaded=There is already a card inserted
diff --git a/Items.c4d/Sensors.c4d/CodeInput.c4d/DefCore.txt b/Items.c4d/Sensors.c4d/CodeInput.c4d/DefCore.txt
new file mode 100644
index 0000000..224a95a
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CodeInput.c4d/DefCore.txt
@@ -0,0 +1,19 @@
+[DefCore]
+id=CI7I
+Name=Code Input
+Version=4,9,5
+Category=C4D_Object|C4D_SelectMaterial|C4D_SelectKnowledge|C4D_SelectHomebase
+Width=10
+Height=13
+Offset=-5,-6
+Mass=10
+Value=5
+Components=METL=1;
+Picture=10,0,64,64
+Vertices=1
+VertexFriction=100
+Grab=2
+Collectible=1
+MaxUserSelect=10
+Rebuy=1
+NoPushEnter=1
diff --git a/Items.c4d/Sensors.c4d/CodeInput.c4d/Graphics.png b/Items.c4d/Sensors.c4d/CodeInput.c4d/Graphics.png
new file mode 100644
index 0000000..f4be8c6
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CodeInput.c4d/Graphics.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/CodeInput.c4d/Names.txt b/Items.c4d/Sensors.c4d/CodeInput.c4d/Names.txt
new file mode 100644
index 0000000..d238d54
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CodeInput.c4d/Names.txt
@@ -0,0 +1,2 @@
+DE:Passworteingabe
+US:Code input
diff --git a/Items.c4d/Sensors.c4d/CodeInput.c4d/Script.c b/Items.c4d/Sensors.c4d/CodeInput.c4d/Script.c
new file mode 100644
index 0000000..bd5af5c
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CodeInput.c4d/Script.c
@@ -0,0 +1,138 @@
+#strict 2
+#include SN7I
+
+local inputMode, code, authedPlayers;
+
+func Init()
+{
+ inputMode = [];
+ authedPlayers = [];
+}
+
+func Triggers() { return [["$RightCode$"], ["$WrongCode$"]];}
+
+func ControlThrow(object caller)
+{
+ if(!code)
+ {
+ PlayerMessage(GetController(caller), "$NoCodeSet$", this);
+ }
+ else
+ {
+ QueryCode(caller, 0);
+ }
+ return ClearCom(caller);
+}
+
+func ControlThrowDouble() { return ControlThrow(...); }
+
+func QueryCode(object caller, int mode)
+{
+ var plr = GetController(caller);
+ inputMode[plr] = [mode, caller];
+ CallMessageBoard(this, false, ["$EnterCode$", "$EnterCurrentCode$", "$EnterNewCode$", "$EnterCode$"][mode], plr);
+}
+
+func InputCallback(string answer, int plr)
+{
+ if(!inputMode[plr])
+ {
+ return _inherited(answer, plr, ...);
+ }
+ else if(answer != "")
+ {
+ var mode = inputMode[plr][0];
+ var caller = inputMode[plr][1];
+ inputMode[plr] = 0;
+ if(mode == 0 || mode == 3)
+ {
+ authedPlayers[GetPlayerID(plr)] = answer == code;
+ if(mode == 0)
+ {
+ Trigger(answer != code, caller);
+ }
+ else if(mode == 3)
+ {
+ if(answer == code)
+ {
+ _Setup(caller);
+ }
+ else
+ {
+ Trigger(1, caller);
+ }
+ }
+ ShowSuccess(answer == code, caller);
+ if(answer != code)
+ {
+ ScheduleCall(this, "QueryCode", 1, 0, caller, mode);
+ }
+ }
+ else if(mode == 1)
+ {
+ ShowSuccess(answer == code, caller);
+ ScheduleCall(this, "QueryCode", 1, 0, caller, 1 + (answer == code));
+ if(answer != code)
+ {
+ Trigger(1, caller);
+ }
+ }
+ else if(mode == 2)
+ {
+ code = answer;
+ authedPlayers = [];
+ authedPlayers[GetPlayerID(plr)] = true;
+ PlayerMessage(plr, "$CodeChanged$", this);
+ }
+ }
+}
+
+func ShowSuccess(bool success, object caller)
+{
+ if(!success)
+ {
+ Sound("Error");
+ PlayerMessage(GetController(caller), "$TxtWrongCode$", this);
+ CreateParticle("PSpark", -2, -3, 0, 0, 50, RGB(192, 0, 0));
+ }
+ else
+ {
+ CreateParticle("PSpark", -2, -3, 0, 0, 50, RGB(0, 192, 0));
+ }
+}
+
+func _Setup(object caller)
+{
+ if(code && !authedPlayers[GetPlayerID(GetController(caller))])
+ {
+ QueryCode(caller, 3);
+ }
+ else
+ {
+ return _inherited(caller, ...);
+ }
+}
+
+func Setup(object caller, int& menuIndex)
+{
+ if(GetController(caller) == GetOwner())
+ {
+ AddMenuItem("$ChangeCode$", "ChangeCode", GetID(), caller, 0, caller, 0, C4MN_Add_ForceNoDesc);
+ ++menuIndex;
+ }
+ return true;
+}
+
+func ChangeCode(id id, object caller)
+{
+ _Setup(caller);
+ SelectMenuItem(2, caller);
+
+ QueryCode(caller, 1 + !code);
+}
+
+func ChangeDesc(id id, object caller, bool right)
+{
+ inputMode[GetController(caller)] = 0;
+ return _inherited(id, caller, right, ...);
+}
diff --git a/Items.c4d/Sensors.c4d/CodeInput.c4d/StringTblDE.txt b/Items.c4d/Sensors.c4d/CodeInput.c4d/StringTblDE.txt
new file mode 100644
index 0000000..64671f3
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CodeInput.c4d/StringTblDE.txt
@@ -0,0 +1,9 @@
+RightCode=Richtiges Passwort
+WrongCode=Falsches Passwort
+EnterCode=Passwort eingeben
+EnterCurrentCode=Aktuelles Passwort eingeben
+EnterNewCode=Neues Passwort eingeben
+NoCodeSet=Es ist noch kein Passwort gesetzt!
+CodeChanged=Passwort erfolgreich gesetzt.
+ChangeCode=Passwort ändern
+TxtWrongCode=Falsches Passwort!|Neuer Versuch…
diff --git a/Items.c4d/Sensors.c4d/CodeInput.c4d/StringTblUS.txt b/Items.c4d/Sensors.c4d/CodeInput.c4d/StringTblUS.txt
new file mode 100644
index 0000000..eecdb4f
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/CodeInput.c4d/StringTblUS.txt
@@ -0,0 +1,9 @@
+RightCode=Right code
+WrongCode=Wrong code
+EnterCode=Enter code
+EnterCurrentCode=Enter current code
+EnterNewCode=Enter new code
+NoCodeSet=No code is set!
+CodeChanged=Code changed successfully.
+ChangeCode=Change code
+TxtWrongCode=Wrong code!|Try again…
diff --git a/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/DefCore.txt b/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/DefCore.txt
new file mode 100644
index 0000000..335d9ae
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/DefCore.txt
@@ -0,0 +1,19 @@
+[DefCore]
+id=FP7I
+Name=Fingerprint sensor
+Version=4,9,5
+Category=C4D_Object|C4D_SelectMaterial|C4D_SelectKnowledge|C4D_SelectHomebase
+Width=10
+Height=4
+Offset=-5,-2
+Mass=10
+Value=5
+Components=METL=1;
+Picture=10,0,64,64
+Vertices=1
+VertexFriction=100
+Grab=2
+Collectible=1
+MaxUserSelect=10
+Rebuy=1
+NoPushEnter=1
diff --git a/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/Graphics.png b/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/Graphics.png
new file mode 100644
index 0000000..83ff04b
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/Graphics.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/Names.txt b/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/Names.txt
new file mode 100644
index 0000000..d251351
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/Names.txt
@@ -0,0 +1,2 @@
+DE:Fingerabdrucksensor
+US:Fingerprint sensor
diff --git a/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/Script.c b/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/Script.c
new file mode 100644
index 0000000..58a673b
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/Script.c
@@ -0,0 +1,172 @@
+#strict 2
+#include SN7I
+
+local masterFinger, fingers;
+
+func Init()
+{
+ fingers = [];
+}
+
+func CleanupFingers()
+{
+ ArrayEraseItem(fingers, 0, true);
+}
+
+func Triggers() { return [["$RightFinger$"], ["$WrongFinger$"]];}
+
+func ControlThrow(object caller)
+{
+ if(GetLength(fingers) > 0)
+ {
+ var success = IsKnownFinger(caller);
+ ShowSuccess(success);
+ Trigger(!success, caller);
+ }
+ return ClearCom(caller);
+}
+
+func ShowSuccess(bool success, object caller)
+{
+ if(!success)
+ {
+ Sound("Error");
+ CreateParticle("PSpark", -2, -2, 0, 0, 50, RGB(192, 0, 0));
+ }
+ else
+ {
+ CreateParticle("PSpark", -2, -2, 0, 0, 50, RGB(0, 192, 0));
+ }
+}
+
+func ControlThrowDouble() { return ControlThrow(...); }
+
+func EntranceCallback() { return "ControlThrow"; }
+
+func SetupCondition(object caller)
+{
+ return GetLength(fingers) == 0 || IsKnownFinger(caller);
+}
+
+func IsKnownFinger(object finger)
+{
+ return GetIndexOf(finger, fingers) != -1;
+}
+
+func Setup(object caller, int& menuIndex)
+{
+ if(!CheckMasterFinger())
+ {
+ AddMenuItem("$SetMasterFinger$", "SetMasterFinger", RSR1, caller, 0, caller, 0, C4MN_Add_ForceNoDesc);
+ ++menuIndex;
+ }
+ if(caller == masterFinger)
+ {
+ if(FindObject2(AddFingerCondition()))
+ {
+ AddMenuItem("$AddFinger$", "AddFingers", RSR1, caller, 0, caller, 0, C4MN_Add_ForceNoDesc);
+ ++menuIndex;
+ }
+ if(GetLength(fingers) > 0)
+ {
+ AddMenuItem("$ChangeFingers$", "ChangeFingers", RSR1, caller, 0, caller, 0, C4MN_Add_ForceNoDesc);
+ ++menuIndex;
+ }
+ }
+ return true;
+}
+
+func SetMasterFinger(id id, object caller)
+{
+ if(!CheckMasterFinger())
+ {
+ masterFinger = caller;
+ if(!IsKnownFinger(caller))
+ {
+ fingers[GetLength(fingers)] = caller;
+ }
+ }
+}
+
+func AddFingerCondition()
+{
+ return Find_And(Find_OCF(OCF_CrewMember), Find_ActionTarget(this), Find_Procedure("PUSH"), Find_Not(Find_Func("FP7I_IsKnownFinger", this)));
+}
+
+func GetFingerList(array fingers, bool showMaster)
+{
+ var ret = CreateArray(GetLength(fingers));
+ for(var i = 0; i < GetLength(fingers); ++i)
+ {
+ var obj = fingers[i];
+ ret[i] = [obj, Format("%s (%s)", GetName(obj), GetPlayerName(GetOwner(obj)))];
+ if(showMaster && obj == masterFinger)
+ {
+ ret[i][1] = Format("$MasterFinger$", ret[i][1]);
+ }
+ }
+ return ret;
+}
+
+func AddFingers(id id, object caller)
+{
+ return caller->~CreateSelectionMenu("AddFinger", GetFingerList(FindObjects(AddFingerCondition())), GetID(), "$AddFinger$", this);
+}
+
+func AddFinger(id id, object finger, bool right)
+{
+ if(!IsKnownFinger(finger))
+ {
+ fingers[GetLength(fingers)] = finger;
+ }
+ if(right)
+ {
+ masterFinger = finger;
+ }
+}
+
+func ChangeFingers(id id, object caller)
+{
+ selectCaller = caller;
+ return caller->~CreateSelectionMenu("ChangeFinger", GetFingerList(fingers, true), GetID(), "$ChangeFingers$", this);
+}
+
+func ChangeFinger(id id, object finger, bool right)
+{
+ if(right)
+ {
+ masterFinger = finger;
+ }
+ else
+ {
+ var i = GetIndexOf(finger, fingers);
+ if(i != -1)
+ {
+ ArrayErase(fingers, i);
+ if(finger != masterFinger)
+ {
+ ChangeFingers(0, selectCaller);
+ SelectMenuItem(i - 1, selectCaller);
+ SelectMenuItem(i, selectCaller);
+ }
+ else
+ {
+ masterFinger = 0;
+ }
+ }
+ }
+}
+
+global func FP7I_IsKnownFinger(object sensor)
+{
+ return sensor && sensor->IsKnownFinger(this);
+}
+
+func CheckMasterFinger()
+{
+ if(masterFinger && !GetAlive(masterFinger))
+ {
+ masterFinger = 0;
+ }
+ return !!masterFinger;
+}
diff --git a/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/StringTblDE.txt b/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/StringTblDE.txt
new file mode 100644
index 0000000..239f4d7
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/StringTblDE.txt
@@ -0,0 +1,6 @@
+RightFinger=Richtiger Fingerabdruck
+WrongFinger=Falscher Fingerabdruck
+SetMasterFinger=Hauptfingerabdruck setzen
+AddFinger=Fingerabdruck hinzufügen
+ChangeFingers=Fingerabdrücke verwalten
+MasterFinger=Hauptfingerabdruck: %s
diff --git a/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/StringTblUS.txt b/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/StringTblUS.txt
new file mode 100644
index 0000000..9f7e56f
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/FingerprintSensor.c4d/StringTblUS.txt
@@ -0,0 +1,6 @@
+RightFinger=Right fingerprint
+WrongFinger=Wrong fingerprint
+SetMasterFinger=Set master fingerprint
+AddFinger=Add fingerprint
+ChangeFingers=Manage fingerprints
+MasterFinger=Master fingerprint: %s
diff --git a/Items.c4d/Sensors.c4d/LiquidSensor.c4d/DefCore.txt b/Items.c4d/Sensors.c4d/LiquidSensor.c4d/DefCore.txt
new file mode 100644
index 0000000..1809615
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/LiquidSensor.c4d/DefCore.txt
@@ -0,0 +1,19 @@
+[DefCore]
+id=LS7I
+Name=Liquid sensor
+Category=C4D_Object|C4D_SelectMaterial|C4D_SelectKnowledge|C4D_SelectHomebase
+Width=10
+Height=6
+Offset=-5,-3
+Mass=10
+Value=5
+Components=METL=1;
+Picture=10,0,64,64
+Vertices=1
+VertexFriction=100
+VertexY=0
+Grab=2
+Collectible=1
+MaxUserSelect=10
+Rebuy=1
+NoPushEnter=1
diff --git a/Items.c4d/Sensors.c4d/LiquidSensor.c4d/Graphics.png b/Items.c4d/Sensors.c4d/LiquidSensor.c4d/Graphics.png
new file mode 100644
index 0000000..533ec87
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/LiquidSensor.c4d/Graphics.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/LiquidSensor.c4d/Names.txt b/Items.c4d/Sensors.c4d/LiquidSensor.c4d/Names.txt
new file mode 100644
index 0000000..9bf0e18
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/LiquidSensor.c4d/Names.txt
@@ -0,0 +1,2 @@
+DE:Flüssigkeitssensor
+US:Liquid sensor
diff --git a/Items.c4d/Sensors.c4d/LiquidSensor.c4d/Script.c b/Items.c4d/Sensors.c4d/LiquidSensor.c4d/Script.c
new file mode 100644
index 0000000..02eed62
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/LiquidSensor.c4d/Script.c
@@ -0,0 +1,45 @@
+#strict 2
+#include SN7I
+
+local triggered;
+
+func Init()
+{
+ AddTimer("Check", 1);
+}
+
+func Attach(object caller, object contained)
+{
+ if(GetID() == LS7I && contained)
+ {
+ return SetPosition(GetX(), GetY() + 9);
+ }
+}
+
+func Triggers() { return [["$LiquidTrigger$"], ["$NoLiquidTrigger$"]]; }
+
+func SensorCallbacks() { return [["$Retrigger$", "Retrigger"]]; }
+
+func Check(bool retrigger)
+{
+ ClearParticles("PSpark", this);
+ if(GBackLiquid())
+ {
+ CreateParticle("PSpark", 0, -1, 0, 0, 50, RGB(0, 192, 0), this);
+ if(!triggered || retrigger)
+ {
+ triggered = true;
+ return Trigger(0);
+ }
+ }
+ else if(triggered || retrigger)
+ {
+ triggered = false;
+ return Trigger(1);
+ }
+}
+
+func Retrigger()
+{
+ return Check(true);
+}
diff --git a/Items.c4d/Sensors.c4d/LiquidSensor.c4d/StringTblDE.txt b/Items.c4d/Sensors.c4d/LiquidSensor.c4d/StringTblDE.txt
new file mode 100644
index 0000000..99cd70b
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/LiquidSensor.c4d/StringTblDE.txt
@@ -0,0 +1,3 @@
+Retrigger=Erneut aktivieren
+LiquidTrigger=Flüssigkeit erkannt
+NoLiquidTrigger=Flüssigkeit entfernt
diff --git a/Items.c4d/Sensors.c4d/LiquidSensor.c4d/StringTblUS.txt b/Items.c4d/Sensors.c4d/LiquidSensor.c4d/StringTblUS.txt
new file mode 100644
index 0000000..aae6f34
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/LiquidSensor.c4d/StringTblUS.txt
@@ -0,0 +1,3 @@
+Retrigger=Retrigger
+LiquidTrigger=Liquid detected
+NoLiquidTrigger=Liquid removed
diff --git a/Items.c4d/Sensors.c4d/LivingSensor.c4d/DefCore.txt b/Items.c4d/Sensors.c4d/LivingSensor.c4d/DefCore.txt
new file mode 100644
index 0000000..21f6b36
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/LivingSensor.c4d/DefCore.txt
@@ -0,0 +1,18 @@
+[DefCore]
+id=LV7I
+Name=Living sensor
+Category=C4D_Object|C4D_SelectMaterial|C4D_SelectKnowledge|C4D_SelectHomebase
+Width=10
+Height=6
+Offset=-5,-3
+Mass=10
+Value=5
+Components=METL=1;
+Picture=10,0,64,64
+Vertices=1
+VertexFriction=100
+Grab=2
+Collectible=1
+MaxUserSelect=10
+Rebuy=1
+NoPushEnter=1
diff --git a/Items.c4d/Sensors.c4d/LivingSensor.c4d/Graphics.png b/Items.c4d/Sensors.c4d/LivingSensor.c4d/Graphics.png
new file mode 100644
index 0000000..74f2588
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/LivingSensor.c4d/Graphics.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/LivingSensor.c4d/Names.txt b/Items.c4d/Sensors.c4d/LivingSensor.c4d/Names.txt
new file mode 100644
index 0000000..b959d0d
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/LivingSensor.c4d/Names.txt
@@ -0,0 +1,2 @@
+DE:Lebewesensensor
+US:Living sensor
diff --git a/Items.c4d/Sensors.c4d/LivingSensor.c4d/Script.c b/Items.c4d/Sensors.c4d/LivingSensor.c4d/Script.c
new file mode 100644
index 0000000..00ba923
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/LivingSensor.c4d/Script.c
@@ -0,0 +1,112 @@
+#strict 2
+#include LS7I
+
+local range;
+static LV7I_MaxRange;
+local rangeTarget;
+
+func MaxRange()
+{
+ return LV7I_MaxRange || 200;
+}
+
+func SetMaxRange(int range)
+{
+ if(this)
+ {
+ DebugLog("WARNING: LV7I->SetMaxRange() sets the maximum available distance for all living sensors.");
+ DebugLog("Use this function in definition context only (this also disables this warning).");
+ }
+
+ LV7I_MaxRange = range;
+}
+
+func Init()
+{
+ range = 50;
+ return _inherited(...);
+}
+
+func Triggers() { return [["$AnimalTrigger$"], ["$NoAnimalTrigger$"], ["$AlliedTrigger$"], ["$NoAlliedTrigger$"], ["$HostileTrigger$"], ["$NoHostileTrigger$"]]; }
+
+func SetupMenuID() { return LV7I; }
+
+func Setup(object caller, int& menuIndex)
+{
+ selectCaller = caller;
+ AddMenuItem(Format("$Range$", range), "ChangeRange", GetID(), caller, 0, menuIndex++, 0, C4MN_Add_ForceNoDesc);
+ if(!GetEffect("IntShowRange", caller))
+ {
+ AddEffect("IntShowRange", caller, 1, 1, this);
+ rangeTarget = caller;
+ }
+ return true;
+}
+
+func ChangeRange(id id, int index, bool right)
+{
+ range = BoundBy(range - (right * 2 - 1), 1, MaxRange());
+ _Setup(selectCaller);
+ SelectMenuItem(index, selectCaller);
+}
+
+func FxIntShowRangeTimer(object target, int effectNumber)
+{
+ ClearParticles("PSpark", this);
+ if(Contained())
+ {
+ ClearParticles("PSpark", Contained());
+ }
+ if(!target || GetMenu(target) != SetupMenuID())
+ {
+ rangeTarget = 0;
+ return FX_Execute_Kill;
+ }
+
+ var ret = 0;
+ var step = BoundBy(500 * MaxRange() / range, 500, 2000);
+ var size = 30; //BoundBy((range * 3) / 5, 20, 60);
+ for(var r = 0; r < 36000 - step + 1; r += step)
+ {
+ ret += CreateParticle("PSpark", Cos(r, range, 100), Sin(r, range, 100), 0, 0, size, GetPlrColorDw(GetOwner()), Contained() || this);
+ }
+}
+
+func AnimalCondition()
+{
+ return Find_Or(Find_Category(4096), Find_Func("IsAnimal")); // C4D_SelectAnimal is 4096 but is not available as constant
+}
+
+func Check(bool retrigger)
+{
+ if(!rangeTarget)
+ {
+ ClearParticles("PSpark", this);
+ }
+ for(var mode in [[0, Find_Or(AnimalCondition(), Find_Owner(NO_OWNER)), RGB(255, 255, 0)], [1, Find_And(Find_Not(Find_Hostile(GetOwner())), Find_Not(AnimalCondition())), RGB(0, 192, 0)], [2, Find_And(Find_Hostile(GetOwner()), Find_Not(AnimalCondition())), RGB(192, 0, 0)]])
+ {
+ var living = FindObject2(Find_Distance(range), Find_OCF(OCF_Alive), mode[1], Sort_Random());
+ TestAndTrigger(mode[0], living, living, mode[2], retrigger);
+ }
+}
+
+func TestAndTrigger(int type, bool present, object obj, int color, bool retrigger)
+{
+ present = !!present;
+ if(present)
+ {
+ CreateParticle("PSpark", (type - 1) * 5, 1, 0, 0, 50, color, this);
+ }
+ if((!!(triggered & (1 << type))) != present || retrigger)
+ {
+ if(present)
+ {
+ triggered |= (1 << type);
+ }
+ else
+ {
+ triggered &= ~(1 << type);
+ }
+ return Trigger(2 * type + !present, obj);
+ }
+}
diff --git a/Items.c4d/Sensors.c4d/LivingSensor.c4d/StringTblDE.txt b/Items.c4d/Sensors.c4d/LivingSensor.c4d/StringTblDE.txt
new file mode 100644
index 0000000..4b36fb6
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/LivingSensor.c4d/StringTblDE.txt
@@ -0,0 +1,7 @@
+AnimalTrigger=Tier erkannt
+NoAnimalTrigger=Tier entfernt
+AlliedTrigger=Verbündeter erkannt
+NoAlliedTrigger=Verbündeter entfernt
+HostileTrigger=Feind erkannt
+NoHostileTrigger=Feind entfernt
+Range=Reichweite: %d Pixel
diff --git a/Items.c4d/Sensors.c4d/LivingSensor.c4d/StringTblUS.txt b/Items.c4d/Sensors.c4d/LivingSensor.c4d/StringTblUS.txt
new file mode 100644
index 0000000..110758b
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/LivingSensor.c4d/StringTblUS.txt
@@ -0,0 +1,7 @@
+AnimalTrigger=Animal detected
+NoAnimalTrigger=Animal removed
+AlliedTrigger=Allied detected
+NoAlliedTrigger=Allied removed
+HostileTrigger=Enemy detected
+NoHostileTrigger=Enemy removed
+Range=Range: %d pixels
diff --git a/Items.c4d/Sensors.c4d/Names.txt b/Items.c4d/Sensors.c4d/Names.txt
new file mode 100644
index 0000000..463af24
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Names.txt
@@ -0,0 +1,2 @@
+DE:Neuer Objektordner
+US:New object folder
diff --git a/Items.c4d/Sensors.c4d/ObjectSensor.c4d/ActMap.txt b/Items.c4d/Sensors.c4d/ObjectSensor.c4d/ActMap.txt
new file mode 100644
index 0000000..6f9738a
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/ObjectSensor.c4d/ActMap.txt
@@ -0,0 +1,3 @@
+[Action]
+Name=Wall
+Facet=0,4,10,10
diff --git a/Items.c4d/Sensors.c4d/ObjectSensor.c4d/DefCore.txt b/Items.c4d/Sensors.c4d/ObjectSensor.c4d/DefCore.txt
new file mode 100644
index 0000000..af1dbd5
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/ObjectSensor.c4d/DefCore.txt
@@ -0,0 +1,19 @@
+[DefCore]
+id=OS7I
+Name=Object sensor
+Category=C4D_Object|C4D_SelectMaterial|C4D_SelectKnowledge|C4D_SelectHomebase
+Width=10
+Height=4
+Offset=-5,-2
+Mass=10
+Value=5
+Components=METL=1;
+Picture=10,0,64,64
+Vertices=1
+VertexFriction=100
+VertexY=-2
+Grab=2
+Collectible=1
+MaxUserSelect=10
+Rebuy=1
+NoPushEnter=1
diff --git a/Items.c4d/Sensors.c4d/ObjectSensor.c4d/Graphics.png b/Items.c4d/Sensors.c4d/ObjectSensor.c4d/Graphics.png
new file mode 100644
index 0000000..6a87007
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/ObjectSensor.c4d/Graphics.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/ObjectSensor.c4d/Names.txt b/Items.c4d/Sensors.c4d/ObjectSensor.c4d/Names.txt
new file mode 100644
index 0000000..0cb612c
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/ObjectSensor.c4d/Names.txt
@@ -0,0 +1,2 @@
+DE:Objektsensor
+US:Object sensor
diff --git a/Items.c4d/Sensors.c4d/ObjectSensor.c4d/Script.c b/Items.c4d/Sensors.c4d/ObjectSensor.c4d/Script.c
new file mode 100644
index 0000000..a27a398
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/ObjectSensor.c4d/Script.c
@@ -0,0 +1,292 @@
+#strict 2
+#include LS7I
+
+local detectIDs, exceptIDs, denyIDs, detectCats, denyCats, hostility;
+
+func Init()
+{
+ detectCats = C4D_Living | C4D_Object | C4D_Vehicle;
+ denyCats = 0;
+ detectIDs = [C4FO_Or];
+ exceptIDs = [C4FO_Or];
+ denyIDs = [C4FO_Or];
+ return _inherited(...);
+}
+
+func ControlUp(object caller)
+{
+ if(!Attached() && caller)
+ {
+ caller->Collect(this);
+ }
+}
+
+func Attach(object caller, object contained)
+{
+ if(contained && GetProcedure(contained) == "WALK")
+ {
+ return SetPosition(GetX(), GetY() + 10);
+ }
+}
+
+func Triggers() { return [["$ObjectTrigger$"], ["$NoObjectTrigger$"], ["$DeniedObjectTrigger$"]]; }
+
+func Setup(object caller, int &menuIndex)
+{
+ selectCaller = caller;
+ AddMenuItem("$SetupDetection$", "SetupDetection", RSR1, caller, 0, caller, 0, C4MN_Add_ForceNoDesc);
+ ++menuIndex;
+ return true;
+}
+
+func SetupDetection(id id, object caller, int selection)
+{
+ if(CreateMenu(RSR1, caller, this, C4MN_Extra_None, "$SetupDetection$", 0, C4MN_Style_Context, 0))
+ {
+ var menuIndex = 0;
+ AddMenuItem("$AddType$", "AddType", GetID(), caller, 0, caller, 0, C4MN_Add_ForceNoDesc);
+ ++menuIndex;
+ AddMenuItem(Format("$TargetOwner$", ["$All$", "$Allied$", "$Hostile$", 0, "$DenyHostile$", "$DenyAllied$"][hostility]), "ChangeHostility", GetID(), caller, 0, caller, 0, C4MN_Add_ForceNoDesc);
+ ++menuIndex;
+
+ for(var part in [["$DetectDef$", detectCats], ["$DetectDenial$", denyCats]])
+ {
+ for(var cat in [[C4D_Vehicle, "$Vehicle$", LORY], [C4D_Living, "$Living$", WIPF], [C4D_Object, "$Object$", ROCK]])
+ {
+ if(part[1] & cat[0])
+ {
+ AddMenuItem(Format(part[0], cat[1]), "RemoveCat", cat[2], caller, 0, cat[0], 0, C4MN_Add_ForceNoDesc);
+ ++menuIndex;
+ }
+ }
+ }
+
+ for(var part in [["$DetectDef$", detectIDs], ["$DetectException$", exceptIDs], ["$DetectDenial$", denyIDs]])
+ {
+ for(var i = 1; i < GetLength(part[1]); ++i)
+ {
+ AddMenuItem(Format(part[0], GetName(0, part[1][i][1])), "RemoveDef", part[1][i][1], caller, 0, ++menuIndex, 0, C4MN_Add_ForceNoDesc);
+ }
+ }
+ SelectMenuItem(selection - 1, caller);
+ SelectMenuItem(selection, caller);
+ }
+}
+
+func RemoveCat(id id, int cat, bool right)
+{
+ var denial = detectCats & cat;
+ detectCats &= ~cat;
+ denyCats &= ~cat;
+ if(right)
+ {
+ if(denial)
+ {
+ denyCats |= cat;
+ }
+ else
+ {
+ detectCats |= cat;
+ }
+ }
+ SetupDetection(0, selectCaller, 3);
+}
+
+func RemoveDef(id id, int indexPO, bool right)
+{
+ var part = [C4FO_ID, id], exception, denial;
+ if(right)
+ {
+ exception = GetIndexOf2(part, detectIDs) == -1;
+ denial = GetIndexOf2(part, denyIDs) == -1;
+ }
+ ArrayEraseItem(detectIDs, part);
+ ArrayEraseItem(exceptIDs, part);
+ ArrayEraseItem(denyIDs, part);
+ if(right)
+ {
+ if(exception)
+ {
+ if(denial)
+ {
+ denyIDs[GetLength(denyIDs)] = part;
+ }
+ else
+ {
+ detectIDs[GetLength(detectIDs)] = part;
+ }
+ }
+ else
+ {
+ exceptIDs[GetLength(exceptIDs)] = part;
+ }
+ }
+ SetupDetection(0, selectCaller, indexPO - 1);
+}
+
+func AddType(id id, object caller, int selection)
+{
+ var menuIndex = 0;
+ if(CreateMenu(RSR1, caller, this, C4MN_Extra_None, "$AddType$", 0, C4MN_Style_Context, 0))
+ {
+ for(var cat in [[C4D_Vehicle, "$Vehicle$", LORY], [C4D_Living, "$Living$", WIPF], [C4D_Object, "$Object$", ROCK]])
+ {
+ if(!(detectCats & cat[0]))
+ {
+ AddMenuItem(cat[1], "AddCat", cat[2], caller, 0, cat[0], 0, C4MN_Add_ForceNoDesc);
+ ++menuIndex;
+ }
+ }
+ var defs = [];
+ for(var obj in FindObjects(Find_Exclude(this), (caller || this)->Find_AtPoint(), IgnoreSensorIgnored(), Find_Category(C4D_Living | C4D_Object | C4D_Vehicle)))
+ {
+ var def = GetID(obj);
+ if(GetIndexOf(def, defs) == -1 && GetIndexOf2([C4FO_ID, def], detectIDs) == -1 && GetIndexOf2([C4FO_ID, def], exceptIDs) == -1)
+ {
+ defs[GetLength(defs)] = def;
+ }
+ }
+
+ for(def in defs)
+ {
+ AddMenuItem(GetName(0, def), "AddDef", def, caller, 0, ++menuIndex, 0, C4MN_Add_ForceNoDesc);
+ }
+
+ SelectMenuItem(selection - 1, caller);
+ SelectMenuItem(selection, caller);
+ }
+}
+
+func AddCat(id id, int cat, bool right)
+{
+ if(right)
+ {
+ denyCats |= cat;
+ }
+ else
+ {
+ detectCats |= cat;
+ }
+ AddType(0, selectCaller, 1);
+}
+
+func AddDef(id id, int indexPO, bool right)
+{
+ if(right)
+ {
+ exceptIDs[GetLength(exceptIDs)] = [C4FO_ID, id];
+ }
+ else
+ {
+ detectIDs[GetLength(detectIDs)] = [C4FO_ID, id];
+ }
+ AddType(0, selectCaller, indexPO - 1);
+}
+
+func ChangeHostility(id id, object caller, bool right)
+{
+ if(right)
+ {
+ if(hostility)
+ {
+ if(hostility > 2)
+ {
+ hostility -= 3;
+ }
+ else
+ {
+ hostility += 3;
+ }
+ }
+ else
+ {
+ hostility = 4;
+ }
+ }
+ else
+ {
+ var denyOther = (hostility > 2) * 4;
+ ++hostility;
+ if((!denyOther && hostility > 2) || (denyOther && hostility > 5))
+ {
+ hostility = denyOther;
+ }
+ }
+
+ SetupDetection(0, caller, 1);
+}
+
+func Check(bool retrigger)
+{
+ var posCond;
+ if(Attached() && !GBackSemiSolid(0, 2))
+ {
+ SetCategory(C4D_Structure);
+ SetAction("Wall");
+ SetSolidMask();
+ posCond = Find_AtRect(-3, 0, 8, 8);
+ }
+ else
+ {
+ SetCategory(C4D_Object);
+ SetAction("Idle");
+ posCond = Find_AtPoint(0, -3);
+ if(!Contained() && GetSpeed() < 5)
+ {
+ SetSolidMask(0, 0, 10, 1);
+ }
+ else
+ {
+ SetSolidMask();
+ }
+ }
+ var obj;
+ var additionalConds = [C4FO_And];
+ var hostilityCond = [0, Find_Not(Find_Hostile(GetOwner(this))), Find_Hostile(GetOwner(this))][hostility % 3];
+ var hostilityDenyCond = [0, Find_Hostile(GetOwner(this)), Find_Not(Find_Hostile(GetOwner(this)))][hostility - 3];
+ if(GetLength(exceptIDs) > 1)
+ {
+ additionalConds[GetLength(additionalConds)] = Find_Not(exceptIDs);
+ }
+ if(hostilityCond)
+ {
+ additionalConds[GetLength(additionalConds)] = hostilityCond;
+ }
+ var additionalDenyConds = [C4FO_Or];
+ if(denyIDs)
+ {
+ additionalDenyConds[GetLength(additionalDenyConds)] = denyIDs;
+ }
+ if(denyCats)
+ {
+ additionalDenyConds[GetLength(additionalDenyConds)] = Find_Category(denyCats);
+ }
+ if(hostilityDenyCond)
+ {
+ additionalDenyConds[GetLength(additionalDenyConds)] = Find_And(Find_Or(detectIDs, detectCats && Find_Category(detectCats)), hostilityDenyCond);
+ }
+ ClearParticles("PSpark", this);
+ if(GetLength(additionalDenyConds) > 1 && (obj = FindObject2(Find_Exclude(this), posCond, Find_NoContainer(), Find_Category(C4D_Living | C4D_Object | C4D_Vehicle), IgnoreSensorIgnored(), additionalDenyConds)))
+ {
+ CreateParticle("PSpark", 0, 0, 0, 0, 50, RGB(192, 0, 0), this);
+ if(triggered != 2 || retrigger)
+ {
+ triggered = 2;
+ return Trigger(2, obj);
+ }
+ }
+ else if(obj = FindObject2(Find_Exclude(this), posCond, Find_NoContainer(), IgnoreSensorIgnored(), Find_Or(detectIDs, detectCats && Find_Category(detectCats)), additionalConds))
+ {
+ CreateParticle("PSpark", 0, 0, 0, 0, 50, RGB(0, 192, 0), this);
+ if(!triggered || retrigger)
+ {
+ triggered = true;
+ return Trigger(0, obj);
+ }
+ }
+ else if(triggered || retrigger)
+ {
+ triggered = false;
+ return Trigger(1);
+ }
+}
diff --git a/Items.c4d/Sensors.c4d/ObjectSensor.c4d/StringTblDE.txt b/Items.c4d/Sensors.c4d/ObjectSensor.c4d/StringTblDE.txt
new file mode 100644
index 0000000..68388c2
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/ObjectSensor.c4d/StringTblDE.txt
@@ -0,0 +1,17 @@
+ObjectTrigger=Objekt erkannt
+NoObjectTrigger=Objekt entfernt
+DeniedObjectTrigger=Verbotenes Objekt erkannt
+SetupDetection=Erkennung einstellen
+DetectException=Ausnahme: %s
+DetectDef=%s
+DetectDenial=Verbot: %s
+AddType=Erkennungstyp hinzufügen
+Vehicle=Fahrzeuge
+Living=Lebewesen
+Object=Objekte
+TargetOwner=Zielbesitzer: %s
+All=Alle
+Allied=Verbündet
+Hostile=Feindlich
+DenyHostile=Verbündet, Feindlich verboten
+DenyAllied=Feindlich, Verbündet verboten
diff --git a/Items.c4d/Sensors.c4d/ObjectSensor.c4d/StringTblUS.txt b/Items.c4d/Sensors.c4d/ObjectSensor.c4d/StringTblUS.txt
new file mode 100644
index 0000000..814bd4f
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/ObjectSensor.c4d/StringTblUS.txt
@@ -0,0 +1,15 @@
+ObjectTrigger=Object detected
+NoObjectTrigger=Object removed
+DeniedObjectTrigger=Denied Object detected
+SetupDetection=Setup detection
+DetectException=Exception: %s
+DetectDef=%s
+DetectDenial=Denial: %s
+AddType=Add detection type
+Vehicle=Vehicles
+Living=Living
+Object=Objects
+TargetOwner=Target owner: %s
+All=All
+Allied=Allied
+Hostile=Hostile
diff --git a/Items.c4d/Sensors.c4d/RC.c4d/ActMap.txt b/Items.c4d/Sensors.c4d/RC.c4d/ActMap.txt
new file mode 100644
index 0000000..4fd7110
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/RC.c4d/ActMap.txt
@@ -0,0 +1,4 @@
+[Action]
+Name=Active
+FacetBase=1
+Facet=0,12,2,105,5,-105
diff --git a/Items.c4d/Sensors.c4d/RC.c4d/DefCore.txt b/Items.c4d/Sensors.c4d/RC.c4d/DefCore.txt
new file mode 100644
index 0000000..1a6fc10
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/RC.c4d/DefCore.txt
@@ -0,0 +1,21 @@
+[DefCore]
+id=RC7I
+Name=Remote control
+Version=4,9,5
+Category=C4D_Object|C4D_SelectHomebase|C4D_SelectKnowledge|C4D_SelectMaterial
+Width=12
+Height=12
+Offset=-6,-6
+Mass=10
+Value=5
+Components=METL=1
+Picture=12,0,52,52
+Vertices=2
+VertexX=1,-1
+VertexFriction=100
+Grab=2
+Collectible=1
+MaxUserSelect=10
+Rotate=1
+Rebuy=1
+NoPushEnter=1
diff --git a/Items.c4d/Sensors.c4d/RC.c4d/Graphics.png b/Items.c4d/Sensors.c4d/RC.c4d/Graphics.png
new file mode 100644
index 0000000..6c18bce
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/RC.c4d/Graphics.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/RC.c4d/Graphics.svg b/Items.c4d/Sensors.c4d/RC.c4d/Graphics.svg
new file mode 100644
index 0000000..e1cbd28
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/RC.c4d/Graphics.svg
@@ -0,0 +1,311 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="64"
+ version="1.1"
+ height="64"
+ id="svg2"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="Graphics.svg">
+ <sodipodi:namedview
+ pagecolor="#d82c2c"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="1051"
+ id="namedview46"
+ showgrid="false"
+ inkscape:zoom="1.84375"
+ inkscape:cx="70.392402"
+ inkscape:cy="228.58413"
+ inkscape:window-x="2010"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1-3" />
+ <defs
+ id="defs5455">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 32 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="64 : 32 : 1"
+ inkscape:persp3d-origin="32 : 21.333333 : 1"
+ id="perspective4190" />
+ <linearGradient
+ id="linearGradient4176"
+ osb:paint="solid">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop4178" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4417"
+ xlink:href="#linearGradient4159"
+ y1="24"
+ y2="7.999974"
+ gradientUnits="userSpaceOnUse"
+ x2="0"
+ gradientTransform="translate(384.42761,521.11928)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4449"
+ xlink:href="#linearGradient4219"
+ y1="532.79797"
+ y2="526.79797"
+ gradientUnits="userSpaceOnUse"
+ x2="0"
+ gradientTransform="translate(-0.14381833,5.3212782)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4467"
+ xlink:href="#linearGradient4159"
+ y1="533.79797"
+ y2="523.79797"
+ gradientUnits="userSpaceOnUse"
+ x2="0"
+ gradientTransform="translate(-0.14381833,5.3212782)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4499"
+ xlink:href="#linearGradient4159"
+ y1="536.79797"
+ y2="532.79797"
+ gradientUnits="userSpaceOnUse"
+ x2="0"
+ gradientTransform="translate(0.85621167,5.3212782)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4529"
+ xlink:href="#linearGradient4219"
+ y1="20"
+ y2="18"
+ gradientUnits="userSpaceOnUse"
+ x2="0"
+ gradientTransform="translate(384.42761,521.11928)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4219">
+ <stop
+ style="stop-color:#999a9c"
+ id="stop4221" />
+ <stop
+ offset="1"
+ style="stop-color:#f4f5f5"
+ id="stop4223" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4159">
+ <stop
+ style="stop-color:#2a2c2f"
+ id="stop4161" />
+ <stop
+ offset="1"
+ style="stop-color:#424649"
+ id="stop4163" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4347">
+ <stop
+ style="stop-color:#f33777"
+ id="stop4349" />
+ <stop
+ offset="1"
+ style="stop-color:#fd2d65"
+ id="stop4351" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4280">
+ <stop
+ style="stop-color:#c0392b"
+ id="stop4282" />
+ <stop
+ offset="1"
+ style="stop-color:#e74c3c"
+ id="stop4284" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4264">
+ <stop
+ style="stop-color:#2980b9"
+ id="stop4266" />
+ <stop
+ offset="1"
+ style="stop-color:#3498db"
+ id="stop4268" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4255">
+ <stop
+ style="stop-color:#27ae60"
+ id="stop4257" />
+ <stop
+ offset="1"
+ style="stop-color:#2ecc71"
+ id="stop4259" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4725"
+ xlink:href="#linearGradient4264"
+ y1="532.79797"
+ y2="530.79797"
+ gradientUnits="userSpaceOnUse"
+ x2="0"
+ gradientTransform="translate(-0.14381833,5.3212782)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4733"
+ xlink:href="#linearGradient4255"
+ y1="528.79797"
+ y2="526.79797"
+ gradientUnits="userSpaceOnUse"
+ x2="0"
+ gradientTransform="translate(-0.14381833,5.3212782)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4741"
+ xlink:href="#linearGradient4280"
+ y1="530.79797"
+ y2="528.79797"
+ gradientUnits="userSpaceOnUse"
+ x2="0"
+ gradientTransform="translate(-0.14381833,5.3212782)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4749"
+ xlink:href="#linearGradient4347"
+ y1="530.79797"
+ y2="528.79797"
+ gradientUnits="userSpaceOnUse"
+ x2="0"
+ gradientTransform="translate(-0.14381833,5.3212782)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4219"
+ id="linearGradient4188"
+ x1="400.45703"
+ y1="523.32343"
+ x2="400.95703"
+ y2="523.32343"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(14.174709,0,0,14.174709,-5281.1937,-6964.4697)" />
+ </defs>
+ <metadata
+ id="metadata5458">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Capa 1"
+ inkscape:groupmode="layer"
+ id="layer1-3"
+ transform="matrix(2 0 0 2 -769.14286 -1031.596)">
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4188);stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 398.71188,533.2502 0,-159.52542"
+ id="path4174"
+ inkscape:connector-curvature="0"
+ inkscape:export-filename="/media/oldarch/home/maxmitti/clonk/TodsStuff.c4d/DTSensors.c4d/Items.c4d/Sensors.c4d/RC.c4d/path4174.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <circle
+ cx="393.42761"
+ cy="535.11926"
+ style="fill:#e3dbdb;stroke-width:0.1;stroke-linecap:square"
+ id="ellipse4246"
+ r="0" />
+ <g
+ id="g4324"
+ inkscape:export-filename="/media/oldarch/home/maxmitti/clonk/TodsStuff.c4d/DTSensors.c4d/Items.c4d/Sensors.c4d/RC.c4d/Portrait.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <g
+ transform="translate(-1.7157267,3.0447673)"
+ id="g4220">
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient4417);stroke-width:0.1;stroke-linecap:square"
+ id="path4220"
+ d="m 388.42761,535.11928 -0.9414,7.52539 c -0.0385,0.15529 -0.0581,0.31463 -0.0586,0.47461 0,1.10457 0.89543,2 2,2 0.59429,-5.5e-4 1.15756,-0.26536 1.53711,-0.72266 l 0.002,0.004 5.46094,-6.28124 z m 24,0 -8,3 5.46094,6.28125 0.002,-0.004 c 0.37951,0.45729 0.94277,0.7221 1.53706,0.72265 1.10457,0 2,-0.89543 2,-2 -4.8e-4,-0.15998 -0.0202,-0.31932 -0.0586,-0.47461 z" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient4467);stroke-width:0.1;stroke-linecap:square"
+ id="rect4234"
+ d="m 394.42761,529.11928 c -3.31371,0 -6,2.68629 -6,6 0,3.31371 2.68629,6 6,6 1.17775,-10e-4 2.32909,-0.34898 3.31055,-1 l 5.3789,0 c 0.98146,0.65102 2.13281,0.9988 3.31055,1 3.31371,0 6,-2.68629 6,-6 0,-3.31371 -2.68629,-6 -6,-6 l -5,0 -2,0 z" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient4733);stroke-width:0.1;stroke-linecap:square"
+ id="path4717"
+ d="m 407.42761,532.11928 a 1,1 0 0 0 -1,1 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient4749);stroke-width:0.1;stroke-linecap:square"
+ id="path4715"
+ d="m 405.42761,534.11928 a 1,1 0 0 0 -1,1 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient4741);stroke-width:0.1;stroke-linecap:square"
+ id="path4713"
+ d="m 409.42761,534.11928 a 1,1 0 0 0 -1,1 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient4725);stroke-width:0.1;stroke-linecap:square"
+ id="path4268"
+ d="m 407.42761,536.11928 a 1,1 0 0 0 -1,1 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient4449);stroke-width:0.1;stroke-linecap:square"
+ id="rect4297"
+ d="m 392.42761,532.11928 0,2 -2,0 0,2 2,0 0,2 2,0 0,-2 2,0 0,-2 -2,0 0,-2 -2,0 z" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient4499);stroke-width:0.033333;stroke-linecap:square"
+ id="circle4489"
+ d="m 397.42761,538.11928 a 2,2 0 0 0 -2,2 2,2 0 0 0 2,2 2,2 0 0 0 2,-2 2,2 0 0 0 -2,-2 z m 6,0 a 2,2 0 0 0 -2,2 2,2 0 0 0 2,2 2,2 0 0 0 2,-2 2,2 0 0 0 -2,-2 z" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:url(#linearGradient4529);stroke-width:0.1;stroke-linecap:square"
+ id="path4518"
+ d="m 397.42761,539.11928 a 0.99999398,0.99999398 0 0 0 -1,1 0.99999398,0.99999398 0 0 0 1,1 0.99999398,0.99999398 0 0 0 1,-1 0.99999398,0.99999398 0 0 0 -1,-1 z m 6,0 a 1.000006,1.000006 0 0 0 -1,1 1.000006,1.000006 0 0 0 1,1 1.000006,1.000006 0 0 0 1,-1 1.000006,1.000006 0 0 0 -1,-1 z" />
+ </g>
+ <rect
+ ry="1.25"
+ rx="1.25"
+ y="522.57532"
+ x="385.71188"
+ height="26"
+ width="26"
+ id="rect4231"
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ </g>
+</svg>
diff --git a/Items.c4d/Sensors.c4d/RC.c4d/Names.txt b/Items.c4d/Sensors.c4d/RC.c4d/Names.txt
new file mode 100644
index 0000000..51b0792
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/RC.c4d/Names.txt
@@ -0,0 +1,2 @@
+DE:Fernsteuerung
+US:Remote control
diff --git a/Items.c4d/Sensors.c4d/RC.c4d/Script.c b/Items.c4d/Sensors.c4d/RC.c4d/Script.c
new file mode 100644
index 0000000..933d875
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/RC.c4d/Script.c
@@ -0,0 +1,721 @@
+#strict 2
+#include SN7I
+
+local viewTarget;
+local user;
+local controlTimer;
+local realAttachPos;
+
+// _enum(RC7I_Control_, L, LS, LD, LR, R, RS, RD, RR, U, US, UD, UR, D, DS, DD, DR, T, TS, TD, TR, Q, QS, QD, QR, S, SS, SD, SR, Z, ZS, ZD, ZR, V)
+static const RC7I_Control_L = 0;
+static const RC7I_Control_LS = 1;
+static const RC7I_Control_LD = 2;
+static const RC7I_Control_LR = 3;
+static const RC7I_Control_R = 4;
+static const RC7I_Control_RS = 5;
+static const RC7I_Control_RD = 6;
+static const RC7I_Control_RR = 7;
+static const RC7I_Control_U = 8;
+static const RC7I_Control_US = 9;
+static const RC7I_Control_UD = 10;
+static const RC7I_Control_UR = 11;
+static const RC7I_Control_D = 12;
+static const RC7I_Control_DS = 13;
+static const RC7I_Control_DD = 14;
+static const RC7I_Control_DR = 15;
+static const RC7I_Control_T = 16;
+static const RC7I_Control_TS = 17;
+static const RC7I_Control_TD = 18;
+static const RC7I_Control_TR = 19;
+static const RC7I_Control_Q = 20;
+static const RC7I_Control_QS = 21;
+static const RC7I_Control_QD = 22;
+static const RC7I_Control_QR = 23;
+static const RC7I_Control_S = 24;
+static const RC7I_Control_SS = 25;
+static const RC7I_Control_SD = 26;
+static const RC7I_Control_SR = 27;
+static const RC7I_Control_Z = 28;
+static const RC7I_Control_ZS = 29;
+static const RC7I_Control_ZD = 30;
+static const RC7I_Control_ZR = 31;
+static const RC7I_Control_V = 32;
+
+func GetControlName(int ctrl)
+{
+ return ["$Left$" ,
+ "$LeftSingle$" ,
+ "$LeftDouble$" ,
+ "$LeftReleased$" ,
+ "$Right$" ,
+ "$RightSingle$" ,
+ "$RightDouble$" ,
+ "$RightReleased$" ,
+ "$Up$" ,
+ "$UpSingle$" ,
+ "$UpDouble$" ,
+ "$UpReleased$" ,
+ "$Down$" ,
+ "$DownSingle$" ,
+ "$DownDouble$" ,
+ "$DownReleased$" ,
+ "$Throw$" ,
+ "$ThrowSingle$" ,
+ "$ThrowDouble$" ,
+ "$ThrowReleased$" ,
+ "$Dig$" ,
+ "$DigSingle$" ,
+ "$DigDouble$" ,
+ "$DigReleased$" ,
+ "$Special$" ,
+ "$SpecialSingle$" ,
+ "$SpecialDouble$" ,
+ "$SpecialReleased$" ,
+ "$Special2$" ,
+ "$Special2Single$" ,
+ "$Special2Double$" ,
+ "$Special2Released$" ,
+ "$Update$"
+ ][ctrl];
+}
+
+func Triggers()
+{
+ return [["$Left$" ],
+ ["$LeftSingle$" ],
+ ["$LeftDouble$" ],
+ ["$LeftReleased$" ],
+ ["$Right$" ],
+ ["$RightSingle$" ],
+ ["$RightDouble$" ],
+ ["$RightReleased$" ],
+ ["$Up$" ],
+ ["$UpSingle$" ],
+ ["$UpDouble$" ],
+ ["$UpReleased$" ],
+ ["$Down$" ],
+ ["$DownSingle$" ],
+ ["$DownDouble$" ],
+ ["$DownReleased$" ],
+ ["$Throw$" ],
+ ["$ThrowSingle$" ],
+ ["$ThrowDouble$" ],
+ ["$ThrowReleased$" ],
+ ["$Dig$" ],
+ ["$DigSingle$" ],
+ ["$DigDouble$" ],
+ ["$DigReleased$" ],
+ ["$Special$" ],
+ ["$SpecialSingle$" ],
+ ["$SpecialDouble$" ],
+ ["$SpecialReleased$" ],
+ ["$Special2$" ],
+ ["$Special2Single$" ],
+ ["$Special2Double$" ],
+ ["$Special2Released$" ],
+ ["$Update$" ]];
+}
+
+global func IsRemoteControllable(object controller)
+{
+ return GetOCF() & OCF_Grab;
+}
+
+global func RemoteControlMap(object controller)
+{
+ if(this->~IsRemoteControllable(controller))
+ {
+ if(GetOCF() & OCF_Grab)
+ {
+ return
+ [
+ [RC7I_Control_L, "ControlLeft" ],
+ [RC7I_Control_LS, "ControlLeftSingle" ],
+ [RC7I_Control_LD, "ControlLeftDouble" ],
+ [RC7I_Control_LR, "ControlLeftReleased" ],
+ [RC7I_Control_R, "ControlRight" ],
+ [RC7I_Control_RS, "ControlRightSingle" ],
+ [RC7I_Control_RD, "ControlRightDouble" ],
+ [RC7I_Control_RR, "ControlRightReleased" ],
+ [RC7I_Control_U, "ControlUp" ],
+ [RC7I_Control_US, "ControlUpSingle" ],
+ [RC7I_Control_UD, "ControlUpDouble" ],
+ [RC7I_Control_UR, "ControlUpReleased" ],
+ [RC7I_Control_D, "ControlDown" ],
+ [RC7I_Control_DS, "ControlDownSingle" ],
+ [RC7I_Control_DD, "ControlDownDouble" ],
+ [RC7I_Control_DR, "ControlDownReleased" ],
+ [RC7I_Control_T, "ControlThrow" ],
+ [RC7I_Control_TS, "ControlThrowSingle" ],
+ [RC7I_Control_TD, "ControlThrowDouble" ],
+ [RC7I_Control_TR, "ControlThrowReleased" ],
+ [RC7I_Control_Q, "ControlDig" ],
+ [RC7I_Control_QS, "ControlDigSingle" ],
+ [RC7I_Control_QD, "ControlDigDouble" ],
+ [RC7I_Control_QR, "ControlDigReleased" ],
+ [RC7I_Control_S, "ControlSpecial" ],
+ [RC7I_Control_SS, "ControlSpecialSingle" ],
+ [RC7I_Control_SD, "ControlSpecialDouble" ],
+ [RC7I_Control_SR, "ControlSpecialReleased" ],
+ [RC7I_Control_Z, "ControlSpecial2" ],
+ [RC7I_Control_ZS, "ControlSpecial2Single" ],
+ [RC7I_Control_ZD, "ControlSpecial2Double" ],
+ [RC7I_Control_ZR, "ControlSpecial2Released" ],
+ [RC7I_Control_V, "ControlUpdate" ],
+ [RC7I_Control_L, BindCallback(RC7I->Callback("UpdateTargetDir"), [Bind(this), Bind(DIR_Left)]), "$ChangeDirLeft$"],
+ [RC7I_Control_R, BindCallback(RC7I->Callback("UpdateTargetDir"), [Bind(this), Bind(DIR_Right)]), "$ChangeDirRight$"],
+ [RC7I_Control_S, BindCallback(RC7I->Callback("ShiftTargetContents"), [Bind(this)]), "$ShiftContents$"],
+ [RC7I_Control_SD, BindCallback(RC7I->Callback("ShiftTargetContents"), [Bind(this)]), "$ShiftContents$"]
+ ];
+ }
+ else if(GetOCF() & OCF_Entrance)
+ {
+ return
+ [
+ [RC7I_Control_L, "ContainedLeft" ],
+ [RC7I_Control_LS, "ContainedLeftSingle" ],
+ [RC7I_Control_LD, "ContainedLeftDouble" ],
+ [RC7I_Control_LR, "ContainedLeftReleased" ],
+ [RC7I_Control_R, "ContainedRight" ],
+ [RC7I_Control_RS, "ContainedRightSingle" ],
+ [RC7I_Control_RD, "ContainedRightDouble" ],
+ [RC7I_Control_RR, "ContainedRightReleased" ],
+ [RC7I_Control_U, "ContainedUp" ],
+ [RC7I_Control_US, "ContainedUpSingle" ],
+ [RC7I_Control_UD, "ContainedUpDouble" ],
+ [RC7I_Control_UR, "ContainedUpReleased" ],
+ [RC7I_Control_D, "ContainedDown" ],
+ [RC7I_Control_DS, "ContainedDownSingle" ],
+ [RC7I_Control_DD, "ContainedDownDouble" ],
+ [RC7I_Control_DR, "ContainedDownReleased" ],
+ [RC7I_Control_T, "ContainedThrow" ],
+ [RC7I_Control_TS, "ContainedThrowSingle" ],
+ [RC7I_Control_TD, "ContainedThrowDouble" ],
+ [RC7I_Control_TR, "ContainedThrowReleased" ],
+ [RC7I_Control_Q, "ContainedDig" ],
+ [RC7I_Control_QS, "ContainedDigSingle" ],
+ [RC7I_Control_QD, "ContainedDigDouble" ],
+ [RC7I_Control_QR, "ContainedDigReleased" ],
+ [RC7I_Control_V, "ContainedUpdate" ],
+ [RC7I_Control_S, BindCallback(RC7I->Callback("ShiftTargetContents"), [Bind(this)]), "$ShiftContents$"],
+ [RC7I_Control_SD, BindCallback(RC7I->Callback("ShiftTargetContents"), [Bind(this)]), "$ShiftContents$"]
+ ];
+ }
+ }
+}
+
+
+func Setup(object caller, int &menuIndex)
+{
+ AddMenuItem("$AddControlTarget$", "AutoTarget", GetID(), caller, 0, caller, 0, C4MN_Add_ForceNoDesc);
+ ++menuIndex;
+ AddMenuItem("$SetViewObject$", "SelectViewObject", GetID(), caller, 0, caller, 0, C4MN_Add_ForceNoDesc);
+ ++menuIndex;
+ return true;
+}
+
+func GetPossibleTargets(object caller)
+{
+ return FindObjects((caller || this)->Find_AtPoint(), Find_Not(Find_Hostile(GetOwner(this))), Find_Func("IsRemoteControllable", this), Find_NoContainer(), Find_Exclude(this));
+}
+
+func AutoTarget(id id, object caller)
+{
+ var objs = GetPossibleTargets(caller);
+ var ret = caller->~CreateSelectionMenu("AddTarget", objs, GetID(), SelectTargetText(), this);
+ return ret;
+}
+
+func SelectViewObject(id id, object caller)
+{
+ var objs = GetPossibleTargets(caller);
+ var ret = caller->~CreateSelectionMenu("SetViewObject", objs, GetID(), SelectTargetText(), this);
+ if(ret && viewTarget)
+ {
+ AddMenuItem(RemoveTargetText(), "SetViewObject", GetID(), caller, 0, 0, 0, C4MN_Add_ForceNoDesc);
+ }
+ return ret;
+}
+
+func SetViewObject(id id, object obj)
+{
+ viewTarget = obj;
+}
+
+func Activate(object caller)
+{
+ if(!triggerCallbacks || !GetLength(triggerCallbacks))
+ {
+ _Setup(caller);
+ return true;
+ }
+ else if(caller)
+ {
+ user = caller;
+ caller->Exit(this);
+ realAttachPos = attachPos;
+ RemoteControlTimer(true);
+ controlTimer = AddTimer("RemoteControlTimer", 1);
+ SetCursor(GetController(caller), this);
+ if(viewTarget)
+ {
+ SetViewCursor(GetController(caller), viewTarget);
+ caller->CreateSelectMark()->MarkObject(viewTarget, 35);
+ }
+ SetCommand(caller, "Grab", this);
+ ExecuteCommand(caller);
+ SetAction("Active");
+ return true;
+ }
+ else if(!Attached())
+ {
+ return ControlDigDouble(caller, ...);
+ }
+}
+
+func ControlDigDouble(object caller)
+{
+ if(user || (caller && (GetProcedure(caller) != "PUSH" || GetActionTarget(0, caller) != this) && Contained() != caller))
+ {
+ Trigger(RC7I_Control_QD, caller || user, ...);
+ return true;
+ }
+ else if(Attached())
+ {
+ return Activate(caller, ...);
+ }
+}
+
+func RemoteControlTimer(bool first)
+{
+ if(!first && (GetProcedure(user) != "PUSH" || GetActionTarget(0, user) != this || !user))
+ {
+ SetCursor(GetOwner(user), user);
+ }
+ else
+ {
+ if(!GetPlrView(GetController(user)) && viewTarget && (first || !GetPlayerVal("MouseControl", "Player", GetController(user))))
+ {
+ SetPlrView(GetController(user), viewTarget);
+ }
+ SetSpeed();
+ if(viewTarget)
+ {
+ user->SetDir(GetX(viewTarget) > GetX(user));
+ }
+ SetR((2 * GetDir(user) - 1) * 30);
+ attachPos = [GetX(user) + (2 * GetDir(user) - 1) * 5, GetY(user)];
+ if(!Attached())
+ {
+ SetPosition(attachPos[0], attachPos[1]);
+ }
+ }
+}
+
+func AllowEntrance() { return !user; }
+
+func ControlUpdate(object caller)
+{
+ if(user || (caller && Contained() != caller))
+ {
+ return Trigger(RC7I_Control_V, user || caller, ...);
+ }
+}
+
+func ControlLeft(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_L, caller || user, ...);
+ }
+}
+
+func ControlLeftSingle(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_LS, caller || user, ...);
+ }
+}
+
+func ControlLeftDouble(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_LD, caller || user, ...);
+ }
+}
+
+func ControlLeftReleased(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_LR, caller || user, ...);
+ }
+}
+
+func ControlRight(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_R, caller || user, ...);
+ }
+}
+
+func ControlRightSingle(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_RS, caller || user, ...);
+ }
+}
+
+func ControlRightDouble(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_RD, caller || user, ...);
+ }
+}
+
+func ControlRightReleased(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_RR, caller || user, ...);
+ }
+}
+
+func ControlUp(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_U, caller || user, ...);
+ }
+}
+
+func ControlUpSingle(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_US, caller || user, ...);
+ }
+}
+
+func ControlUpDouble(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_UD, caller || user, ...);
+ }
+}
+
+func ControlUpReleased(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_UR, caller || user, ...);
+ }
+}
+
+func ControlDown(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_D, caller || user, ...);
+ }
+}
+
+func ControlDownSingle(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_DS, caller || user, ...);
+ }
+}
+
+func ControlDownDouble(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_DD, caller || user, ...);
+ }
+}
+
+func ControlDownReleased(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_DR, caller || user, ...);
+ }
+}
+
+func ControlThrow(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_T, caller || user, ...);
+ }
+}
+
+func ControlThrowSingle(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_TS, caller || user, ...);
+ }
+}
+
+func ControlThrowDouble(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_TD, caller || user, ...);
+ }
+}
+
+func ControlThrowReleased(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_TR, caller || user, ...);
+ }
+}
+
+func ControlDig(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_Q, caller || user, ...);
+ }
+}
+
+func ControlDigSingle(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_QS, caller || user, ...);
+ }
+}
+
+func ControlDigReleased(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_QD, caller || user, ...);
+ }
+}
+
+func ControlSpecial(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_S, caller || user, ...);
+ }
+}
+
+func ControlSpecialSingle(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_SS, caller || user, ...);
+ }
+}
+
+func ControlSpecialDouble(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_SD, caller || user, ...);
+ }
+}
+
+func ControlSpecialReleased(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_SR, caller || user, ...);
+ }
+}
+
+func ControlSpecial2(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_Z, caller || user, ...);
+ }
+}
+
+func ControlSpecial2Single(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_ZS, caller || user, ...);
+ }
+}
+
+func ControlSpecial2Double(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_ZD, caller || user, ...);
+ }
+}
+
+func ControlSpecial2Released(object caller)
+{
+ if((caller && Contained() != caller) || user)
+ {
+ return Trigger(RC7I_Control_ZR, caller || user, ...);
+ }
+}
+
+
+func UpdateTargetDir(object target, int dir)
+{
+ if(GetXDir(target) == 0)
+ {
+ SetDir(dir, target);
+ }
+}
+
+func ShiftTargetContents(object target)
+{
+ ShiftContents(target, false, 0, true);
+}
+
+func AddTarget(id id, object obj)
+{
+ if(!triggerCallbacks && !viewTarget)
+ {
+ SetViewObject(id, obj);
+ }
+ for(var mapping in obj->RemoteControlMap(this))
+ {
+ AddTargetAction(mapping[0], obj, [mapping[2] || GetControlName(mapping[0]), mapping[1]]);
+ }
+}
+
+func CrewSelection(bool deselect)
+{
+ if(deselect)
+ {
+ if(user)
+ {
+ SetViewCursor(GetController(user), 0);
+ }
+ SetCursor(GetController(user), user);
+ if(!Attached())
+ {
+ SetCommand(user, "UnGrab");
+ }
+ user = 0;
+ SetCategory(GetCategory(0, GetID()));
+ if(!Attached())
+ {
+ SetAction("Idle");
+ SetR(0);
+ }
+ if(controlTimer)
+ {
+ RemoveTimer(controlTimer);
+ attachPos = realAttachPos;
+ }
+ }
+}
+
+func Selection()
+{
+ if(viewTarget)
+ {
+ PlayerMessage(GetOwner(Contained()), "%s: {{%i}} %s%s", Contained(), TargetText(), GetID(viewTarget), GetName(viewTarget), ((!desc || !descVisible) && "") || "|");
+ Contained()->CreateSelectMark()->MarkObject(viewTarget, 35);
+ }
+}
+
+func Entrance(object container)
+{
+ if(GetOCF(container) & OCF_CrewMember)
+ {
+ Selection();
+ }
+}
+
+global func FxIntJnRAimTimer(object target, int number, int time)
+{
+ // Controller weg?
+ var controller = EffectVar(2, target, number);
+ if(!controller) return(-1);
+
+ // Controller muss Fahrzeug anfassen
+ if(target)
+ if(target->GetCategory() & C4D_Vehicle)
+ if(controller->GetProcedure() != "PUSH" || (controller->GetActionTarget() != target && GetID(controller->GetActionTarget()) != RC7I))
+ return FX_Execute_Kill;
+
+ if(target)
+ target->AimConf(EffectVar(0, target, number), EffectVar(1, target, number), EffectVar(2, target, number));
+ else if(EffectVar(3, target, number))
+ AimConf(EffectVar(0, target, number), EffectVar(1, target, number), EffectVar(2, target, number), EffectVar(3, target, number));
+ else
+ // Global call via eval()?
+ ;
+}
+
+func Attach(object caller)
+{
+ if(!user)
+ {
+ SetAction("Active");
+ var dir;
+ if(viewTarget)
+ {
+ dir = GetX(viewTarget) > GetX();
+ }
+ else
+ {
+ dir = Random(2);
+ }
+ SetR((dir * 2 - 1) * 30);
+ }
+ SetPosition(GetX(caller) + (2 * GetDir(caller) - 1) * 5, GetY(caller));
+}
+
+func Detach()
+{
+ if(!user)
+ {
+ SetAction("Idle");
+ SetR(0);
+ }
+}
+
+func AttachCondition() { return !user; }
+
+func DetachCondition() { return !user; }
+
+func IsRemoteControllable() { return true; }
+
+
+global func CreateMenu(sym, object menuObject)
+{
+ var mObj = menuObject || this;
+ var actionTarget = GetActionTarget(0, menuObject);
+ if(menuObject && menuObject->GetProcedure() == "PUSH" && GetID(actionTarget) == RC7I && LocalN("user", actionTarget) == menuObject)
+ {
+ menuObject = actionTarget;
+ }
+ return _inherited(sym, menuObject, ...);
+}
+
+global func AddMenuItem(caption, command, sym, object menuObject)
+{
+ var mObj = menuObject || this;
+ var actionTarget = GetActionTarget(0, menuObject);
+ if(menuObject && menuObject->GetProcedure() == "PUSH" && GetID(actionTarget) == RC7I && LocalN("user", actionTarget) == menuObject)
+ {
+ menuObject = actionTarget;
+ }
+ return _inherited(caption, command, sym, menuObject, ...);
+
+}
diff --git a/Items.c4d/Sensors.c4d/RC.c4d/StringTblDE.txt b/Items.c4d/Sensors.c4d/RC.c4d/StringTblDE.txt
new file mode 100644
index 0000000..c4bbecb
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/RC.c4d/StringTblDE.txt
@@ -0,0 +1,39 @@
+Left=Links
+LeftSingle=Einfach Links
+LeftDouble=Doppelt Links
+LeftReleased=Links loslassen
+Right=Rechts
+RightSingle=Einfach Rechts
+RightDouble=Doppelt Rechts
+RightReleased=Rechts loslassen
+Up=Hoch
+UpSingle=Einfach Hoch
+UpDouble=Doppelt Hoch
+UpReleased=Hoch loslassen
+Down=Runter
+DownSingle=Einfach Runter
+DownDouble=Doppelt Runter
+DownReleased=Runter loslassen
+Throw=Werfen
+ThrowSingle=Einfach Werfen
+ThrowDouble=Doppelt Werfen
+ThrowReleased=Werfen loslassen
+Dig=Graben
+DigSingle=Einfach Graben
+DigDouble=Doppelt Graben
+DigReleased=Graben loslassen
+Special=Spezial
+SpecialSingle=Einfach Spezial
+SpecialDouble=Doppelt Spezial
+SpecialReleased=Spezial loslassen
+Special2=Spezial 2
+Special2Single=Einfach Spezial 2
+Special2Double=Doppelt Spezial 2
+Special2Released=Spezial 2 loslassen
+Update=Steuerungsupdate
+ChangeDirLeft=Blickrichtung links
+ChangeDirRight=Blickrichtung rechts
+ShiftContents=Inventarwechsel
+
+AddControlTarget=Steuerziel hinzufügen
+SetViewObject=Sichtobjekt wählen
diff --git a/Items.c4d/Sensors.c4d/RC.c4d/StringTblUS.txt b/Items.c4d/Sensors.c4d/RC.c4d/StringTblUS.txt
new file mode 100644
index 0000000..fe37386
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/RC.c4d/StringTblUS.txt
@@ -0,0 +1,39 @@
+Left=Left
+LeftSingle=Left single
+LeftDouble=Left double
+LeftReleased=Left released
+Right=Right
+RightSingle=Right single
+RightDouble=Right double
+RightReleased=Right released
+Up=Up
+UpSingle=Up single
+UpDouble=Up double
+UpReleased=Up released
+Down=Down
+DownSingle=Down single
+DownDouble=Down double
+DownReleased=Down released
+Throw=Throw
+ThrowSingle=Throw single
+ThrowDouble=Throw double
+ThrowReleased=Throw released
+Dig=Dig
+DigSingle=Dig single
+DigDouble=Dig double
+DigReleased=Dig released
+Special=Special
+SpecialSingle=Special single
+SpecialDouble=Special double
+SpecialReleased=Special released
+Special2=Special 2
+Special2Single=Special 2 single
+Special2Double=Special 2 double
+Special2Released=Special 2 released
+Update=Control update
+ChangeDirLeft=Direction left
+ChangeDirRight=Direction right
+ShiftContents=Shift contents
+
+AddControlTarget=Add control target
+SetViewObject=Select view object
diff --git a/Items.c4d/Sensors.c4d/Sensor.c4d/DefCore.txt b/Items.c4d/Sensors.c4d/Sensor.c4d/DefCore.txt
new file mode 100644
index 0000000..bf25a7a
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Sensor.c4d/DefCore.txt
@@ -0,0 +1,4 @@
+[DefCore]
+id=SN7I
+Name=Sensor base
+Category=C4D_StaticBack
diff --git a/Items.c4d/Sensors.c4d/Sensor.c4d/Graphics.png b/Items.c4d/Sensors.c4d/Sensor.c4d/Graphics.png
new file mode 100644
index 0000000..2326ee6
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Sensor.c4d/Graphics.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/Sensor.c4d/Script.c b/Items.c4d/Sensors.c4d/Sensor.c4d/Script.c
new file mode 100644
index 0000000..30bf933
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Sensor.c4d/Script.c
@@ -0,0 +1,791 @@
+#strict 2 // TODO: catch ChangeDef and Fire (because of BurnTo. ignore BuildTo because connecting construction sites is nonsense, isnt it?)
+
+local attached;
+local selectCaller, selectTrigger, selectCallbacks, selectTarget, selectTargets, selectTargetsMax;
+local triggerCallbacks;
+local desc, descVisible;
+local attachPos;
+local entrance;
+
+static const SN7I_Setup_NoDesc = -1;
+
+func Initialize()
+{
+ Init();
+}
+
+func ContextSetup()
+{
+ [$CtxSetup$|Image=RSR1|Condition=_SetupCondition]
+ return _Setup(...);
+}
+
+func ContextAttach()
+{
+ [$Attach$|Image=CXCN|Condition=_AttachCondition]
+ return _Attach(...);
+}
+
+func ContextDetach()
+{
+ [$Detach$|Image=CXCN|Condition=_DetachCondition]
+ return _Detach(...);
+}
+
+func Attached() { return !!attached; }
+
+func RejectContents() { return true; }
+func RejectEntrance() { return attached || !AllowEntrance(); }
+func AllowEntrance() { return true; }
+func Setup() { return true; }
+func Attach() { }
+func Detach() { }
+func SetupMenuID() { }
+func Triggers() { return []; }
+
+func AttachCondition() { return true; }
+func DetachCondition() { return true; }
+func SetupCondition() { return true; }
+
+func SelectTargetText() { return "$SelectTarget$"; }
+func RemoveTargetText() { return "$RemoveTarget$"; }
+func TargetText() { return "$Target$"; }
+
+func EntranceCallback() { }
+
+func Init() { }
+
+func AttachFixPosition() { return true; }
+
+func Activate(object caller)
+{
+ return SetupCondition(caller) && _Setup(caller, ...);
+}
+
+func ControlDigDouble()
+{
+ return Attached() && Activate(...);
+}
+
+func DenyHostility(object caller)
+{
+ return !Hostile(GetOwner(), GetOwner(caller));
+}
+
+func _SetupCondition(object caller)
+{
+ return DenyHostility(caller);
+}
+
+func _Setup(object caller, bool selectDescChange, bool selectDescToggle)
+{
+ if(!DenyHostility(caller))
+ {
+ return 0;
+ }
+ if(CreateMenu(RSR1, caller, this, C4MN_Extra_None, Format("$Setup$", GetName()), 0, C4MN_Style_Context, 0, SetupMenuID()))
+ {
+ var i = 0;
+ selectTrigger = 0;
+ AddMenuItem("$AddTarget$", "AddSensorTarget", GetID(), caller, 0, caller, 0, C4MN_Add_ForceNoDesc);
+ ++i;
+ if(triggerCallbacks && GetLength(triggerCallbacks))
+ {
+ AddMenuItem("$RemoveTarget$", "RemoveSensorTarget", GetID(), caller, 0, caller, 0, C4MN_Add_ForceNoDesc);
+ ++i;
+ }
+ var ret = Setup(caller, i, ...);
+ if(ret != SN7I_Setup_NoDesc)
+ {
+ AddMenuItem(Format("$ChangeDesc$", desc || ""), "ChangeDesc", GetID(), caller, 0, caller, 0, C4MN_Add_ForceNoDesc);
+ if(selectDescChange)
+ {
+ SelectMenuItem(i, caller);
+ }
+ ++i;
+ AddMenuItem((!descVisible && "$ShowDesc$") || "$HideDesc$", "ToggleDesc", GetID(), caller, 0, caller, 0, C4MN_Add_ForceNoDesc);
+ if(selectDescToggle)
+ {
+ SelectMenuItem(i, caller);
+ }
+ ++i;
+ }
+ return ret;
+ }
+}
+
+func ChangeDesc(id id, object caller, bool right)
+{
+ if(right)
+ {
+ descVisible = false;
+ desc = 0;
+ ToggleDesc(0, 0, 0, true);
+ }
+
+ if(caller)
+ {
+ _Setup(caller, true);
+ selectCaller = caller;
+ }
+
+ if(!right)
+ {
+ CallMessageBoard(this, false, "$EnterDesc$", GetController(caller));
+ }
+}
+
+func InputCallback(string input, int plr)
+{
+ if(!desc)
+ {
+ descVisible = true;
+ }
+ if(input != "")
+ {
+ desc = input;
+ ToggleDesc(0, 0, 0, true);
+ }
+ _Setup(selectCaller, true);
+}
+
+func ToggleDesc(id id, object caller, bool right, bool update)
+{
+ if(!update)
+ {
+ descVisible = !descVisible;
+ }
+ if(!descVisible)
+ {
+ Message("", this);
+ }
+ else if(desc)
+ {
+ Message("@%s", this, desc);
+ }
+ if(caller && !update)
+ {
+ _Setup(caller, false, true);
+ }
+}
+
+func AddSensorTarget(id id, object caller, bool right, int selection)
+{
+ var itemCommand = (right && "SelectSensorTarget2") || "SelectSensorTarget";
+ selectCaller = caller;
+ if(CreateMenu(GetID(), selectCaller, this, C4MN_Extra_None, "$SelectTrigger$", 0, C4MN_Style_Context, 0))
+ {
+ var i = 0;
+ for(var trigger in Triggers())
+ {
+ var caption = trigger[0];
+ if(GetType(selectTrigger) == C4V_Array)
+ {
+ if(GetIndexOf(i, selectTrigger) != -1)
+ {
+ caption = Format("× %s", caption);
+ }
+ else
+ {
+ caption = Format(" %s", caption);
+ }
+ }
+ AddMenuItem(caption, itemCommand, trigger[1] || GetID(), selectCaller, 0, i++, 0, C4MN_Add_ForceNoDesc);
+ }
+ if(GetType(selectTrigger) == C4V_Array)
+ {
+ AddMenuItem("$Continue$", itemCommand, GetID(), selectCaller, 0, -1, 0, C4MN_Add_ForceNoDesc);
+ }
+ SelectMenuItem(selection, caller);
+ return true;
+ }
+}
+
+local triggerTargetList;
+func RemoveSensorTarget(id id, object caller)
+{
+ if(CreateMenu(GetID(), caller, this, C4MN_Extra_None, SelectTargetText(), 0, C4MN_Style_Context, 0, SELM))
+ {
+ triggerTargetList = [];
+ var j = 0, cnt = 0;
+ for(var trigger in triggerCallbacks)
+ {
+ if(trigger)
+ {
+ var triggerInfo = Triggers()[j], i = 0;
+ for(var callback in trigger)
+ {
+ if(GetType(callback) == C4V_Array)
+ {
+ if(CheckTarget(j, i))
+ {
+ AddMenuItem(Format("%s: {{%i}} %s -> %s", triggerInfo[0], GetID(callback[0]), GetName(callback[0]), callback[1][0]), Format("RemoveSensorTargetIndex(%d, %d, Object(%d), %d)", j, i - 1, ObjectNumber(caller), cnt++), callback[1][2] || GetID(), caller, 0, 0, 0, C4MN_Add_ForceNoDesc);
+ triggerTargetList[GetLength(triggerTargetList)] = callback[0];
+ }
+ }
+ }
+ }
+ ++j;
+ }
+ EffectCall(caller, AddEffect("IntShowSelection", caller, 1, 1, this), "Timer");
+ return true;
+ }
+}
+
+func RemoveSensorTargetIndex(int trigger, int index, object menuObject, int selection)
+{
+ if(triggerCallbacks && triggerCallbacks[trigger])
+ {
+ ArrayErase(triggerCallbacks[trigger], index);
+ if(!GetLength(triggerCallbacks[trigger]))
+ {
+ triggerCallbacks[trigger] = 0;
+ }
+ var empty = true;
+ for(var callbacks in triggerCallbacks)
+ {
+ if(callbacks)
+ {
+ empty = false;
+ break;
+ }
+ }
+ if(!empty && menuObject)
+ {
+ RemoveSensorTarget(0, menuObject);
+ SelectMenuItem(selection && (selection - 1), menuObject); // fallback to previous if next is not existent
+ SelectMenuItem(selection, menuObject);
+ }
+ else
+ {
+ triggerCallbacks = 0;
+ }
+ }
+}
+
+local selectMark;
+func FxIntShowSelectionTimer(object target, int effectNumber)
+{
+ if(GetMenu(target) != SELM)
+ {
+ if(selectMark)
+ {
+ RemoveObject(selectMark);
+ }
+ return FX_Execute_Kill;
+ }
+ else
+ {
+ var obj = triggerTargetList[GetMenuSelection(target)];
+ if(!obj)
+ {
+ if(selectMark)
+ {
+ RemoveObject(selectMark);
+ }
+ }
+ else
+ {
+ selectMark = selectMark || CreateSelectMark();
+ selectMark->MarkObject(obj);
+ }
+ }
+}
+
+func _Attach(object caller)
+{
+ var contained;
+ if(contained = Contained())
+ {
+ contained->Exit(this);
+ SetPosition(GetX(), GetY() + 3);
+ }
+ var ret = Attach(caller, contained, ...);
+ if(AttachFixPosition())
+ {
+ attachPos = [GetX(), GetY()];
+ attached = AddTimer("AttachTimer", 1);
+ }
+ else
+ {
+ attached = true;
+ }
+ if(EntranceCallback())
+ {
+ entrance = CreateObject(SE7I)->Attach(this);
+ }
+ return ret;
+}
+
+func _Detach(object caller)
+{
+ if(Attached())
+ {
+ if(AttachFixPosition())
+ {
+ RemoveTimer(attached);
+ }
+ attached = 0;
+ Collect(this, caller);
+ }
+ if(entrance)
+ {
+ RemoveObject(entrance);
+ }
+ return Detach(...);
+}
+
+func _AttachCondition(object caller)
+{
+ return DenyHostility(caller) && !Attached() && AttachCondition(caller, ...);
+}
+
+func _DetachCondition(object caller)
+{
+ return DenyHostility(caller) && Attached() && DetachCondition(caller, ...);
+}
+
+func AttachTimer()
+{
+ SetPosition(attachPos[0], attachPos[1]);
+ SetSpeed();
+}
+
+global func GetSensorCallbacks(object sensor)
+{
+ var ret = [];
+ // Remote control callbacks
+
+ var customCallbacks = this->~SensorCallbacks(sensor);
+ if(customCallbacks)
+ {
+ ArrayAppendArray(ret, customCallbacks);
+ }
+
+ // Legacy sensor pack (and hazard) support
+ for(var i = 1, name; ; ++i)
+ {
+ if(GetType(name = this->~GetTriggerName(i)) == C4V_String)
+ {
+ ret[GetLength(ret)] = [name, BindCallback("Trigger", [Bind(i), Bind(sensor), 0])]; // 0 = user, rest = other args passed to trigger
+ // WARNING: update mapping when necessary
+ }
+ else if(name = this->~ConsoleControl(i))
+ {
+ ret[GetLength(ret)] = [name, BindCallback(SN7I->Callback("HazardCallback"), [Bind(i), Bind(this), Bind(ObjectNumber(sensor)), 0])]; // 0 = user, rest = other args passed to trigger
+ // WARNING: update mapping when necessary
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if(this->~IsRemoteControllable(sensor))
+ {
+ for(var mapping in this->~RemoteControlMap(sensor))
+ {
+ ret[GetLength(ret)] = [mapping[2] || Format("$Control$", RC7I->GetControlName(mapping[0])), mapping[1]];
+ }
+ }
+ if(GetLength(ret) > 0)
+ {
+ return ret;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+func HazardCallback(int trigger, object target, int sensor, object user)
+{
+ return target->~ConsoleControlled(trigger, ObjectNumber(user), sensor);
+}
+
+func SelectSensorTarget(id id, int index, bool right)
+{
+ if(index != -1 && (right || GetType(selectTrigger) == C4V_Array))
+ {
+ if(GetType(selectTrigger) == C4V_Array)
+ {
+ var idx;
+ if((idx = GetIndexOf(index, selectTrigger)) != -1)
+ {
+ ArrayErase(selectTrigger, idx);
+ }
+ else
+ {
+ selectTrigger[GetLength(selectTrigger)] = index;
+ }
+ }
+ else
+ {
+ selectTrigger = [index];
+ }
+ AddSensorTarget(0, selectCaller, 0, index);
+ }
+ else
+ {
+ if(index != -1)
+ {
+ selectTrigger = index;
+ }
+ if(GetType(selectTrigger) != C4V_Array)
+ {
+ selectTrigger = [selectTrigger];
+ }
+ var targets = FindObjects(selectCaller->Find_AtPoint(), Find_Not(Find_Hostile(GetOwner(this))), Find_Func("GetSensorCallbacks", this), Find_Exclude(this));
+ if(GetLength(targets) > 0)
+ {
+ return selectCaller->~CreateSelectionMenu("SelectTargetAction", targets, GetID(), SelectTargetText(), this);
+ }
+ else
+ {
+ PlayerMessage(GetOwner(selectCaller), "$NoTargets$", this);
+ }
+ }
+}
+
+func SelectSensorTarget2(id id, int index, bool right)
+{
+ if(index != -1 && (right || GetType(selectTrigger) == C4V_Array))
+ {
+ if(GetType(selectTrigger) == C4V_Array)
+ {
+ var idx;
+ if((idx = GetIndexOf(index, selectTrigger)) != -1)
+ {
+ ArrayErase(selectTrigger, idx);
+ }
+ else
+ {
+ selectTrigger[GetLength(selectTrigger)] = index;
+ }
+ }
+ else
+ {
+ selectTrigger = [index];
+ }
+ AddSensorTarget(0, selectCaller, true, index);
+ }
+ else
+ {
+ if(index != -1)
+ {
+ selectTrigger = index;
+ }
+ if(GetType(selectTrigger) != C4V_Array)
+ {
+ selectTrigger = [selectTrigger];
+ }
+ var targets = FindObjects(selectCaller->Find_AtPoint(), Find_Not(Find_Hostile(GetOwner(this))), Find_Func("GetSensorCallbacks", this), Find_Exclude(this));
+ if(GetLength(targets) > 0)
+ {
+ selectTargets = CreateArray(GetLength(targets));
+ selectTargetsMax = 0;
+ for(var i = 0; i < GetLength(targets); ++i)
+ {
+ var target = targets[i];
+ selectTargets[i] = [target, target->GetSensorCallbacks(this), 0];
+ selectTargetsMax = Max(selectTargetsMax, GetLength(selectTargets[i][1]));
+ }
+ SelectTargetActionsSideBySide();
+ }
+ else
+ {
+ PlayerMessage(GetOwner(selectCaller), "$NoTargets$", this);
+ }
+ }
+}
+
+func SelectTargetActionsSideBySide(int mainSelection, int subSelection)
+{
+ SetComDir(COMD_Stop, selectCaller);
+ if(CreateMenu(GetID(), selectCaller, this, C4MN_Extra_None, SelectTargetText(), 0, C4MN_Style_Context, 0, SEN2))
+ {
+ SetMenuSize(2, 0, selectCaller);
+ var i, cnt = Max(GetLength(selectTargets) + 1, GetLength(selectTargets[mainSelection][1]));
+ for(i = 0; i < cnt; ++i)
+ {
+ if(i < GetLength(selectTargets))
+ {
+ var obj = selectTargets[i][0];
+ var caption = Format((selectTargets[i][2] && "· %s") || " %s", GetName(obj));
+ if(i != mainSelection)
+ {
+ caption = Format("<c 808080>%s</c>", caption);
+ }
+ AddMenuItem(caption, "SelectTargetActionObject", GetID(obj), selectCaller, 0, i, 0, C4MN_Add_ForceNoDesc | C4MN_Add_ImgObject, obj);
+ }
+ else if(i == GetLength(selectTargets))
+ {
+ AddMenuItem("$Finish$", "SelectTargetAction2", GetID(), selectCaller, 0, -1, 0, C4MN_Add_ForceNoDesc);
+ }
+ else
+ {
+ AddMenuItem(0, " ", 0, selectCaller);
+ }
+ if(i < GetLength(selectTargets[mainSelection][1]))
+ {
+ var callback = selectTargets[mainSelection][1][i];
+ var caption = Format((callback[10] && "× %s") || " %s", callback[0]);
+ AddMenuItem(caption, "SelectTargetAction2", callback[2] || GetID(selectTargets[mainSelection][0]), selectCaller, 0, i, 0, C4MN_Add_ForceNoDesc);
+ }
+ else
+ {
+ AddMenuItem(0, " ", 0, selectCaller);
+ }
+ }
+ for(; i < selectTargetsMax; ++i)
+ {
+ AddMenuItem(0, " ", 0, selectCaller);
+ AddMenuItem(0, " ", 0, selectCaller);
+ }
+ if(subSelection)
+ {
+ SelectMenuItem(subSelection * 2 - 1, selectCaller);
+ }
+ else
+ {
+ SelectMenuItem(mainSelection * 2, selectCaller);
+ }
+ lastMainRow = mainSelection;
+ if(!GetEffect("IntShowSelection", this))
+ {
+ EffectCall(this, AddEffect("IntShowSelection", this, 100, 2, this), "Timer");
+ }
+ }
+}
+
+func FxIntShowSelectionTimer(object target, int effectNumber)
+{
+ var marker = EffectVar(0, target, effectNumber);
+ if(!selectCaller || GetMenu(selectCaller) != SEN2)
+ {
+ if(marker)
+ {
+ RemoveObject(marker);
+ }
+ return FX_Execute_Kill;
+ }
+
+ if(GetMenuSelection(selectCaller) == GetLength(selectTargets) * 2 || !selectTargets[lastMainRow][0])
+ {
+ if(marker)
+ {
+ RemoveObject(marker);
+ }
+ }
+ else
+ {
+ if(!marker)
+ {
+ marker = selectCaller->CreateSelectMark();
+ }
+ marker->MarkObject(selectTargets[lastMainRow][0]);
+ }
+ EffectVar(0, target, effectNumber) = marker;
+}
+
+func SelectTargetActionObject(id id, int index)
+{
+ for(var i = 0; i < GetLength(selectTargets[index][1]); ++i)
+ {
+ selectTargets[index][1][i][10] = false;
+ }
+ selectTargets[index][2] = 0;
+ SelectTargetActionsSideBySide(lastMainRow);
+}
+
+func SelectTargetAction2(id id, int index)
+{
+ if(index != -1)
+ {
+ selectTargets[lastMainRow][2] += ((selectTargets[lastMainRow][1][index][10] = !selectTargets[lastMainRow][1][index][10]) * 2) - 1;
+ SelectTargetActionsSideBySide(lastMainRow, index + 1);
+ }
+ else
+ {
+ for(var target in selectTargets)
+ {
+ if(target[2] > 0)
+ {
+ for(var trigger in selectTrigger)
+ {
+ for(var callback in target[1])
+ {
+ if(callback[10])
+ {
+ AddTargetAction(trigger, target[0], callback);
+ }
+ }
+ }
+ }
+ }
+ selectTargets = 0;
+ selectTargetsMax = 0;
+ }
+}
+
+local byMenuSelection, lastMainRow, lastSelectedCol;
+func SelectMenuItem(int selection, object menuObject, bool redraw)
+{
+ if(!redraw)
+ {
+ byMenuSelection = true;
+ var ret = _inherited(selection, menuObject);
+ byMenuSelection = false;
+ return ret;
+ }
+ else
+ {
+ return _inherited(selection, menuObject);
+ }
+}
+
+func OnMenuSelection(int selection, object menuObject)
+{
+ if(!byMenuSelection)
+ {
+ if(GetMenu(menuObject) == SEN2)
+ {
+ if(!(selection % 2))
+ {
+ if(lastSelectedCol == 0)
+ {
+ if(selection/2 < GetLength(selectTargets))
+ {
+ CloseMenu(menuObject);
+ SelectTargetActionsSideBySide(selection/2);
+ }
+ else if(selection/2 == GetLength(selectTargets) + 1)
+ {
+ SelectMenuItem(0, menuObject, true);
+ }
+ else if(selection/2 != GetLength(selectTargets))
+ {
+ SelectMenuItem((GetLength(selectTargets) - 1) * 2, menuObject, lastMainRow != (GetLength(selectTargets) - 1));
+ }
+ }
+ else
+ {
+ SelectMenuItem(2 * lastMainRow, menuObject);
+ }
+ lastSelectedCol = 0;
+ }
+ else
+ {
+ if(lastSelectedCol == 0)
+ {
+ SelectMenuItem(1, menuObject);
+ }
+ else
+ {
+ if(selection/2 == GetLength(selectTargets[lastMainRow][1]))
+ {
+ SelectMenuItem(1, menuObject);
+ }
+ else if(selection/2 > GetLength(selectTargets[lastMainRow][1]))
+ {
+ SelectMenuItem(2 * GetLength(selectTargets[lastMainRow][1]) - 1, menuObject);
+ }
+ }
+ lastSelectedCol = 1;
+ }
+ }
+ }
+}
+
+func SelectTargetAction(id id, object target)
+{
+ if(CreateMenu(GetID(), selectCaller, this, C4MN_Extra_None, "$SelectAction$", 0, C4MN_Style_Context, 0))
+ {
+ var i = 0;
+ selectTarget = target;
+ selectCallbacks = target->GetSensorCallbacks(this);
+ for(var callback in selectCallbacks)
+ {
+ AddMenuItem(callback[0], "SetTargetAction", callback[2] || GetID(target), selectCaller, 0, i++, 0, C4MN_Add_ForceNoDesc);
+ }
+ }
+}
+
+func SetTargetAction(id id, int index)
+{
+ for(var trigger in selectTrigger)
+ {
+ AddTargetAction(trigger, selectTarget, selectCallbacks[index]);
+ }
+ selectTrigger = 0;
+}
+
+func AddTargetAction(int trigger, object target, callback)
+{
+ triggerCallbacks = triggerCallbacks || [];
+ triggerCallbacks[trigger] = triggerCallbacks[trigger] || [];
+ triggerCallbacks[trigger][GetLength(triggerCallbacks[trigger])] = [target, callback];
+}
+
+func Trigger(int index, object user)
+{
+ if(triggerCallbacks && GetType(triggerCallbacks[index]) == C4V_Array)
+ {
+ var ret = false, i = 0;
+ for(var callback in triggerCallbacks[index])
+ {
+ if(GetType(callback) == C4V_Array)
+ {
+ if(CheckTarget(index, i))
+ {
+ ret = callback[0]->CallA(callback[1][1], CreateFilledArray(user, ...), true) || ret;
+ }
+ }
+ }
+ return ret;
+ }
+}
+
+func CheckTarget(int trigger, int& index)
+{
+ if(!triggerCallbacks || !triggerCallbacks[trigger] || !triggerCallbacks[trigger][index] || !triggerCallbacks[trigger][index][0])
+ {
+ RemoveSensorTargetIndex(trigger, index);
+ return false;
+ }
+ else
+ {
+ ++index;
+ return true;
+ }
+}
+
+func ClearTrigger(int index)
+{
+ triggerCallbacks[index] = 0;
+}
+
+func UpdateTransferZone()
+{
+ ToggleDesc(0, 0, 0, true);
+}
+
+func IsAnvilProduct() { return GetID() != SN7I; }
+
+func IsRemoteControllable() { return false; }
+
+func IgnoreSensorIgnored() { return Find_Not(Find_Func("SensorIgnored")); }
+
+func ClearCom(object caller)
+{
+ if(caller)
+ {
+ ClearLastPlrCom(GetController(caller));
+ }
+ return true;
+}
+
+func GetDescription()
+{
+ return desc;
+}
diff --git a/Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/ActMap.txt b/Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/ActMap.txt
new file mode 100644
index 0000000..a0663b3
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/ActMap.txt
@@ -0,0 +1,4 @@
+[Action]
+Name=Attach
+Procedure=ATTACH
+FacetBase=1
diff --git a/Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/DefCore.txt b/Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/DefCore.txt
new file mode 100644
index 0000000..cbcfbf8
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/DefCore.txt
@@ -0,0 +1,8 @@
+[DefCore]
+id=SE7I
+Name=Sensor entrance
+Category=C4D_Object|C4D_Foreground|C4D_MouseIgnore
+Width=10
+Height=10
+Offset=-5,-5
+Entrance=-5,-5,10,10
diff --git a/Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/Graphics.png b/Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/Graphics.png
new file mode 100644
index 0000000..9349486
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/Graphics.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/Script.c b/Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/Script.c
new file mode 100644
index 0000000..0aa77fb
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Sensor.c4d/SensorEntrance.c4d/Script.c
@@ -0,0 +1,33 @@
+#strict 2
+
+local target;
+
+func Initialize()
+{
+ SetVisibility(VIS_None);
+}
+
+func Attach(object obj)
+{
+ target = obj;
+ SetAction("Attach", target);
+ AddEffect("AttachCheck", target, 1, 0, this);
+ SetName(GetName(obj));
+ SetGraphics(0, this, GetID(target), GFX_Overlay, GFXOV_MODE_Picture);
+ return this;
+}
+
+func FxAttachCheckStop()
+{
+ return RemoveObject();
+}
+
+func ActivateEntrance(object caller)
+{
+ FinishCommand(caller, true);
+ target->Call(target->EntranceCallback(), caller, ...);
+ return 1;
+}
+
+func HiddenEntrance() { return true; }
+func SensorIgnored() { return true; }
diff --git a/Items.c4d/Sensors.c4d/Sensor.c4d/StringTblDE.txt b/Items.c4d/Sensors.c4d/Sensor.c4d/StringTblDE.txt
new file mode 100644
index 0000000..4b9121b
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Sensor.c4d/StringTblDE.txt
@@ -0,0 +1,19 @@
+CtxSetup=Sensor einstellen
+Setup=%s einstellen
+SelectTarget=Ziel auswählen
+RemoveTarget=Ziel löschen
+Target=Ziel
+Attach=Anbringen
+Detach=Loslösen
+SelectAction=Aktion auswählen
+SelectTrigger=Auslöser auswählen
+NoTargets=Keine Ziele in der Nähe!
+AddTarget=Ziel hinzufügen
+RemoveTarget=Ziel löschen
+Control=Steuerung: %s
+Continue=Weiter
+ChangeDesc=Beschreibung: %s
+EnterDesc=Beschreibung eingeben
+ShowDesc=Beschreibung einblenden
+HideDesc=Beschreibung ausblenden
+Finish=Fertig
diff --git a/Items.c4d/Sensors.c4d/Sensor.c4d/StringTblUS.txt b/Items.c4d/Sensors.c4d/Sensor.c4d/StringTblUS.txt
new file mode 100644
index 0000000..27627df
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Sensor.c4d/StringTblUS.txt
@@ -0,0 +1,19 @@
+CtxSetup=Setup sensor
+Setup=Setup %s
+SelectTarget=Select target
+RemoveTarget=Remove target
+Target=Target
+Attach=Attach
+Detach=Detach
+SelectAction=Select action
+SelectTrigger=Select trigger
+NoTargets=No targets nearby!
+AddTarget=Add target
+RemoveTarget=Remove target
+Control=Control: %s
+Continue=Continue
+ChangeDesc=Description: %s
+EnterDesc=Enter description
+ShowDesc=Show description
+HideDesc=Hide description
+Finish=Finish
diff --git a/Items.c4d/Sensors.c4d/Switch.c4d/ActMap.txt b/Items.c4d/Sensors.c4d/Switch.c4d/ActMap.txt
new file mode 100644
index 0000000..1090e76
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Switch.c4d/ActMap.txt
@@ -0,0 +1,3 @@
+[Action]
+Name=On
+Facet=0,5,10,5
diff --git a/Items.c4d/Sensors.c4d/Switch.c4d/DefCore.txt b/Items.c4d/Sensors.c4d/Switch.c4d/DefCore.txt
new file mode 100644
index 0000000..bce04e3
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Switch.c4d/DefCore.txt
@@ -0,0 +1,19 @@
+[DefCore]
+id=SW7I
+Name=Switch
+Version=4,9,5
+Category=C4D_Object|C4D_SelectMaterial|C4D_SelectKnowledge|C4D_SelectHomebase
+MaxUserSelect=10
+Width=10
+Height=5
+Offset=-5,-2
+Mass=1
+Value=5
+Components=METL=1;
+Picture=10,0,64,64
+Vertices=1
+VertexFriction=100
+Grab=2
+Collectible=1
+Rebuy=1
+NoPushEnter=1
diff --git a/Items.c4d/Sensors.c4d/Switch.c4d/Graphics.png b/Items.c4d/Sensors.c4d/Switch.c4d/Graphics.png
new file mode 100644
index 0000000..716cfaa
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Switch.c4d/Graphics.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/Switch.c4d/Names.txt b/Items.c4d/Sensors.c4d/Switch.c4d/Names.txt
new file mode 100644
index 0000000..db637a2
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Switch.c4d/Names.txt
@@ -0,0 +1,2 @@
+DE:Schalter
+US:Switch \ No newline at end of file
diff --git a/Items.c4d/Sensors.c4d/Switch.c4d/Script.c b/Items.c4d/Sensors.c4d/Switch.c4d/Script.c
new file mode 100644
index 0000000..1396ba7
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Switch.c4d/Script.c
@@ -0,0 +1,21 @@
+#strict 2
+#include BS7I
+
+local state;
+
+func Triggers() { return [["$On$"], ["$Off$"]]; }
+
+func ControlThrow(object caller)
+{
+ state = !state;
+ SetAction(["Idle", "On"][state]);
+ Sound("Grab");
+ TriggerState(caller);
+}
+
+func TriggerState(object caller)
+{
+ Trigger(!state, caller);
+}
+
+func SensorCallbacks() { return [["$Switch$", "ControlThrow"], ["$Retrigger$", "TriggerState"]]; }
diff --git a/Items.c4d/Sensors.c4d/Switch.c4d/StringTblDE.txt b/Items.c4d/Sensors.c4d/Switch.c4d/StringTblDE.txt
new file mode 100644
index 0000000..442738c
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Switch.c4d/StringTblDE.txt
@@ -0,0 +1,4 @@
+On=Einschalten
+Off=Ausschalten
+Switch=Schalten
+Retrigger=Erneut aktivieren
diff --git a/Items.c4d/Sensors.c4d/Switch.c4d/StringTblUS.txt b/Items.c4d/Sensors.c4d/Switch.c4d/StringTblUS.txt
new file mode 100644
index 0000000..37de868
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Switch.c4d/StringTblUS.txt
@@ -0,0 +1,4 @@
+On=Switch on
+Off=Switch off
+Switch=Switch
+Retrigger=Retrigger
diff --git a/Items.c4d/Sensors.c4d/Timer.c4d/ActMap.txt b/Items.c4d/Sensors.c4d/Timer.c4d/ActMap.txt
new file mode 100644
index 0000000..7dc639a
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Timer.c4d/ActMap.txt
@@ -0,0 +1,7 @@
+[Action]
+Name=On
+Facet=0,0,10,5
+Length=2
+Delay=35
+NextAction=On
+Reverse=1
diff --git a/Items.c4d/Sensors.c4d/Timer.c4d/DefCore.txt b/Items.c4d/Sensors.c4d/Timer.c4d/DefCore.txt
new file mode 100644
index 0000000..5b2a80f
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Timer.c4d/DefCore.txt
@@ -0,0 +1,18 @@
+[DefCore]
+id=TI7I
+Name=Timer
+Category=C4D_Object|C4D_SelectMaterial|C4D_SelectKnowledge|C4D_SelectHomebase
+Width=10
+Height=5
+Offset=-5,-2
+Mass=10
+Value=5
+Components=METL=1;
+Picture=0,5,64,64
+Vertices=1
+VertexFriction=100
+Grab=2
+Collectible=1
+MaxUserSelect=10
+Rebuy=1
+NoPushEnter=1
diff --git a/Items.c4d/Sensors.c4d/Timer.c4d/Graphics.png b/Items.c4d/Sensors.c4d/Timer.c4d/Graphics.png
new file mode 100644
index 0000000..a42131c
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Timer.c4d/Graphics.png
Binary files differ
diff --git a/Items.c4d/Sensors.c4d/Timer.c4d/Names.txt b/Items.c4d/Sensors.c4d/Timer.c4d/Names.txt
new file mode 100644
index 0000000..5e3934a
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Timer.c4d/Names.txt
@@ -0,0 +1,2 @@
+DE:Zeitgeber
+US:Timer
diff --git a/Items.c4d/Sensors.c4d/Timer.c4d/Script.c b/Items.c4d/Sensors.c4d/Timer.c4d/Script.c
new file mode 100644
index 0000000..e41043a
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Timer.c4d/Script.c
@@ -0,0 +1,112 @@
+#strict 2
+#include SN7I
+
+local interval, timer, setupUser, repeats, repeatCount;
+
+func Init()
+{
+ interval = 35;
+}
+
+func ControlThrow(object caller)
+{
+ Toggle();
+ return ClearCom(caller);
+}
+
+func ControlThrowDouble() { return ControlThrow(...); }
+
+func Triggers() { return [["$Timeout$"]];}
+
+func Setup(object caller, int &menuIndex)
+{
+ setupUser = caller;
+ AddMenuItem(Format("$Interval$", interval), "SetTimerEntry", GetID(), caller, 0, menuIndex++, 0, C4MN_Add_ForceNoDesc);
+ AddMenuItem(Format("$Repeats$", (repeats && Format("%d", repeats)) || "$InfRepeats$"), "SetRepeatsEntry", GetID(), caller, 0, menuIndex++, 0, C4MN_Add_ForceNoDesc);
+ AddMenuItem((!timer && "$Start$") || "$Stop$", "ToggleActive", GetID(), caller, 0, menuIndex++, 0, C4MN_Add_ForceNoDesc);
+ AddMenuItem("$Test$", "Timeout", GetID(), caller, 0, menuIndex++, 0, C4MN_Add_ForceNoDesc);
+ return true;
+}
+
+func SetTimerEntry(id id, int menuIndex, bool right)
+{
+ interval = Max(1, interval - (right * 2 - 1));
+ _Setup(setupUser);
+ SelectMenuItem(menuIndex, setupUser);
+ if(timer)
+ {
+ RemoveTimer(timer);
+ timer = 0;
+ timer = AddTimer("Timeout", interval);
+ }
+}
+
+func SetRepeatsEntry(id id, int menuIndex, bool right)
+{
+ repeats = Max(0, repeats - (right * 2 - 1));
+ _Setup(setupUser);
+ SelectMenuItem(menuIndex, setupUser);
+}
+
+func ToggleActive(id id, int menuIndex, bool right)
+{
+ Toggle();
+ _Setup(setupUser);
+ SelectMenuItem(menuIndex, setupUser);
+}
+
+func Toggle()
+{
+ if(timer)
+ {
+ Stop();
+ }
+ else
+ {
+ Start();
+ }
+}
+
+func Stop()
+{
+ if(timer)
+ {
+ RemoveTimer(timer);
+ timer = 0;
+ SetAction("Idle");
+ }
+}
+
+func Start()
+{
+ if(!timer)
+ {
+ timer = AddTimer("Timeout", interval);
+ SetAction("On");
+ repeatCount = 0;
+ }
+}
+
+func Timeout(sym, int menuIndex)
+{
+ Trigger(0, this);
+ if(GetType(sym) == C4V_C4ID)
+ {
+ _Setup(setupUser);
+ SelectMenuItem(menuIndex, setupUser);
+ }
+ else if(!sym && repeats && ++repeatCount >= repeats)
+ {
+ Stop();
+ }
+}
+
+func SingleShot()
+{
+ ScheduleCall(this, "Timeout", interval);
+}
+
+func SensorCallbacks()
+{
+ return [["$SingleShot$", "SingleShot"], ["$Start$", "Start"], ["$Stop$", "Stop"]];
+}
diff --git a/Items.c4d/Sensors.c4d/Timer.c4d/StringTblDE.txt b/Items.c4d/Sensors.c4d/Timer.c4d/StringTblDE.txt
new file mode 100644
index 0000000..7cf46ee
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Timer.c4d/StringTblDE.txt
@@ -0,0 +1,8 @@
+Timeout=Zeitablauf
+Interval=Zeitintervall: %d Frames
+Start=Starten
+Stop=Stoppen
+SingleShot=Einzelne Verzögerung
+Test=Testsignal auslösen
+Repeats=Wiederholungen: %s
+InfRepeats=Endlos
diff --git a/Items.c4d/Sensors.c4d/Timer.c4d/StringTblUS.txt b/Items.c4d/Sensors.c4d/Timer.c4d/StringTblUS.txt
new file mode 100644
index 0000000..ae1e896
--- /dev/null
+++ b/Items.c4d/Sensors.c4d/Timer.c4d/StringTblUS.txt
@@ -0,0 +1,8 @@
+Timeout=Timeout
+Interval=Interval: %d frames
+Start=Start
+Stop=Stop
+SingleShot=Single shot
+Test=Emit test signal
+Repeats=Repeat: %s
+InfRepeats=infinite