├── .gitignore
├── .DS_Store
├── .gitattributes
├── FS19_simpleIC.zip
├── FS19_simpleIC
├── .DS_Store
├── store.dds
├── modDesc.xml
├── sic_ptoControl.lua
├── sic_motorStartControl.lua
├── sic_drivableControl.lua
├── simpleIC_implementBalls.lua
├── sic_implementControl.lua
├── registerSimpleIC.lua
├── sic_attacherControl.lua
├── sic_lightControl.lua
└── simpleIC.lua
├── README.md
└── examples.xml
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .DS_Store
3 |
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/modelleicher/FS19_simpleIC/HEAD/.DS_Store
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/FS19_simpleIC.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/modelleicher/FS19_simpleIC/HEAD/FS19_simpleIC.zip
--------------------------------------------------------------------------------
/FS19_simpleIC/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/modelleicher/FS19_simpleIC/HEAD/FS19_simpleIC/.DS_Store
--------------------------------------------------------------------------------
/FS19_simpleIC/store.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/modelleicher/FS19_simpleIC/HEAD/FS19_simpleIC/store.dds
--------------------------------------------------------------------------------
/FS19_simpleIC/modDesc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | modelleicher (LS-Modcompany)
4 | 0.9.3.4
5 |
6 | SimpleIC - Einfaches Interactive Control
7 | SimpleIC - Easy Interactive Control
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | store.dds
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | IC: an/aus schaltenIC: on/off
41 | IC: Interagieren vehicleIC: interact vehicle
42 | IC: Interagieren zu FußIC: interact on foot
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FS19_simpleIC
2 | New Interactive Control Script for FS19
3 |
4 | # Changelog:
5 |
6 | ###### V 0.9.3.2
7 | - simpleIC_implementBalls.lua:207: attempt to index field 'vehicle' fixed (at least I hope that did the trick, I assume this error comes from synch issues not actual bug in script)
8 | - code cleanup ptoControl
9 | - addition of implementControl though not fully implemented yet (thus no example in examples.xml yet)
10 | - addition of disableInvisibleTriggers attribute if you want to disable triggerPoints via visibility. Was on by default in previous versions since implementation.
11 | But when people converted old IC to simpleIC they just set the old buttons to invisible and used the index for IC, now all of those didn't work anymore.
12 | So now by default it SimpleIC doesn't care about visibilty but if you want to disable triggerPoints via visibility you can do that by adding this attribute. (see Examples XML)
13 | ###### V 0.9.3.1
14 | - added motorStartControl and animations
15 | ###### V 0.9.3.0
16 | - lightControl leverAnimations for all types added and synched
17 | - debugPrints removed
18 | ###### V 0.9.2.9
19 | - implementBalls synch Issue possible fix
20 | - lightControl addition (leverAnimations still to do)
21 | ###### V 0.9.2.8
22 | - some bugfixes for the recent additions
23 | ###### V 0.9.2.7
24 | - separated attacherControl into seperate lua
25 | - synchronized attacherControl with setJointMoveDown so its always in synch
26 | - fixed doNotSynch for ptoControl
27 | - added returnToCenter, returnToCenterRaised, returnToCenterLowered for attacherControl leverAnimation
28 | ###### V 0.9.2.6
29 | - separated ptoControl into seperate lua
30 | - synchronized ptoControl animation with turnOnVehicle so its always in synch
31 | - fixed version numbering mishap (yes this is 0.9.2.6 not 0.9.1.6)
32 | ###### V 0.9.2.5
33 | - added attacherControl
34 | - added ptoControl
35 | ###### V 0.9.2.4
36 | - made icFunctions more universally usable for future additions
37 | - icFunction can be "turned off" by setting visibility of triggerPoint to false
38 | ###### V 0.9.2.3
39 | - MP Server fix of vehicle not enterable
40 | ###### V 0.9.2.2
41 | - fix for line 102 error I think, couldn't reproduce but I found an issue with the table indexing and I think it worked fine for most mods but some may have caused the issue to show.
42 | ###### V 0.9.2.1
43 | - possibly fixed dedicated server issue
44 | - removed "cylinder" debug finally
45 | ###### V 0.9.2.0
46 | - addition of SimpleIC-ImplementBalls
47 | ###### V 0.9.1.9
48 | - fixed the issue introduced in the version before last version and partially fixed in the last version. Now fixed completely. I hope.. again.
49 | ###### V 0.9.1.8
50 | - fixed Issue introduced in the last version of indoor buttons only working when the ingame-menu is on, fully removed issue with double-mapping of mouseButtons I hope
51 | ###### V 0.9.1.7
52 | - fixed Error: simpleIC.lua:488: attempt to index field 'spec_motorized' (a nil value)
53 | - fixed Error: simpleIC.lua:318: attempt to call method 'getAttacherVehicle' (a nil value)
54 | - reachDistance can be set per vehicle (optional, default 1.8) to specify how far away a player can reach an IC-point
55 | ###### V 0.9.1.6
56 | - fixed spec insertion so simpleIC now works in every implement, trailer etc. not just drivables
57 | ###### V 0.9.1.5
58 | - fixed Error: simpleIC.lua:248: attempt to index local 'spec' (a nil value)
59 | - added cylinderAnimation for easy animation of struts on windows/doors etc.
60 | ###### V 0.9.1.4
61 | - fixed IC active on all vehicles bug (now only active if vehicle actually has IC functions)
62 | - fixed bug Error: Running LUA method 'update' simpleIC.lua:292: attempt to index a nil value
63 | - added default keymapping
64 | ###### V 0.9.1.3
65 | - multiplayer fix
66 | - added triggerPoint_ON and triggerPoint_OFF as alternative to toggle via triggerPoint
67 |
68 | # the most important thing:
69 | How do I test this?
70 | 1. download FS19_simpleIC.zip and add to modfolder
71 | 2. download my Agrostar 6.61 Edit I released for christmas, it already has simpleIC added. https://youtu.be/lsEg6T7XOkE
72 | (by now there are a lot of SimpleIC ready mods out there already so just find the next best one you like)
73 | 3. go ingame and have fun :D
74 |
75 | # What this is:
76 | This is a new take on the well known Interactive Control Scripts in Farming Simulator. Since there hasn't been a well-working bug-free version of the old scripts in FS19, and since I always didn't like the way the Mouse is used, I created this alternative.
77 |
78 | - This is a global script, which means that it doesn't have to be added to each Mod seperately, no additional modDesc.xml changes like l10n Texts etc. neccessary.
79 | - Obviously the vehicle-xml and i3d still has to be edited, the script can't magically seperate doors and add trigger-points. But as soon as the needed lines are added, IC will be active as long as you have this mod active.
80 | - this also means that people who don't like IC don't have to remove it all vehicle-mods, just not activate this mod.
81 | - this also means that there's only one IC version and not 50 different ones that get into conflict with each other
82 | - updates to IC are global and useable in all mods
83 |
84 | Now for the bad parts
85 | - still Beta
86 | - still Bugs
87 | - not even close to the amount of features the original IC Script had in FS17. (But I'm working on that ;) )
88 |
89 | # How to add this to my Mod:
90 | - I will create videos explaining the process of adding simpleIC to your vehicle.
91 |
92 | - There is an examples.xml explaining all the current possible XML entrys and what they do. If you're not brandnew to modding this should be enough to get going :)
93 |
94 | If you already know modding well, here's a short explanation:
95 | (look at the linked Deutz Agrostar above to see the full XML lines)
96 |
97 | - outsideInteractionTrigger = playerTrigger in which the player can open doors and other outside-stuff from the outside
98 | - animationName = name of the animation for the door
99 | - animationSpeed = speed of the animation (obvious)
100 | - shared animation = not added yet
101 | - soundVolumeIncreasePercentage = by how much will the sound-volume increase if that door is opened. Values will be added together for more than one door, max is outdoorSoundVolume
102 | - insideTrigger and outsideTrigger = "Triggerpoints" e.g. transformGroups that mark the spot where the IC component can be clicked
103 | - triggerPoint = index / i3dMapping name for the transformGroup
104 | - triggerPointSize = size/radius around the triggerPoint where it still registeres as being clicked
105 |
106 |
107 |
--------------------------------------------------------------------------------
/FS19_simpleIC/sic_ptoControl.lua:
--------------------------------------------------------------------------------
1 | -- SimpleIC PTO Control
2 | -- to control PTO Implements e.g. TurnOnVehicle via simpleIC
3 |
4 | sic_ptoControl = {};
5 |
6 | function sic_ptoControl.prerequisitesPresent(specializations)
7 | return true;
8 | end;
9 |
10 | function sic_ptoControl.registerEventListeners(vehicleType)
11 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", sic_ptoControl);
12 | end;
13 |
14 | function sic_ptoControl:onLoad(savegame)
15 | self.loadPTOControl = sic_ptoControl.loadPTOControl;
16 | self.setPTOControl = sic_ptoControl.setPTOControl;
17 |
18 | -- access tables
19 | if self.sic_at == nil then
20 | self.sic_at = {};
21 | end;
22 | self.sic_at.attacherIndex_ptoControl = {};
23 | self.sic_at.ptoControl = {};
24 | end;
25 |
26 | function sic_ptoControl:loadPTOControl(key, table)
27 | local ptoControl ={};
28 | -- load xml attributes for ptoControl, attacherIndex is for backwards-compatability, use attacherIndices instead
29 | local attacherIndex = getXMLInt(self.xmlFile, key.."#attacherIndex");
30 | ptoControl.turnOnSelf = getXMLBool(self.xmlFile, key.."#turnOnSelf");
31 | local attacherIndices = getXMLString(self.xmlFile, key.."#attacherIndices")
32 |
33 | -- if we turn on self we don't need attacherIndices
34 | if attacherIndex ~= nil or (attacherIndices ~= "" and attacherIndices ~= nil) or ptoControl.turnOnSelf then
35 |
36 | -- split attacherIndices string into attacherIndices/add attacherIndex to table. Also add to create access tables
37 | if attacherIndices ~= nil then
38 | ptoControl.attacherIndices = StringUtil.splitString(" ", attacherIndices);
39 | for _, attacherIndex in pairs(ptoControl.attacherIndices) do
40 | self.sic_at.attacherIndex_ptoControl[tonumber(attacherIndex)] = ptoControl;
41 | end;
42 | else
43 | ptoControl.attacherIndices = {tostring(attacherIndex)};
44 | self.sic_at.attacherIndex_ptoControl[attacherIndex] = ptoControl;
45 | end;
46 |
47 | -- load optional animation
48 | local animationName = getXMLString(self.xmlFile, key..".leverAnimation#animationName");
49 | if animationName ~= "" and animationName ~= nil then
50 | ptoControl.leverAnimation = {};
51 | ptoControl.leverAnimation.animationName = animationName;
52 | ptoControl.leverAnimation.doNotSynch = getXMLBool(self.xmlFile, key..".leverAnimation#doNotSynch");
53 | end;
54 |
55 | -- add table and access table
56 | table.ptoControl = ptoControl;
57 | self.sic_at.ptoControl[#self.sic_at.ptoControl+1] = ptoControl;
58 | return true;
59 | end;
60 | end;
61 |
62 | function sic_ptoControl:setPTOControl(wantedState, i)
63 | local ptoControl = self.spec_simpleIC.icFunctions[i].ptoControl;
64 |
65 | -- if turnOnSelf its easy just turn on ourselfes lol
66 | if ptoControl.turnOnSelf then
67 | if wantedState == nil then
68 | wantedState = not self.spec_turnOnVehicle.isTurnedOn;
69 | end;
70 | self:setIsTurnedOn(wantedState);
71 | end;
72 |
73 | -- cycle through all attached implements to find the implement attached to the attacherIndex of this icFunction ptoControl
74 | for _ , attacherIndex in pairs(ptoControl.attacherIndices) do
75 | for _, implement in pairs(self.spec_attacherJoints.attachedImplements) do
76 | if tostring(implement.jointDescIndex) == attacherIndex then
77 | if implement.object.spec_turnOnVehicle ~= nil then
78 |
79 | -- wantedState is either true or false when there is a _ON and _OFF trigger, otherwise its nil so we need the != of the current state
80 | if wantedState == nil then
81 | wantedState = not implement.object.spec_turnOnVehicle.isTurnedOn;
82 | end;
83 | -- apply state
84 | implement.object:setIsTurnedOn(wantedState)
85 |
86 | -- run animation if doNotSynch is true, otherwise animation will be run by setIsTurnedOn Append function
87 | if ptoControl.leverAnimation ~= nil and ptoControl.leverAnimation.doNotSynch then
88 | local speed = 1;
89 | if not wantedState then
90 | speed = -1;
91 | end;
92 | self:playAnimation(ptoControl.leverAnimation.animationName, speed, self:getAnimationTime(ptoControl.leverAnimation.animationName), true);
93 | end;
94 | end;
95 | end;
96 | end;
97 | end;
98 |
99 | end;
100 |
101 |
102 |
103 | -- override setIsTurnedOn for playing animation when turned on/off even if it isn't done via SIC Input
104 | function sic_ptoControl.setIsTurnedOnAppend(self, superFunc, isTurnedOn, noEventSend)
105 | superFunc(self, isTurnedOn, noEventSend);
106 |
107 | -- check if we have simpleIC ourselfes
108 | if self.spec_simpleIC ~= nil and self.spec_simpleIC.hasIC then
109 | for _, ptoControl in pairs(self.sic_at.ptoControl) do
110 | if ptoControl.turnOnSelf then
111 | if ptoControl.leverAnimation ~= nil then
112 | local speed = -1;
113 | if isTurnedOn then
114 | speed = 1;
115 | end;
116 | self:playAnimation(ptoControl.leverAnimation.animationName, speed, nil, false);
117 | end;
118 | end;
119 | end;
120 | end;
121 |
122 | -- if we are an implement, we need to get our attacherVehicle
123 | if self.getAttacherVehicle ~= nil then
124 | local attacherVehicle = self:getAttacherVehicle()
125 | -- check if attacherVehicle has simpleIC
126 | if attacherVehicle ~= nil and attacherVehicle.spec_simpleIC ~= nil and attacherVehicle.spec_simpleIC.hasIC then
127 | -- run through implements attached to attacherVehicle to find out attacherIndex
128 | for _, implement in pairs(attacherVehicle.spec_attacherJoints.attachedImplements) do
129 | local ptoControl = attacherVehicle.sic_at.attacherIndex_ptoControl[implement.jointDescIndex];
130 | -- check if ptoControl has leverAnimation
131 | if ptoControl ~= nil and ptoControl.leverAnimation ~= nil then
132 | if implement.object == self then
133 | -- run animation
134 | local speed = -1;
135 | if isTurnedOn then
136 | speed = 1;
137 | end;
138 | attacherVehicle:playAnimation(ptoControl.leverAnimation.animationName, speed, attacherVehicle:getAnimationTime(ptoControl.leverAnimation.animationName), true);
139 | end;
140 | end;
141 | end;
142 | end;
143 | end;
144 |
145 | end;
146 |
147 | TurnOnVehicle.setIsTurnedOn = Utils.overwrittenFunction(TurnOnVehicle.setIsTurnedOn, sic_ptoControl.setIsTurnedOnAppend);
148 |
149 |
--------------------------------------------------------------------------------
/FS19_simpleIC/sic_motorStartControl.lua:
--------------------------------------------------------------------------------
1 | -- SimpleIC Motor Start Control
2 | -- to start/stop engine via IC and animate button/lever
3 |
4 | sic_motorStartControl = {};
5 |
6 | function sic_motorStartControl.prerequisitesPresent(specializations)
7 | return true;
8 | end;
9 |
10 | function sic_motorStartControl.registerEventListeners(vehicleType)
11 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", sic_motorStartControl);
12 | SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", sic_motorStartControl)
13 | end;
14 |
15 |
16 | function sic_motorStartControl:onLoad(savegame)
17 | self.loadMotorStartControl = sic_motorStartControl.loadMotorStartControl;
18 | self.setMotorStartControl = sic_motorStartControl.setMotorStartControl;
19 |
20 | self.spec_sic_motorStartControl = {};
21 |
22 | local spec = self.spec_sic_motorStartControl;
23 |
24 | spec.turnKeyAnimationState = 0;
25 | spec.turnKeyAnimation = nil;
26 |
27 | end;
28 |
29 |
30 | function sic_motorStartControl:loadMotorStartControl(key, table)
31 | local motorStartControl ={};
32 |
33 | if hasXMLProperty(self.xmlFile, key) then
34 |
35 | local animationName = getXMLString(self.xmlFile, key..".leverAnimation#animationName");
36 | if animationName ~= "" and animationName ~= nil then
37 | motorStartControl.leverAnimation = {};
38 | motorStartControl.leverAnimation.animationName = animationName;
39 | motorStartControl.leverAnimation.isTurnKeyAnimation = getXMLBool(self.xmlFile, key..".leverAnimation#isTurnKeyAnimation")
40 | end;
41 |
42 | local animationNameStart = getXMLString(self.xmlFile, key..".leverAnimationStart#animationName");
43 | if animationNameStart ~= "" and animationNameStart ~= nil then
44 | motorStartControl.leverAnimationStart = {};
45 | motorStartControl.leverAnimationStart.animationName = animationNameStart;
46 | end;
47 |
48 | local animationNameStop = getXMLString(self.xmlFile, key..".leverAnimationStop#animationName");
49 | if animationNameStop ~= "" and animationNameStop ~= nil then
50 | motorStartControl.leverAnimationStop = {};
51 | motorStartControl.leverAnimationStop.animationName = animationNameStop;
52 | end;
53 |
54 | table.motorStartControl = motorStartControl;
55 | return true;
56 |
57 | end;
58 |
59 | end;
60 |
61 | function sic_motorStartControl:setMotorStartControl(wantedState, i)
62 | local motorStartControl = self.spec_simpleIC.icFunctions[i].motorStartControl;
63 |
64 | if wantedState == nil then
65 | wantedState = not self:getIsMotorStarted();
66 | end;
67 |
68 | if not wantedState then
69 | self:stopMotor();
70 | elseif wantedState and self:getCanMotorRun() then
71 | self:startMotor()
72 | end;
73 |
74 | end;
75 |
76 | function sic_motorStartControl:onUpdateTick(dt)
77 | if self:getIsActive() then
78 | local spec = self.spec_sic_motorStartControl;
79 | if spec.turnKeyAnimation ~= nil and spec.turnKeyAnimationState == 1 then
80 | if g_currentMission.time > self:getMotorStartTime() then
81 | self:playAnimation(spec.turnKeyAnimation.animationName, -1, self:getAnimationTime(spec.turnKeyAnimation.animationName), true);
82 | self:setAnimationStopTime(spec.turnKeyAnimation.animationName, 0.7);
83 | spec.turnKeyAnimationState = 2;
84 | spec.turnKeyAnimation = nil;
85 | end;
86 | end;
87 | if spec.leverAnimationStart ~= nil then
88 | local animTime = self:getAnimationTime(spec.leverAnimationStart.animationName);
89 | if animTime == 1 then
90 | self:playAnimation(spec.leverAnimationStart.animationName, -1, self:getAnimationTime(spec.leverAnimationStart.animationName), true);
91 | spec.leverAnimationStart = nil;
92 | end;
93 | end;
94 | if spec.leverAnimationStop ~= nil then
95 | local animTime = self:getAnimationTime(spec.leverAnimationStop.animationName);
96 | if animTime < 1 then
97 | self:raiseActive();
98 | else
99 | self:playAnimation(spec.leverAnimationStop.animationName, -1, self:getAnimationTime(spec.leverAnimationStop.animationName), true);
100 | spec.leverAnimationStop = nil;
101 | end;
102 | end;
103 | end;
104 | end;
105 |
106 | function sic_motorStartControl.startMotorAppend(self, superFunc, noEventSend)
107 | superFunc(self, noEventSend);
108 |
109 | if self.spec_simpleIC ~= nil and self.spec_simpleIC.hasIC then
110 | for _, icFunction in pairs(self.spec_simpleIC.icFunctions) do
111 | if icFunction.motorStartControl ~= nil then
112 |
113 | local spec = self.spec_sic_motorStartControl;
114 |
115 | local leverAnimation = icFunction.motorStartControl.leverAnimation;
116 | if leverAnimation ~= nil then
117 | self:playAnimation(leverAnimation.animationName, 1, self:getAnimationTime(leverAnimation.animationName), true);
118 | if leverAnimation.isTurnKeyAnimation then
119 | spec.turnKeyAnimationState = 1;
120 | spec.turnKeyAnimation = leverAnimation;
121 | end;
122 | end;
123 |
124 | local leverAnimationStart = icFunction.motorStartControl.leverAnimationStart;
125 | if leverAnimationStart ~= nil then
126 | self:playAnimation(leverAnimationStart.animationName, 1, self:getAnimationTime(leverAnimationStart.animationName), true);
127 | spec.leverAnimationStart = leverAnimationStart;
128 | end;
129 | end;
130 | end;
131 | end;
132 | end;
133 | Motorized.startMotor = Utils.overwrittenFunction(Motorized.startMotor, sic_motorStartControl.startMotorAppend)
134 |
135 | function sic_motorStartControl.stopMotor(self, superFunc, noEventSend)
136 | superFunc(self, noEventSend);
137 |
138 | if self.spec_simpleIC ~= nil and self.spec_simpleIC.hasIC then
139 | for _, icFunction in pairs(self.spec_simpleIC.icFunctions) do
140 | if icFunction.motorStartControl ~= nil then
141 |
142 | if icFunction.motorStartControl.leverAnimation ~= nil then
143 | local leverAnimation = icFunction.motorStartControl.leverAnimation;
144 | self:playAnimation(leverAnimation.animationName, -1, self:getAnimationTime(leverAnimation.animationName), true);
145 | end;
146 |
147 | local leverAnimationStop = icFunction.motorStartControl.leverAnimationStop;
148 | if leverAnimationStop ~= nil then
149 | self:playAnimation(leverAnimationStop.animationName, 1, self:getAnimationTime(leverAnimationStop.animationName), true);
150 | self.spec_sic_motorStartControl.leverAnimationStop = leverAnimationStop;
151 | self:raiseActive();
152 | end;
153 | end;
154 | end;
155 | end;
156 | end;
157 | Motorized.stopMotor = Utils.overwrittenFunction(Motorized.stopMotor, sic_motorStartControl.stopMotor)
--------------------------------------------------------------------------------
/FS19_simpleIC/sic_drivableControl.lua:
--------------------------------------------------------------------------------
1 | -- SimpleIC Drivable Control
2 | -- to control stuff that is generally found in drivable vehicles
3 |
4 |
5 | sic_drivableControl = {};
6 |
7 | function sic_drivableControl.prerequisitesPresent(specializations)
8 | return true;
9 | end;
10 |
11 | function sic_drivableControl.registerEventListeners(vehicleType)
12 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", sic_drivableControl);
13 | SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", sic_drivableControl);
14 | SpecializationUtil.registerEventListener(vehicleType, "onUpdate", sic_drivableControl);
15 | end;
16 |
17 | function sic_drivableControl:onLoad(savegame)
18 | self.loadDrivableControl = sic_drivableControl.loadDrivableControl;
19 | self.setDrivableControl = sic_drivableControl.setDrivableControl;
20 |
21 | -- access tables
22 | if self.sic_at == nil then
23 | self.sic_at = {};
24 | end;
25 | self.sic_at.drivableControl = {};
26 |
27 | self.spec_sic_drivableControl = {};
28 |
29 |
30 |
31 | end;
32 |
33 | function sic_drivableControl:onPostLoad(savegame)
34 | local spec = self.spec_sic_drivableControl;
35 |
36 | spec.tsx_enhancedVehicleLoaded = g_modIsLoaded.TSX_EnhancedVehicle;
37 | if spec.tsx_enhancedVehicleLoaded then
38 | spec.tsx_enhancedVehicle_diffEnabled = TSX_EnhancedVehicle.TSX_EnhancedVehicle.functionDifferentialIsEnabled;
39 | spec.tsx_enhancedVehicle_shuttleEnabled = TSX_EnhancedVehicle.TSX_EnhancedVehicle.functionShuttleIsEnabled;
40 |
41 | spec.vDataBackup = {nil, nil, nil, nil, nil, nil};
42 | end;
43 | end;
44 |
45 | function sic_drivableControl:loadDrivableControl(key, table)
46 | local drivableControl = {};
47 |
48 | drivableControl.type = getXMLString(self.xmlFile, key.."#type");
49 | drivableControl.specific = getXMLString(self.xmlFile, key.."#specific");
50 |
51 | if drivableControl.type ~= nil and drivableControl.type ~= "" then
52 |
53 | local animationName = getXMLString(self.xmlFile, key..".leverAnimation#animationName");
54 | if animationName ~= "" and animationName ~= nil then
55 | drivableControl.leverAnimation = {};
56 | drivableControl.leverAnimation.animationName = animationName;
57 | drivableControl.leverAnimation.doNotSynch = getXMLBool(self.xmlFile, key..".leverAnimation#doNotSynch");
58 | end;
59 |
60 | table.drivableControl = drivableControl;
61 | self.sic_at.drivableControl[#self.sic_at.drivableControl+1] = drivableControl;
62 | return true;
63 | end;
64 |
65 | end;
66 |
67 | -- get access to TSX functions
68 | function sic_drivableControl.tsx_onRegisterActionEventsAppend(self, superFunc, isSelected, isOnActiveVehicle)
69 |
70 | local returnValues = superFunc(self, isSelected, isOnActiveVehicle);
71 |
72 | self.onActionCall = TSX_EnhancedVehicle.TSX_EnhancedVehicle.onActionCall;
73 | end;
74 | if TSX_EnhancedVehicle ~= nil and TSX_EnhancedVehicle.TSX_EnhancedVehicle ~= nil then
75 | TSX_EnhancedVehicle.TSX_EnhancedVehicle.onRegisterActionEvents = Utils.overwrittenFunction(TSX_EnhancedVehicle.TSX_EnhancedVehicle.onRegisterActionEvents, sic_drivableControl.tsx_onRegisterActionEventsAppend);
76 | end;
77 |
78 | function sic_drivableControl:onUpdate(dt)
79 | if self:getIsActive() then
80 | local spec = self.spec_sic_drivableControl;
81 |
82 | for _, drivableControl in pairs(self.sic_at.drivableControl) do
83 | local leverAnimation = drivableControl.leverAnimation;
84 | if leverAnimation ~= nil then
85 | if spec.tsx_enhancedVehicleLoaded then
86 | local speed = -1;
87 | if spec.tsx_enhancedVehicle_diffEnabled then
88 | if drivableControl.type == "diffLock" and (drivableControl.specific == "front" or drivableControl.specific == "all") then
89 | if spec.vDataBackup[1] ~= self.vData.want[1] then
90 | if self.vData.want[1] then
91 | speed = 1;
92 | end;
93 | self:playAnimation(leverAnimation.animationName, speed, self:getAnimationTime(leverAnimation.animationName), true);
94 | end;
95 | end;
96 | if drivableControl.type == "diffLock" and (drivableControl.specific == "rear" or drivableControl.specific == "all") then
97 | if spec.vDataBackup[2] ~= self.vData.want[2] then
98 | if self.vData.want[2] then
99 | speed = 1;
100 | end;
101 | self:playAnimation(leverAnimation.animationName, speed, self:getAnimationTime(leverAnimation.animationName), true);
102 | end;
103 | end;
104 | if drivableControl.type == "4wd" then
105 |
106 | if spec.vDataBackup[3] ~= self.vData.want[3] then
107 | if self.vData.want[3] then
108 | speed = 1;
109 | end;
110 | print("4wd do")
111 | self:playAnimation(leverAnimation.animationName, speed, self:getAnimationTime(leverAnimation.animationName), true);
112 | end;
113 | end;
114 | end;
115 | if spec.tsx_enhancedVehicle_shuttleEnabled then
116 | if drivableControl.type == "shuttle" then
117 | if spec.vDataBackup[4] ~= self.vData.want[4] then
118 | if self.vData.want[4] then
119 | speed = 1;
120 | end;
121 | self:playAnimation(leverAnimation.animationName, speed, self:getAnimationTime(leverAnimation.animationName), true);
122 | end;
123 | end;
124 | if drivableControl.type == "handbrake" then
125 | if spec.vDataBackup[6] ~= self.vData.want[6] then
126 | if self.vData.want[6] then
127 | speed = 1;
128 | end;
129 | self:playAnimation(leverAnimation.animationName, speed, self:getAnimationTime(leverAnimation.animationName), true);
130 | end;
131 | end;
132 | end;
133 | end;
134 | end;
135 | end;
136 | end;
137 | end;
138 |
139 |
140 |
141 |
142 | function sic_drivableControl:setDrivableControl(wantedState, i)
143 | local drivableControl = self.spec_simpleIC.icFunctions[i].drivableControl;
144 |
145 | local spec = self.spec_sic_drivableControl;
146 |
147 | -- try use TSX 4wd
148 | if spec.tsx_enhancedVehicleLoaded then
149 |
150 | if spec.tsx_enhancedVehicle_diffEnabled then
151 | if drivableControl.type == "4wd" then
152 | self:onActionCall("TSX_EnhancedVehicle_DM");
153 | end;
154 | if drivableControl.type == "diffLock" then
155 | if drivableControl.specific == "all" then
156 | self:onActionCall("TSX_EnhancedVehicle_BD");
157 | elseif drivableControl.specific == "front" then
158 | self:onActionCall("TSX_EnhancedVehicle_FD");
159 | elseif drivableControl.specific == "rear" then
160 | self:onActionCall("TSX_EnhancedVehicle_RD");
161 | end;
162 | end;
163 | end;
164 | if spec.tsx_enhancedVehicle_shuttleEnabled then
165 | if drivableControl.type == "handbrake" then
166 | self:onActionCall("TSX_EnhancedVehicle_SHUTTLE_PARK");
167 | end;
168 | if drivableControl.type == "shuttle" then
169 | if drivableControl.specific == "toggle" then
170 | self:onActionCall("TSX_EnhancedVehicle_SHUTTLE_SWITCH");
171 | elseif drivableControl.specific == "forward" then
172 | self:onActionCall("TSX_EnhancedVehicle_SHUTTLE_FWD");
173 | elseif drivableControl.specific == "reverse" then
174 | self:onActionCall("TSX_EnhancedVehicle_SHUTTLE_REV");
175 | end;
176 | end;
177 | end;
178 | end;
179 |
180 | end;
--------------------------------------------------------------------------------
/FS19_simpleIC/simpleIC_implementBalls.lua:
--------------------------------------------------------------------------------
1 | -- by modelleicher
2 | -- www.ls-modcompany.com
3 | -- Part of SimpleIC global script. Global script that adds the ability to right-click on a implement attacher to add balls.
4 |
5 | simpleIC_implementBalls = {};
6 |
7 |
8 | function simpleIC_implementBalls.prerequisitesPresent(specializations)
9 | return true;
10 | end;
11 |
12 | function simpleIC_implementBalls.registerEventListeners(vehicleType)
13 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", simpleIC_implementBalls);
14 | SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", simpleIC_implementBalls);
15 | SpecializationUtil.registerEventListener(vehicleType, "onDelete", simpleIC_implementBalls);
16 | SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", simpleIC_implementBalls);
17 | SpecializationUtil.registerEventListener(vehicleType, "saveToXMLFile", simpleIC_implementBalls);
18 | SpecializationUtil.registerEventListener(vehicleType, "onReadStream", simpleIC_implementBalls);
19 | SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", simpleIC_implementBalls);
20 | end;
21 |
22 | function simpleIC_implementBalls:onLoad(savegame)
23 | self.setImplementBalls = simpleIC_implementBalls.setImplementBalls
24 | if g_currentMission.simpleIC_implementBalls == nil then
25 | g_currentMission.simpleIC_implementBalls = {};
26 | end;
27 |
28 | self.spec_implementBalls = {}
29 | local spec = self.spec_implementBalls;
30 | local i3dFilename = "$data/vehicles/johnDeere/weightSetBall.i3d"
31 |
32 | local ballI3d = g_i3DManager:loadSharedI3DFile(i3dFilename, self.baseDirectory, false, false, false)
33 |
34 | spec.leftNode = I3DUtil.indexToObject(ballI3d, "0", self.i3dMappings)
35 | spec.rightNode = I3DUtil.indexToObject(ballI3d, "1", self.i3dMappings)
36 |
37 | spec.maxDistance = 1.4;
38 | -- check if we have a implement attacher joint
39 | if self.spec_attachable.inputAttacherJoints ~= nil then
40 | local jointTypeWant = AttacherJoints.jointTypeNameToInt["implement"]
41 | spec.implementJoints = {};
42 | for _ , inputAttacherJoint in pairs(self.spec_attachable.inputAttacherJoints) do
43 | if inputAttacherJoint.jointType == jointTypeWant and inputAttacherJoint.node ~= nil then
44 | inputAttacherJoint.showBalls = false;
45 | spec.implementJoints[#spec.implementJoints+1] = inputAttacherJoint;
46 | end;
47 | end;
48 | if #spec.implementJoints < 1 then
49 | spec = nil;
50 | else
51 | spec.vehicle = self;
52 | table.insert(g_currentMission.simpleIC_implementBalls, spec)
53 | end;
54 | end;
55 |
56 | end;
57 |
58 | function simpleIC_implementBalls:onDelete()
59 | local spec = self.spec_implementBalls;
60 | if spec ~= nil then
61 | for index, specFind in pairs(g_currentMission.simpleIC_implementBalls) do
62 | if specFind == spec then
63 | table.remove(g_currentMission.simpleIC_implementBalls, index)
64 | end;
65 | end;
66 | spec = nil;
67 | end;
68 | end;
69 |
70 |
71 | function simpleIC_implementBalls:onUpdateTick(dt)
72 | local spec = self.spec_implementBalls;
73 | for _, implementJoint in pairs(spec.implementJoints) do
74 | if implementJoint.showX then
75 | local aX, aY, aZ = getWorldTranslation(implementJoint.node)
76 | local x, y, z = project(aX, aY, aZ);
77 |
78 | cameraNode = g_currentMission.player.cameraNode
79 |
80 | local cX, cY, cZ = getWorldTranslation(cameraNode);
81 | local dist = MathUtil.vector3Length(aX-cX, aY-cY, aZ-cZ);
82 | local size = 0.028 / dist;
83 |
84 | local posX, posY, posZ = 0.5, 0.5, 0.5;
85 | local radius = 0.03;
86 |
87 | if posX < (x + radius) and posX > (x - radius) then
88 | if posY < (y + radius) and posY > (y - radius) then
89 | self:renderTextAtProjectedPosition(x ,y ,z, "X", size, 1, 0, 0)
90 | implementJoint.canBeClicked = true;
91 | end;
92 | else
93 | self:renderTextAtProjectedPosition(x ,y ,z, "X", size, 1, 1, 1)
94 | implementJoint.canBeClicked = false;
95 | end;
96 | end;
97 | end;
98 | end;
99 |
100 | function simpleIC_implementBalls:setImplementBalls(index, forceState, noEventSend)
101 | local spec = self.spec_implementBalls;
102 | if spec.implementJoints[index] ~= nil then
103 | spec.implementJoints[index].showBalls = Utils.getNoNil(forceState, not spec.implementJoints[index].showBalls);
104 | setICImplementBallsEvent.sendEvent(self, spec.implementJoints[index].showBalls, index, noEventSend);
105 |
106 | if spec.implementJoints[index].showBalls then
107 | link(spec.implementJoints[index].node, spec.leftNode)
108 | link(spec.implementJoints[index].node, spec.rightNode)
109 | setTranslation(spec.leftNode, 0, 0, -0.432)
110 | setTranslation(spec.rightNode, 0, 0, 0.432)
111 | setRotation(spec.leftNode, 0, math.rad(90), 0)
112 | setRotation(spec.rightNode, 0, math.rad(90), 0)
113 | else
114 | unlink(spec.leftNode)
115 | unlink(spec.rightNode)
116 | end;
117 | end;
118 | end;
119 |
120 | function simpleIC_implementBalls:onPostLoad(savegame)
121 | if self.spec_implementBalls ~= nil and savegame ~= nil then
122 | local spec = self.spec_implementBalls;
123 | local xmlFile = savegame.xmlFile;
124 |
125 |
126 | local key1 = savegame.key..".FS19_simpleIC.simpleIC_implementBalls"
127 | for i, implementJoint in pairs(spec.implementJoints) do
128 | -- load ball state
129 | if implementJoint.showBalls ~= nil then
130 | local state = getXMLBool(xmlFile, key1..".implementBall"..i.."#state");
131 | if state ~= nil then
132 | self:setImplementBalls(i, state)
133 | end;
134 | end;
135 | end;
136 | end;
137 | end;
138 |
139 | function simpleIC_implementBalls:saveToXMLFile(xmlFile, key)
140 | if self.spec_implementBalls ~= nil then
141 | local spec = self.spec_implementBalls;
142 |
143 | for i, implementJoint in pairs(spec.implementJoints) do
144 | -- save ball state
145 | if implementJoint.showBalls ~= nil then
146 | setXMLBool(xmlFile, key..".implementBall"..i.."#state", implementJoint.showBalls);
147 | end;
148 | end;
149 |
150 | end;
151 | end;
152 |
153 | function simpleIC_implementBalls:onReadStream(streamId, connection)
154 | local spec = self.spec_implementBalls
155 | if spec ~= nil then
156 | if connection:getIsServer() then
157 | for i, implementJoint in pairs(spec.implementJoints) do
158 | local state = streamReadBool(streamId, implementJoint.showBalls)
159 | if state ~= nil then
160 | self:setImplementBalls(i, state)
161 | end;
162 | end;
163 | end;
164 | end;
165 | end
166 |
167 | function simpleIC_implementBalls:onWriteStream(streamId, connection)
168 | local spec = self.spec_implementBalls;
169 | if spec ~= nil then
170 | if not connection:getIsServer() then
171 | for _, implementJoint in pairs(spec.implementJoints) do
172 | streamWriteBool(streamId, implementJoint.showBalls)
173 | end;
174 | end;
175 | end;
176 | end
177 |
178 |
179 |
180 | setICImplementBallsEvent = {};
181 | setICImplementBallsEvent_mt = Class(setICImplementBallsEvent, Event);
182 | InitEventClass(setICImplementBallsEvent, "setICImplementBallsEvent");
183 |
184 | function setICImplementBallsEvent:emptyNew()
185 | local self = Event:new(setICImplementBallsEvent_mt );
186 | self.className="setICImplementBallsEvent";
187 | return self;
188 | end;
189 | function setICImplementBallsEvent:new(vehicle, state, ballIndex, animationIndex)
190 | self.vehicle = vehicle;
191 | self.state = state;
192 | self.ballIndex = Utils.getNoNil(ballIndex, 1);
193 | return self;
194 | end;
195 | function setICImplementBallsEvent:readStream(streamId, connection)
196 | self.vehicle = NetworkUtil.readNodeObject(streamId);
197 | self.state = streamReadBool(streamId);
198 | self.ballIndex = streamReadUIntN(streamId, 6);
199 | self:run(connection);
200 | end;
201 | function setICImplementBallsEvent:writeStream(streamId, connection)
202 | NetworkUtil.writeNodeObject(streamId, self.vehicle);
203 | streamWriteBool(streamId, self.state );
204 | streamWriteUIntN(streamId, self.ballIndex, 6);
205 | end;
206 | function setICImplementBallsEvent:run(connection)
207 | if self.vehicle ~= nil then
208 | self.vehicle:setImplementBalls(self.ballIndex, self.state, true);
209 | end;
210 | if not connection:getIsServer() then
211 | g_server:broadcastEvent(setICImplementBallsEvent:new(self.vehicle, self.state, self.ballIndex), nil, connection, self.object);
212 | end;
213 | end;
214 | function setICImplementBallsEvent.sendEvent(vehicle, state, ballIndex, noEventSend)
215 | if noEventSend == nil or noEventSend == false then
216 | if g_server ~= nil then
217 | g_server:broadcastEvent(setICImplementBallsEvent:new(vehicle, state, ballIndex), nil, nil, vehicle);
218 | else
219 | g_client:getServerConnection():sendEvent(setICImplementBallsEvent:new(vehicle, state, ballIndex));
220 | end;
221 | end;
222 | end;
--------------------------------------------------------------------------------
/FS19_simpleIC/sic_implementControl.lua:
--------------------------------------------------------------------------------
1 | -- SimpleIC ImplementControl
2 | -- to control Implements via SimpleIC
3 |
4 | sic_implementControl = {};
5 |
6 | function sic_implementControl.prerequisitesPresent(specializations)
7 | return true;
8 | end;
9 |
10 | function sic_implementControl.registerEventListeners(vehicleType)
11 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", sic_implementControl);
12 | SpecializationUtil.registerEventListener(vehicleType, "onUpdate", sic_implementControl);
13 | end;
14 |
15 | function sic_implementControl:onLoad(savegame)
16 | self.loadImplementControl = sic_implementControl.loadImplementControl;
17 | self.setImplementControl = sic_implementControl.setImplementControl;
18 |
19 | -- access tables
20 | if self.sic_at == nil then
21 | self.sic_at = {};
22 | end;
23 | self.sic_at.attacherIndex_implementControl = {};
24 | self.sic_at.implementControl = {};
25 | end;
26 |
27 |
28 | function sic_implementControl:loadImplementControl(key, table)
29 | local implementControl = {};
30 |
31 | implementControl.attacherIndices = StringUtil.splitString(" ", getXMLString(self.xmlFile, key.."#attacherIndices"));
32 | implementControl.controlSelf = getXMLBool(self.xmlFile, key.."#controlSelf")
33 | implementControl.isType = {}
34 | if #implementControl.attacherIndices > 0 or implementControl.controlSelf then
35 |
36 | for _ , attacherIndex in pairs(implementControl.attacherIndices) do
37 | self.sic_at.attacherIndex_implementControl[tonumber(attacherIndex)] = implementControl;
38 | end;
39 |
40 | implementControl.types = StringUtil.splitString(" ", getXMLString(self.xmlFile, key.."#types"));
41 |
42 | for _, type in pairs(implementControl.types) do
43 | implementControl.isType[type] = true;
44 | end;
45 |
46 | local animationName = getXMLString(self.xmlFile, key..".leverAnimation#animationName");
47 | if animationName ~= "" and animationName ~= nil then
48 | implementControl.leverAnimation = {};
49 | implementControl.leverAnimation.animationName = animationName;
50 | implementControl.leverAnimation.doNotSynch = getXMLBool(self.xmlFile, key..".leverAnimation#doNotSynch");
51 |
52 | implementControl.leverAnimation.returnToCenter = getXMLBool(self.xmlFile, key..".leverAnimation#returnToCenter");
53 | implementControl.leverAnimation.returnToCenterRaised = getXMLBool(self.xmlFile, key..".leverAnimation#returnToCenterRaised");
54 | implementControl.leverAnimation.returnToCenterLowered = getXMLBool(self.xmlFile, key.."leverAnimation#returnToCenterLowered");
55 |
56 | if implementControl.leverAnimation.returnToCenter or implementControl.leverAnimation.returnToCenterRaised then
57 | self:playAnimation(implementControl.leverAnimation.animationName, 1, animTime, true);
58 | self:setAnimationStopTime(implementControl.leverAnimation.animationName, 0.5);
59 | end;
60 | end;
61 |
62 | table.implementControl = implementControl;
63 | self.sic_at.implementControl[#self.sic_at.implementControl+1] = implementControl;
64 | return true;
65 | end;
66 |
67 | end;
68 |
69 |
70 | function sic_implementControl:setImplementControl(wantedState, i)
71 | local implementControl = self.spec_simpleIC.icFunctions[i].implementControl;
72 |
73 | local currentObject = nil;
74 |
75 | -- if we are controlSelf than currentObject will be self
76 | if implementControl.controlSelf then
77 | currentObject = self;
78 | else
79 | -- cycle through all attacherIndices of the current function
80 | for _, attacherIndex in pairs(implementControl.attacherIndices) do
81 | -- cycle through all attacher implements to see if we find a match
82 | for _, implement in pairs(self.spec_attacherJoints.attachedImplements) do
83 | -- if we found a match, "secure" that as our current implement
84 | if tostring(implement.jointDescIndex) == attacherIndex then
85 | currentObject = implement.object;
86 | break;
87 | end;
88 |
89 | end;
90 | if currentObject ~= nil then
91 | break;
92 | end;
93 | end;
94 | end;
95 |
96 | -- now that we find the prioritised object, find the priority function
97 | if currentObject ~= nil then
98 | for _, type in pairs(implementControl.types) do
99 |
100 | if type == "fold" then
101 | -- try do the folding stuffs
102 | if currentObject.spec_foldable ~= nil then
103 | if #currentObject.spec_foldable.foldingParts > 0 then
104 | local toggleDirection = Utils.getNoNil(wantedState, currentObject:getToggledFoldDirection());
105 | if toggleDirection == currentObject.spec_foldable.turnOnFoldDirection then
106 | currentObject:setFoldState(toggleDirection, true);
107 | else
108 | currentObject:setFoldState(toggleDirection, false);
109 | end;
110 | break; -- we done, we break
111 | end;
112 | end;
113 | end;
114 |
115 | if type == "tip" then
116 |
117 | print("tiiiiip")
118 |
119 | end;
120 |
121 | end;
122 | end;
123 | end;
124 |
125 | function sic_implementControl:onUpdate(dt)
126 | if self:getIsActive() then
127 | for _, implementControl in pairs(self.sic_at.implementControl) do
128 | if implementControl.leverAnimation ~= nil and implementControl.leverAnimation.dirtySelf ~= nil then
129 | local leverAnimation = implementControl.leverAnimation;
130 |
131 | -- foldable lever animation return to center
132 | local foldTime = leverAnimation.dirtySelf:getFoldAnimTime()
133 | local animTime = self:getAnimationTime(leverAnimation.animationName)
134 | if leverAnimation.returnToCenter then
135 | if foldTime == 0 then
136 | self:playAnimation(leverAnimation.animationName, 1, animTime, true);
137 | self:setAnimationStopTime(leverAnimation.animationName, 0.5);
138 | leverAnimation.dirtySelf = nil;
139 | elseif foldTime == 1 then
140 | self:playAnimation(leverAnimation.animationName, -1, animTime, true);
141 | self:setAnimationStopTime(leverAnimation.animationName, 0.5);
142 | leverAnimation.dirtySelf = nil;
143 | end;
144 | end;
145 | if leverAnimation.returnToCenterRaised then
146 | if foldTime == 1 then
147 | self:playAnimation(leverAnimation.animationName, -1, animTime, true);
148 | self:setAnimationStopTime(leverAnimation.animationName, 0.5);
149 | leverAnimation.dirtySelf = nil;
150 | end;
151 | end;
152 | if leverAnimation.returnToCenterLowered then
153 | if foldTime == 0 then
154 | self:playAnimation(leverAnimation.animationName, 1, animTime, true);
155 | self:setAnimationStopTime(leverAnimation.animationName, 0.5);
156 | leverAnimation.dirtySelf = nil;
157 | end;
158 | end;
159 |
160 | end;
161 | end;
162 |
163 | end;
164 | end;
165 |
166 |
167 | -- Foldable
168 | function sic_implementControl.setFoldStateAppend(self, superFunc, direction, moveToMiddle, noEventSend)
169 |
170 | local returnValues = superFunc(self, direction, moveToMiddle, noEventSend);
171 |
172 |
173 | -- if we are an implement, we need to get our attacherVehicle
174 | if self.getAttacherVehicle ~= nil then
175 | local attacherVehicle = self:getAttacherVehicle()
176 | -- check if attacherVehicle has simpleIC
177 | if attacherVehicle ~= nil and attacherVehicle.spec_simpleIC ~= nil and attacherVehicle.spec_simpleIC.hasIC then
178 | -- run through implements attached to attacherVehicle to find out attacherIndex
179 | for _, implement in pairs(attacherVehicle.spec_attacherJoints.attachedImplements) do
180 | if implement.object == self then
181 | local implementControl = attacherVehicle.sic_at.attacherIndex_implementControl[implement.jointDescIndex];
182 | if implementControl ~= nil and implementControl.isType["fold"] and implementControl.leverAnimation ~= nil then
183 | -- run animation
184 | attacherVehicle:playAnimation(implementControl.leverAnimation.animationName, direction, attacherVehicle:getAnimationTime(implementControl.leverAnimation.animationName), true);
185 | implementControl.leverAnimation.dirtySelf = self;
186 | end;
187 | end;
188 | end;
189 | end;
190 | end;
191 |
192 | return returnValues;
193 | end;
194 | Foldable.setFoldState = Utils.overwrittenFunction(Foldable.setFoldState, sic_implementControl.setFoldStateAppend);
--------------------------------------------------------------------------------
/FS19_simpleIC/registerSimpleIC.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | Changelog
3 | ##### V 0.9.3.4
4 | - Hotfix game not loading without EnhancedVehicle active
5 | ##### V 0.9.3.3
6 | - implementControl leverAnimation fix, addition of returnToCenter, returnToCenterLowered, returnToCenterRaised
7 | - fixed ptoControl for mods using attacherIndex instead of attacherIndices (pre 0.9.3.2 mods)
8 | - drivableControl initial implementation (not done yet)
9 | ##### V 0.9.3.2
10 | - simpleIC_implementBalls.lua:207: attempt to index field 'vehicle' fixed (at least I hope that did the trick, I assume this error comes from synch issues not actual bug in script)
11 | - code cleanup ptoControl
12 | - addition of implementControl though not fully implemented yet (thus no example in examples.xml yet)
13 | - addition of disableInvisibleTriggers attribute if you want to disable triggerPoints via visibility. Was on by default in previous versions since implementation.
14 | But when people converted old IC to simpleIC they just set the old buttons to invisible and used the index for IC, now all of those didn't work anymore.
15 | So now by default it SimpleIC doesn't care about visibilty but if you want to disable triggerPoints via visibility you can do that by adding this attribute. (see Examples XML)
16 | ##### V 0.9.3.1
17 | - added motorStartControl and animations
18 | ## V 0.9.3.0
19 | - lightControl leverAnimations for all types added and synched
20 | - debugPrints removed
21 | ## V 0.9.2.9
22 | - implementBalls synch Issue possible fix
23 | - lightControl addition (leverAnimations still to do)
24 | ## V 0.9.2.8
25 | - some bugfixes for the recent additions
26 | ## V 0.9.2.7
27 | - separated attacherControl into seperate lua
28 | - synchronized attacherControl with setJointMoveDown so its always in synch
29 | - fixed doNotSynch for ptoControl
30 | - added returnToCenter, returnToCenterRaised, returnToCenterLowered for attacherControl leverAnimation
31 | ## V 0.9.2.6
32 | - separated ptoControl into seperate lua
33 | - synchronized ptoControl animation with turnOnVehicle so its always in synch
34 | - fixed version numbering mishap (yes this is 0.9.2.6 not 0.9.1.6)
35 | ## V 0.9.2.5
36 | - added attacherControl
37 | - added ptoControl
38 | ## V 0.9.2.4
39 | - made icFunctions more universally usable for future additions
40 | - icFunction can be "turned off" by setting visibility of triggerPoint to false
41 | ## V 0.9.2.3
42 | - MP Server fix of vehicle not enterable
43 | ## V 0.9.2.2
44 | - fix for line 102 error I think, couldn't reproduce but I found an issue with the table indexing and I think it worked fine for most mods but some may have caused the issue to show.
45 | ## V 0.9.2.1
46 | - possibly fixed dedicated server issue
47 | - removed "cylinder" debug finally
48 | ## V 0.9.2.0
49 | - addition of SimpleIC-ImplementBalls
50 | ## V 0.9.1.9
51 | - fixed the issue introduced in the version before last version and partially fixed in the last version. Now fixed completely. I hope.. again.
52 | ## V 0.9.1.8
53 | - fixed Issue introduced in the last version of indoor buttons only working when the ingame-menu is on, fully removed issue with double-mapping of mouseButtons I hope
54 | ## V 0.9.1.7
55 | - fixed Error: simpleIC.lua:488: attempt to index field 'spec_motorized' (a nil value)
56 | - fixed Error: simpleIC.lua:318: attempt to call method 'getAttacherVehicle' (a nil value)
57 | - reachDistance can be set per vehicle (optional, default 1.8) to specify how far away a player can reach an IC-point
58 | ## V 0.9.1.6
59 | - fixed spec insertion so simpleIC now works in every implement, trailer etc. not just drivables
60 | ## V 0.9.1.5
61 | - fixed Error: simpleIC.lua:248: attempt to index local 'spec' (a nil value)
62 | - added cylinderAnimation for easy animation of struts on windows/doors etc.
63 | ## V 0.9.1.4
64 | - fixed IC active on all vehicles bug (now only active if vehicle actually has IC functions)
65 | - fixed bug Error: Running LUA method 'update' simpleIC.lua:292: attempt to index a nil value
66 | - added default keymapping
67 | ## V 0.9.1.3
68 | - multiplayer fix
69 | - added triggerPoint_ON and triggerPoint_OFF as alternative to toggle via triggerPoint
70 |
71 |
72 | ]]
73 |
74 |
75 | registerSimpleIC = {};
76 |
77 | registerSimpleIC.version = "0.9.2.6"
78 |
79 | local modName = g_currentModName;
80 | local modDirectory = g_currentModDirectory;
81 |
82 | function init()
83 | VehicleTypeManager.validateVehicleTypes = Utils.prependedFunction(VehicleTypeManager.validateVehicleTypes, validateVehicleTypes)
84 | print("SimpleIC Version "..registerSimpleIC.version.." init.");
85 | end
86 |
87 |
88 | function validateVehicleTypes(vehicleTypeManager)
89 | registerSimpleIC.installSpecializations(g_vehicleTypeManager, g_specializationManager, modDirectory, modName)
90 | end
91 |
92 |
93 | function registerSimpleIC.installSpecializations(vehicleTypeManager, specializationManager, modDirectory, modName)
94 | specializationManager:addSpecialization("sic_drivableControl", "sic_drivableControl", modDirectory.."sic_drivableControl.lua", nil)
95 | specializationManager:addSpecialization("sic_implementControl", "sic_implementControl", modDirectory.."sic_implementControl.lua", nil)
96 | specializationManager:addSpecialization("sic_motorStartControl", "sic_motorStartControl", modDirectory.."sic_motorStartControl.lua", nil)
97 | specializationManager:addSpecialization("sic_lightControl", "sic_lightControl", modDirectory.."sic_lightControl.lua", nil)
98 | specializationManager:addSpecialization("sic_attacherControl", "sic_attacherControl", modDirectory.."sic_attacherControl.lua", nil)
99 | specializationManager:addSpecialization("sic_ptoControl", "sic_ptoControl", modDirectory.."sic_ptoControl.lua", nil)
100 | specializationManager:addSpecialization("simpleIC", "simpleIC", modDirectory.."simpleIC.lua", nil)
101 | specializationManager:addSpecialization("simpleIC_implementBalls", "simpleIC_implementBalls", modDirectory.."simpleIC_implementBalls.lua", nil)
102 |
103 |
104 | for typeName, typeEntry in pairs(vehicleTypeManager:getVehicleTypes()) do
105 |
106 | if typeName ~= "horse" and typeName ~= "pallet" then -- ignore pallets and horse
107 | -- add simpleIC to everything except locomotives
108 | if not SpecializationUtil.hasSpecialization(Locomotive, typeEntry.specializations) then
109 | vehicleTypeManager:addSpecialization(typeName, modName .. ".sic_drivableControl")
110 | vehicleTypeManager:addSpecialization(typeName, modName .. ".sic_implementControl")
111 | vehicleTypeManager:addSpecialization(typeName, modName .. ".sic_motorStartControl")
112 | vehicleTypeManager:addSpecialization(typeName, modName .. ".sic_lightControl")
113 | vehicleTypeManager:addSpecialization(typeName, modName .. ".sic_attacherControl")
114 | vehicleTypeManager:addSpecialization(typeName, modName .. ".sic_ptoControl")
115 | vehicleTypeManager:addSpecialization(typeName, modName .. ".simpleIC")
116 | print("inserted simpleIC to "..tostring(typeName));
117 | if SpecializationUtil.hasSpecialization(Attachable, typeEntry.specializations) then
118 | vehicleTypeManager:addSpecialization(typeName, modName .. ".simpleIC_implementBalls")
119 | print("inserted simpleIC_implementBalls to "..tostring(typeName));
120 | end;
121 | end;
122 | end
123 | end
124 |
125 | end
126 |
127 | init()
128 |
129 | -- FIX for double-mapping of mouse buttons by Stephan-S
130 | function registerSimpleIC:mouseEvent(posX, posY, isDown, isUp, button)
131 | if isUp or isDown then
132 | --Check if this is the key assigned to INTERACT
133 | local action = g_inputBinding:getActionByName("INTERACT_IC_VEHICLE");
134 | for _, binding in ipairs(action.bindings) do
135 | if binding.axisNames[1] ~= nil and binding.axisNames[1] == Input.mouseButtonIdToIdName[button] then
136 | local vehicle = g_currentMission.controlledVehicle
137 | if vehicle ~= nil and vehicle.spec_simpleIC ~= nil then
138 | if isDown then
139 | vehicle.spec_simpleIC.interact_present = true;
140 | if not vehicle.spec_simpleIC.interact_default then
141 | vehicle:doInteraction()
142 | end;
143 | elseif isUp then
144 | vehicle.spec_simpleIC.interact_present = false;
145 | end
146 | end
147 | end
148 | end
149 | end;
150 | end;
151 |
152 | function registerSimpleIC:update(dt)
153 | if g_currentMission.simpleIC_implementBalls ~= nil then -- check if we have implementBalls active
154 | --print("simpleIC_implementBalls not nil")
155 | if g_currentMission.controlPlayer and g_currentMission.player ~= nil and not g_gui:getIsGuiVisible() then -- check if we are the player and no GUI is open
156 | --print("run player")
157 | local x, y, z = getWorldTranslation(g_currentMission.player.rootNode); -- get player pos
158 | for index, spec in pairs(g_currentMission.simpleIC_implementBalls) do -- run through all implementBalls specs
159 | for _, implementJoint in pairs(spec.implementJoints) do -- run through all inputAttachers with implement type of this spec
160 | local aX, aY, aZ = getWorldTranslation(implementJoint.node) -- get pos of implement joint node
161 |
162 | local distance = MathUtil.vector3Length(x - aX, y - aY, z - aZ); -- get distance to player
163 |
164 | --print("distance: "..tostring(distance))
165 |
166 | if distance < spec.maxDistance then -- if we're close enough activate stuffs
167 | -- if we're in distance, show the X and activate inputBinding
168 | implementJoint.showX = true;
169 | spec.vehicle:raiseActive()
170 |
171 | if not spec.isInputActive then
172 | local specSIC = spec.vehicle.spec_simpleIC;
173 | specSIC.actionEvents = {}; -- create actionEvents table since in case we didn't enter the vehicle yet it does not exist
174 | spec.vehicle:clearActionEventsTable(specSIC.actionEvents); -- also clear it for good measure
175 | local _ , eventId = spec.vehicle:addActionEvent(specSIC.actionEvents, InputAction.INTERACT_IC_ONFOOT, spec.vehicle, simpleIC.INTERACT, false, true, false, true); -- now add the actionEvent
176 | spec.isInputActive = true;
177 | end;
178 | else
179 | if spec.isInputActive then
180 | spec.vehicle:removeActionEvent(spec.vehicle.spec_simpleIC.actionEvents, InputAction.INTERACT_IC_ONFOOT);
181 | spec.isInputActive = false;
182 | implementJoint.showX = false;
183 | end;
184 | end;
185 | end;
186 | end;
187 | end;
188 | end;
189 |
190 | end;
191 |
192 | addModEventListener(registerSimpleIC)
--------------------------------------------------------------------------------
/FS19_simpleIC/sic_attacherControl.lua:
--------------------------------------------------------------------------------
1 | -- SimpleIC Attacher Control
2 | -- to control lowering/raising of implements attached to vehicles attacher
3 |
4 | sic_attacherControl = {};
5 |
6 | function sic_attacherControl.prerequisitesPresent(specializations)
7 | return true;
8 | end;
9 |
10 | function sic_attacherControl.registerEventListeners(vehicleType)
11 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", sic_attacherControl);
12 | SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", sic_attacherControl);
13 | SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", sic_attacherControl);
14 |
15 | --SpecializationUtil.registerEventListener(vehicleType, "onPreAttachImplement", sic_attacherControl);
16 | --SpecializationUtil.registerEventListener(vehicleType, "onPreDetachImplement", sic_attacherControl);
17 | end;
18 |
19 | function sic_attacherControl:onPreDetachImplement(implement)
20 | for _ , icFunction in pairs(self.spec_simpleIC.icFunctions) do
21 | if icFunction.attacherControl ~= nil and icFunction.attacherControl.attacherIndex == implement.jointDescIndex then
22 | icFunction.attacherControl.isImplementAttached = false;
23 |
24 | if icFunction.leverAnimation ~= nil then
25 | local leverAnimation = icFunction.leverAnimation;
26 |
27 | local animTime = self:getAnimationTime(leverAnimation.animationName);
28 |
29 | if animTime > leverAnimation.detachedAnimTime then
30 | self:playAnimation(leverAnimation.animationName, -1, animTime, true);
31 | self:setAnimationStopTime(leverAnimation.animationName, leverAnimation.detachedAnimTime);
32 | elseif animTime < leverAnimation.detachedAnimTime then
33 | self:playAnimation(leverAnimation.animationName, 1, animTime, true);
34 | self:setAnimationStopTime(leverAnimation.animationName, leverAnimation.detachedAnimTime);
35 | end;
36 | end;
37 | end;
38 | end;
39 | end;
40 |
41 | function sic_attacherControl:onPreAttachImplement(inputJointDescIndex, jointDescIndex)
42 |
43 | local jointDesc = self.spec_attacherJoints.attacherJoints[jointDescIndex]
44 |
45 | for _ , icFunction in pairs(self.spec_simpleIC.icFunctions) do
46 | if icFunction.attacherControl ~= nil and icFunction.attacherControl.attacherIndex == jointDescIndex then
47 | icFunction.attacherControl.isImplementAttached = true;
48 |
49 | if icFunction.leverAnimation ~= nil then
50 | local leverAnimation = icFunction.leverAnimation;
51 |
52 | local animTime = self:getAnimationTime(leverAnimation.animationName);
53 | self:playAnimation(leverAnimation.animationName, -1, animTime, true);
54 | end;
55 | end;
56 | end;
57 |
58 | end;
59 |
60 | function sic_attacherControl:onLoad(savegame)
61 | self.loadAttacherControl = sic_attacherControl.loadAttacherControl;
62 | self.setAttacherControl = sic_attacherControl.setAttacherControl;
63 |
64 | self.sic_attacherControl = {};
65 |
66 | self.sic_attacherControl.attacherIndexToICFunction = {};
67 |
68 | end;
69 |
70 | function sic_attacherControl:onPostLoad(savegame)
71 | for _ , icFunction in pairs(self.spec_simpleIC.icFunctions) do
72 | if icFunction.attacherControl and icFunction.attacherControl.leverAnimation ~= nil and not icFunction.attacherControl.isImplementAttached then
73 | local leverAnimation = icFunction.attacherControl.leverAnimation;
74 | local animTime = self:getAnimationTime(leverAnimation.animationName);
75 | if animTime > leverAnimation.detachedAnimTime then
76 | self:playAnimation(leverAnimation.animationName, -1, animTime, true);
77 | self:setAnimationStopTime(leverAnimation.animationName, leverAnimation.detachedAnimTime);
78 | elseif animTime < leverAnimation.detachedAnimTime then
79 | self:playAnimation(leverAnimation.animationName, 1, animTime, true);
80 | self:setAnimationStopTime(leverAnimation.animationName, leverAnimation.detachedAnimTime);
81 | end;
82 | end;
83 | end;
84 | end;
85 |
86 |
87 | function sic_attacherControl:onUpdateTick(dt)
88 | if self:getIsActive() then
89 |
90 | -- code for centering lever after lowering or raising depending on setting in XML
91 | for _ , icFunction in pairs(self.spec_simpleIC.icFunctions) do
92 | if icFunction.attacherControl and icFunction.attacherControl.leverAnimation ~= nil then
93 | if icFunction.attacherControl.attacherIndex ~= nil then
94 | local jointDesc = self.spec_attacherJoints.attacherJoints[icFunction.attacherControl.attacherIndex]
95 |
96 | if jointDesc.moveAlpha ~= nil then
97 |
98 | local moveAlpha = Utils.getMovedLimitedValue(jointDesc.moveAlpha, jointDesc.lowerAlpha, jointDesc.upperAlpha, jointDesc.moveTime, dt, not jointDesc.moveDown)
99 |
100 | local leverAnimation = icFunction.attacherControl.leverAnimation;
101 |
102 | if moveAlpha ~= leverAnimation.moveAlpha then
103 | if (moveAlpha == 1 or moveAlpha == 0) and leverAnimation.returnToCenter then
104 |
105 | local animTime = self:getAnimationTime(leverAnimation.animationName);
106 | if animTime > 0.5 then
107 | self:playAnimation(leverAnimation.animationName, -1, animTime, true);
108 | self:setAnimationStopTime(leverAnimation.animationName, 0.5)
109 | elseif animTime < 0.5 then
110 | self:playAnimation(leverAnimation.animationName, 1, animTime, true);
111 | self:setAnimationStopTime(leverAnimation.animationName, 0.5)
112 | end;
113 |
114 | elseif moveAlpha == 0 and leverAnimation.returnToCenterRaised then
115 | local animTime = self:getAnimationTime(leverAnimation.animationName);
116 |
117 | if animTime < 0.5 then
118 | self:playAnimation(leverAnimation.animationName, 1, animTime, true);
119 | self:setAnimationStopTime(leverAnimation.animationName, 0.5)
120 | end;
121 | elseif moveAlpha == 1 and leverAnimation.returnToCenterLowered then
122 | local animTime = self:getAnimationTime(leverAnimation.animationName);
123 |
124 | if animTime > 0.5 then
125 | self:playAnimation(leverAnimation.animationName, -1, animTime, true);
126 | self:setAnimationStopTime(leverAnimation.animationName, 0.5)
127 | end;
128 | end;
129 | leverAnimation.moveAlpha = moveAlpha;
130 | end;
131 | end;
132 | end;
133 | end;
134 | end;
135 | end;
136 | end;
137 |
138 |
139 |
140 |
141 |
142 | function sic_attacherControl:loadAttacherControl(key, table)
143 | -- load attacherControl attributes
144 | local attacherControl = {}
145 | attacherControl.attacherIndex = getXMLInt(self.xmlFile, key.."#attacherIndex");
146 | if attacherControl.attacherIndex ~= nil then
147 |
148 | local animationName = getXMLString(self.xmlFile, key..".leverAnimation#animationName");
149 | if animationName ~= "" and animationName ~= nil then
150 |
151 | attacherControl.leverAnimation = {};
152 | attacherControl.leverAnimation.animationName = animationName;
153 | attacherControl.leverAnimation.doNotSynch = getXMLBool(self.xmlFile, key..".leverAnimation#doNotSynch");
154 |
155 | attacherControl.leverAnimation.returnToCenter = getXMLBool(self.xmlFile, key..".leverAnimation#returnToCenter");
156 | attacherControl.leverAnimation.returnToCenterRaised = getXMLBool(self.xmlFile, key..".leverAnimation#returnToCenterRaised");
157 | attacherControl.leverAnimation.returnToCenterLowered = getXMLBool(self.xmlFile, key.."leverAnimation#returnToCenterLowered");
158 |
159 | attacherControl.leverAnimation.detachedAnimTime = Utils.getNoNil(getXMLFloat(self.xmlFile, key..".leverAnimation#detachedAnimTime"), 1);
160 |
161 | attacherControl.leverAnimation.moveAlpha = 0.5;
162 |
163 | end;
164 |
165 | self.sic_attacherControl.attacherIndexToICFunction[attacherControl.attacherIndex] = table;
166 |
167 | table.attacherControl = attacherControl;
168 | return true;
169 | end;
170 |
171 | end;
172 |
173 | function sic_attacherControl:setAttacherControl(wantedState, i)
174 | -- gets called when IC trigger is triggered
175 | local attacherControl = self.spec_simpleIC.icFunctions[i].attacherControl;
176 | local spec_attacherJoints = self.spec_attacherJoints;
177 |
178 | if spec_attacherJoints.attacherJoints[attacherControl.attacherIndex] ~= nil then
179 | if wantedState == nil then
180 | wantedState = not spec_attacherJoints.attacherJoints[attacherControl.attacherIndex].moveDown
181 | end;
182 |
183 | self:setJointMoveDown(attacherControl.attacherIndex, wantedState)
184 |
185 | if attacherControl.leverAnimation ~= nil and attacherControl.leverAnimation.doNotSynch then
186 | local speed = 1;
187 | if not wantedState then
188 | speed = -1;
189 | end;
190 | self:playAnimation(attacherControl.leverAnimation.animationName, speed, self:getAnimationTime(attacherControl.leverAnimation.animationName), true);
191 | end;
192 |
193 | end;
194 | end;
195 |
196 | function sic_attacherControl.setJointMoveDownAppend(self, superFunc, jointDescIndex, moveDown, noEventSend)
197 |
198 | superFunc(self, jointDescIndex, moveDown, noEventSend);
199 |
200 | -- code for running animation if attacher is raised/lowered
201 | if self.spec_simpleIC ~= nil and self.spec_simpleIC.hasIC then
202 | for _ , icFunction in pairs(self.spec_simpleIC.icFunctions) do
203 | if icFunction.attacherControl and icFunction.attacherControl.leverAnimation ~= nil then
204 | if icFunction.attacherControl.attacherIndex == jointDescIndex then
205 | local speed = -1;
206 | if moveDown then
207 | speed = 1;
208 | end;
209 | self:playAnimation(icFunction.attacherControl.leverAnimation.animationName, speed, self:getAnimationTime(icFunction.attacherControl.leverAnimation.animationName), true);
210 | end;
211 | end;
212 | end;
213 | end;
214 |
215 | end;
216 | AttacherJoints.setJointMoveDown = Utils.overwrittenFunction(AttacherJoints.setJointMoveDown, sic_attacherControl.setJointMoveDownAppend);
217 |
--------------------------------------------------------------------------------
/examples.xml:
--------------------------------------------------------------------------------
1 |
2 | A few examples on how to set up simpleIC in XML.
3 | The first is the "bare minimum" XML code needed to get simpleIC working.
4 | I have not included the lines used to animate the windows/doors etc. since that is universal as it uses basegame animations.
5 | If you don't know how to do that, look at a tutorial which explains that or ask someone (after you tried to figure out yourself of course).
6 | The second example is the current "normal" code with all the optional stuff.
7 | The third example is using triggerPoint_ON and triggerPoint_OFF which means that instead of one "X" to click as a toggle you've got two marks, one that will
8 | "open" the animation, the other one that will close the "animation".
9 | The triggerPoint stuff is global to the script so if I add features in future that aren't controlling animations, it is still "valid" to use off and on points.
10 |
11 | For an example on how it is actually implemented in a mod, take a look at my Deutz Agrostar Edit I linked in the Readme on Github. (youtube video link)
12 |
13 |
14 | ## absolute basic IC function animation lines:
15 | ______________________________________________
16 | -- animationName -> name of the animation controlled by this IC function
17 | -- insideTrigger triggerPoint -> index of the transform group that marks the trigger point
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ## advanced IC function animation lines with optional stuff:
26 | ____________________________________________________________
27 | -- outsideInteractionTrigger -> index of the playerTrigger for outside (onFoot) interaction
28 | -- animationName -> name of the animation controlled by this IC function
29 | -- animationSpeed -> speed the animation is played at (can also be negative)
30 | -- sharedAnimation -> not yet implemented
31 | -- soundVolumeIncreasePercentage -> percentage by which the volume will increase from insideVolume to outsideVolume if this animation is "on" e.g. door/window is open
32 | -- insideTrigger -> line for the triggerPoints that can be triggered from inside camera
33 | -- outsideTrigger -> line for the triggerPoints that can be triggered from outside camera or player on foot
34 | -- triggerPoint -> index of the transform group that marks the particular trigger point
35 | -- triggerPointSize -> radius around the triggerPoint in cm where it still registeres as triggered
36 | -- reachDistance -> the max. distance to which a player can reach an IC point (indoor camera only, default 1.8)
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | ## advanced IC function animation lines with optional 2 trigger points (on and off point instead of toggle):
45 | ____________________________________________________________________________________________________________
46 | -- all the same as the one above except:
47 | -- triggerPoint_ON -> index of the transform group that marks the particular triggerPoint for turning the IC function "on" (animation playing towards end)
48 | -- triggerPoint_OFF -> index of the transform group that marks the particular triggerPoint for turning the IC function "off" (animation playing towards start)
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | ## IC function with easy cylinder animation:
58 | ____________________________________________
59 | -- as for the cylinderAnimations:
60 | -- node1 -> index of one of the nodes for the cylinder
61 | -- node2 -> index of the other node for the cylinder
62 | ----------------------------------------------------
63 | cylinder-nodes are directed at each other, meaning the other part is also acting as reference point.
64 | In order for this to work, the cylinder-parts pivot has to be oriented in a way that the positive Z axis points the direction the cylinder-part points at.
65 | The "rotation" axis is the Y axis (green axis)
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | ## Enabling triggerPoints being disabled when triggerPoint transform-group is invisible
79 | -- disableInvisibleTriggers -> set to true will enable this feature. Default is off to keep backwards-compatible with older mods
80 |
81 | [...]
82 |
83 |
84 |
85 |
86 | ## IC function motorStartControl:
87 | There is no attributes for motorStartControl itself
88 | -- (optional) leverAnimation -> animation to be played for a lever/button. Animation is synchronized with motor start/stop state via other inputs. Animation will play from 0-1 if engine is started and 1-0 if engine is stopped unless isTurnKeyAnimation is true
89 | -- animationName -> name of animation
90 | -- (optional) isTurnKeyAnimation -> if this is set to true the animation will play from 0 to 1 and then back to 0.7 when motor is started. Back to 0 when motor is stopped.
91 | To animate starting via key as you turn it to start position and then let go to run position.
92 | -- (optional) leverAnimationStart -> animation to be played when engine is started. Animation will be played from 0-1 and then back to 0.
93 | -- animationName -> name of animation
94 | -- (optional) leverAnimationStop -> animation to be played when engine is stopped. Animation will be played from 0-1 and then back to 0.
95 | -- animationName -> name of animation
96 | -- triggerPoints work exactly the same as for animations (see above), so you can do triggerPoint_ON and triggerPoint_OFF for starting and stopping engine on different controls
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | ## IC function attacherControl:
106 | -- attacherIndices -> Indices of Attacher in XML (same as for powerTakeoffConfigurations, hoses etc.) you can add multiple attacherIndices because you have one pto for multiple attachers (implement, trailer, low..)
107 | -- (attacherIndex -> depreceated, don't use anymore. Use attacherIndices instead. It still works to be backwards-compatible but better to use attacherIndices)
108 | -- (optional) leverAnimation -> animation to be played for a lever/button, animation is synchronized to lowered/raised state of attacher
109 | -- animationName -> name of animation for leverAnimation
110 | -- (optional) doNotSynch -> don't synch lever animation to inputs with key-binding instead of simpleIC. Not sure why you'd want that but its there if you need it
111 | -- (optional) returnToCenter -> lever will return to center of its animation when implement is finished raising or lowering
112 | -- (optional) returnToCenterRaised -> lever will return to center of its animation when implement is raised only
113 | -- (optional) returnToCenterLowered -> lever will return to center of its animation when implement is lowered only
114 | ! of course only one, either returnToCenter or returnToCenterLowered or returnToCenterRaised should be true anything else doesn't make sense and might not return the expected result !
115 | -- triggerPoints work exactly the same as for animations (see above), so you can do triggerPoint_ON and triggerPoint_OFF for raising/lowering too
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | ## IC function ptoControl:
126 | -- attacherIndex -> Index of Attacher in XML in which the implement needs to be attached for this pto control to control it
127 | (Everything is the same as with attacherControl)
128 | -- (optional) leverAnimation, doNotSynch (optional) set to true if you don't want to synch animation with turning implement on/off with key-binding instead of IC
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | ## IC function lightControl
137 | This one is a bit more difficult to wrap your head around especially regarding the lever animations since the light Control System in FS19 is rather unintuitive.
138 | I will try my best to explain my thoughts as to how I made the leverAnimations work though.
139 | There are 5 different types of lightControl you can have. The 5 types are "state", "toggle", "turnLightLeft", "turnLightRight" and "turnLightHazard" each of which have their own attributes and animation-attributes.
140 | So I'm going to explain all 5 of them separately
141 |
142 | :: type "state"
143 | -- lightTypes -> the lightTypes this will turn on (see lightTypes in default lights section) in this example "1" is usually the rear worklight
144 | -- (optional) leverAnimation -> animation to be played for a lever/button, animation is synchronized with the lightTypes for this lightControl no matter how that lightType is turned on. (key-binding, IC, toggle)
145 |
146 |
147 |
148 |
149 |
150 | :: type "toggle"
151 | - no additional attributes for this. Toggle does the same as "F" key, it toggles through the lightTypes
152 | -- (optional) leverAnimation -> animation to be played for a lever/button. Animation is synchronized with stuff. See below
153 | -- animStopLightTypesN (replace n with number of lightType) animation will move to this animationTime if this lightType is currently on. Turns to the most significant lightTypes
154 | For example to animate a turn-dial switching between different lightTypes or a key that switches different lights when turned.
155 | If you don't want a lightType to influence the animation simply leave it out. For example just make animStopLightTypes2 and animStopLightTypes3 if you want that.
156 | If you don't quite understand how this works just try it out and see how it behaves.
157 |
158 |
159 |
160 |
161 |
162 | :: type "turnLightLeft"
163 | - no additional attributes for this. Just turning on/off left turnlight
164 | -- (optional) leverAnimation -> animation to be played for a lever/button. Animation is synchronized with stuff. See below
165 | -- (optional) isTurnlightSharedAnimation -> set this to true if the left and right turnlight use the same lever/button animation.
166 | Then the animation will default rest in 0.5 position, play to 0 position for right turnlight and 1 position for left turnlight.
167 | If you leave this away/false then the animation will just play to 1 if turnlight is on, 0 if its off.
168 |
169 |
170 |
171 |
172 |
173 | :: type "turnLightRight" (same as left)
174 | - no additional attributes for this. Just turning on/off left turnlight
175 | -- (optional) leverAnimation -> animation to be played for a lever/button. Animation is synchronized with stuff. See below
176 | -- (optional) isTurnlightSharedAnimation -> set this to true if the left and right turnlight use the same lever/button animation.
177 | Then the animation will default rest in 0.5 position, play to 0 position for right turnlight and 1 position for left turnlight.
178 | If you leave this away/false then the animation will just play to 1 if turnlight is on, 0 if its off.
179 |
180 |
181 |
182 |
183 |
184 | :: type "turnLightHazard"
185 | - no additional attributes for this. Just turning on/off left turnlight
186 | -- (optional) leverAnimation -> animation to be played for a lever/button. Animation is synchronized with hazards. Plays to 1 if on, 0 if off. Nothing special here.
187 |
188 |
189 |
190 |
--------------------------------------------------------------------------------
/FS19_simpleIC/sic_lightControl.lua:
--------------------------------------------------------------------------------
1 | -- SimpleIC Light Control
2 | -- to control Vehicle Lights via SimpleIC
3 |
4 | sic_lightControl = {};
5 |
6 | function sic_lightControl.prerequisitesPresent(specializations)
7 | return true;
8 | end;
9 |
10 | function sic_lightControl.registerEventListeners(vehicleType)
11 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", sic_lightControl);
12 | end;
13 |
14 |
15 | function sic_lightControl:onLoad(savegame)
16 | self.loadLightControl = sic_lightControl.loadLightControl;
17 | self.setLightControl = sic_lightControl.setLightControl;
18 | self.getBinaryFromDecimal = sic_lightControl.getBinaryFromDecimal;
19 | end;
20 |
21 |
22 | function sic_lightControl:loadLightControl(key, table)
23 |
24 | local type = getXMLString(self.xmlFile, key.."#type");
25 | if type ~= "" and type ~= nil then
26 | local lightControl = {};
27 | lightControl.type = type;
28 |
29 | lightControl.lightTypes = { StringUtil.getVectorFromString(getXMLString(self.xmlFile, key.."#lightTypes")) }
30 |
31 | local animationName = getXMLString(self.xmlFile, key..".leverAnimation#animationName");
32 | if animationName ~= "" and animationName ~= nil then
33 | lightControl.leverAnimation = {};
34 | lightControl.leverAnimation.animationName = animationName;
35 | --lightControl.leverAnimation.doNotSynch = getXMLBool(self.xmlFile, key..".leverAnimation#doNotSynch");
36 | lightControl.leverAnimation.isTurnlightSharedAnimation = getXMLBool(self.xmlFile, key..".leverAnimation#isTurnlightSharedAnimation")
37 |
38 | if lightControl.type == "toggle" then
39 | lightControl.leverAnimation.animStops = {};
40 | for i = 1, self.spec_lights.numLightTypes do
41 | local animStop = getXMLFloat(self.xmlFile, key..".leverAnimation#animStopLightTypes"..i-1);
42 | if animStop ~= nil then
43 | lightControl.leverAnimation.animStops[i] = animStop;
44 | end;
45 | end;
46 | end;
47 |
48 | end;
49 |
50 | table.lightControl = lightControl;
51 | return true;
52 | end;
53 |
54 |
55 | end;
56 |
57 | function sic_lightControl:setLightControl(wantedState, i)
58 | local lightControl = self.spec_simpleIC.icFunctions[i].lightControl;
59 |
60 | if lightControl ~= nil then
61 |
62 | local spec = self.spec_lights;
63 |
64 | -- get type and set
65 | if lightControl.type == "state" and #lightControl.lightTypes ~= 0 then
66 | local lightsTypesMask = 0;
67 | for i=1, #lightControl.lightTypes do
68 | lightsTypesMask = bitXOR(spec.lightsTypesMask, 2^lightControl.lightTypes[i]);
69 | end;
70 | --print(tostring(lightsTypesMask))
71 | self:setLightsTypesMask(lightsTypesMask);
72 |
73 | elseif lightControl.type == "toggle" then
74 | self:setNextLightsState();
75 |
76 | elseif lightControl.type == "turnLightLeft" then
77 | local state = Lights.TURNLIGHT_OFF;
78 | if spec.turnLightState ~= Lights.TURNLIGHT_LEFT then
79 | state = Lights.TURNLIGHT_LEFT;
80 | end;
81 | if wantedState ~= nil then
82 | if wantedState then
83 | state = Lights.TURNLIGHT_LEFT;
84 | else
85 | state = Lights.TURNLIGHT_OFF;
86 | end;
87 | end;
88 | self:setTurnLightState(state);
89 |
90 | elseif lightControl.type == "turnLightRight" then
91 | local state = Lights.TURNLIGHT_OFF;
92 | if spec.turnLightState ~= Lights.TURNLIGHT_RIGHT then
93 | state = Lights.TURNLIGHT_RIGHT;
94 | end;
95 | if wantedState ~= nil then
96 | if wantedState then
97 | state = Lights.TURNLIGHT_RIGHT;
98 | else
99 | state = Lights.TURNLIGHT_OFF;
100 | end;
101 | end;
102 | self:setTurnLightState(state);
103 |
104 | elseif lightControl.type == "turnLightHazard" then
105 | local state = Lights.TURNLIGHT_OFF;
106 | if spec.turnLightState ~= Lights.TURNLIGHT_HAZARD then
107 | state = Lights.TURNLIGHT_HAZARD;
108 | end;
109 | if wantedState ~= nil then
110 | if wantedState then
111 | state = Lights.TURNLIGHT_HAZARD;
112 | else
113 | state = Lights.TURNLIGHT_OFF;
114 | end;
115 | end;
116 | self:setTurnLightState(state);
117 |
118 | elseif lightControl.type == "beaconLights" then
119 | wantedState = Utils.getNoNil(wantedState, not spec.beaconLightsActive)
120 | self:setBeaconLightsVisibility(not spec.beaconLightsActive);
121 | end;
122 |
123 | end;
124 | end;
125 |
126 |
127 | function sic_lightControl:getBinaryFromDecimal(decimal)
128 | local quot = decimal;
129 | local binary = {};
130 | local i = 1;
131 | while quot ~= 0 do
132 | local remainder = math.fmod(quot, 2);
133 | quot = math.floor(quot / 2);
134 | binary[i] = remainder;
135 | i = i+1;
136 | end;
137 | return binary;
138 | end;
139 |
140 | function sic_lightControl.setLightsTypesMaskAppend(self, superFunc, lightsTypesMask, force, noEventSend)
141 | superFunc(self, lightsTypesMask, force, noEventSend);
142 | local spec = self.spec_lights;
143 |
144 | if self.spec_simpleIC ~= nil and self.spec_simpleIC.hasIC then
145 | for _, icFunction in pairs(self.spec_simpleIC.icFunctions) do
146 | if icFunction.lightControl ~= nil and icFunction.lightControl.leverAnimation ~= nil then
147 | local lightControl = icFunction.lightControl;
148 | local binary = self:getBinaryFromDecimal(lightsTypesMask);
149 |
150 | if lightControl.type == "state" and #lightControl.lightTypes ~= 0 then
151 | local isOn = false;
152 | for i=1, #lightControl.lightTypes do
153 | if binary[lightControl.lightTypes[i]+1] ~= nil and binary[lightControl.lightTypes[i]+1] ~= 0 then
154 | --print("lightTypes("..i.."): "..tostring(lightControl.lightTypes[i]))
155 | --print("binary Index: "..tostring(binary[lightControl.lightTypes[i]]+1))
156 | isOn = true;
157 | end;
158 | end;
159 | if isOn then
160 | self:playAnimation(lightControl.leverAnimation.animationName, 1, self:getAnimationTime(lightControl.leverAnimation.animationName), true);
161 | else
162 | self:playAnimation(lightControl.leverAnimation.animationName, -1, self:getAnimationTime(lightControl.leverAnimation.animationName), true);
163 | end;
164 | end;
165 |
166 | if lightControl.type == "toggle" then
167 | if #binary > 0 then
168 |
169 | local wantedStopTime = 0;
170 |
171 | for i = 1, spec.numLightTypes do
172 | if binary[i] ~= nil and binary[i] ~= 0 then
173 | if lightControl.leverAnimation.animStops[i] ~= nil then
174 | wantedStopTime = lightControl.leverAnimation.animStops[i];
175 | end;
176 | end;
177 | end;
178 |
179 | if wantedStopTime ~= 0 then
180 | local animTime = self:getAnimationTime(lightControl.leverAnimation.animationName)
181 | if animTime > wantedStopTime then
182 | self:playAnimation(lightControl.leverAnimation.animationName, -1, animTime, true);
183 | self:setAnimationStopTime(lightControl.leverAnimation.animationName, wantedStopTime);
184 | elseif animTime < wantedStopTime then
185 | self:playAnimation(lightControl.leverAnimation.animationName, 1, animTime, true);
186 | self:setAnimationStopTime(lightControl.leverAnimation.animationName, wantedStopTime);
187 | end;
188 | end;
189 | else
190 | self:playAnimation(lightControl.leverAnimation.animationName, -1, self:getAnimationTime(lightControl.leverAnimation.animationName), true);
191 | end;
192 | end;
193 | end;
194 | end;
195 | end;
196 |
197 | end;
198 | Lights.setLightsTypesMask = Utils.overwrittenFunction(Lights.setLightsTypesMask, sic_lightControl.setLightsTypesMaskAppend);
199 |
200 |
201 | -- beaconlights animation
202 | function sic_lightControl.setBeaconLightsVisibilityAppend(self, superFunc, visibility, force, noEventSend)
203 | superFunc(self, visibility, force, noEventSend);
204 |
205 | if self.spec_simpleIC ~= nil and self.spec_simpleIC.hasIC then
206 | for _, icFunction in pairs(self.spec_simpleIC.icFunctions) do
207 | if icFunction.lightControl ~= nil and icFunction.lightControl.leverAnimation ~= nil then
208 | if icFunction.lightControl.type == "beaconLights" then
209 | if visibility then
210 | self:playAnimation(lightControl.leverAnimation.animationName, 1, self:getAnimationTime(lightControl.leverAnimation.animationName), true);
211 | else
212 | self:playAnimation(lightControl.leverAnimation.animationName, -1, self:getAnimationTime(lightControl.leverAnimation.animationName), true);
213 | end;
214 | end;
215 | end;
216 | end;
217 | end;
218 | end;
219 | Lights.setBeaconLightsVisibility = Utils.overwrittenFunction(Lights.setBeaconLightsVisibility, sic_lightControl.setBeaconLightsVisibilityAppend);
220 |
221 |
222 | -- Turnlight Animations
223 | function sic_lightControl.setTurnLightStateAppend(self, superFunc, state, force, noEventSend)
224 | superFunc(self, state, foce, noEventSend);
225 |
226 | if self.spec_simpleIC ~= nil and self.spec_simpleIC.hasIC then
227 | for _, icFunction in pairs(self.spec_simpleIC.icFunctions) do
228 | if icFunction.lightControl ~= nil and icFunction.lightControl.leverAnimation ~= nil then
229 | local lightControl = icFunction.lightControl;
230 |
231 | local isSharedAnim = lightControl.leverAnimation.isTurnlightSharedAnimation;
232 |
233 | -- animation is shared for left and right turnlight
234 | if isSharedAnim then
235 | if lightControl.type == "turnLightLeft" then
236 | if state == Lights.TURNLIGHT_LEFT then
237 | self:playAnimation(lightControl.leverAnimation.animationName, 1, self:getAnimationTime(lightControl.leverAnimation.animationName), true);
238 | elseif state == Lights.TURNLIGHT_OFF then
239 | local animTime = self:getAnimationTime(lightControl.leverAnimation.animationName);
240 | if animTime > 0.5 then
241 | self:playAnimation(lightControl.leverAnimation.animationName, -1, animTime, true);
242 | self:setAnimationStopTime(lightControl.leverAnimation.animationName, 0.5);
243 | end;
244 | end;
245 | end;
246 | if lightControl.type == "turnLightRight" then
247 | if state == Lights.TURNLIGHT_RIGHT then
248 | self:playAnimation(lightControl.leverAnimation.animationName, -1, self:getAnimationTime(lightControl.leverAnimation.animationName), true);
249 | elseif state == Lights.TURNLIGHT_OFF then
250 | local animTime = self:getAnimationTime(lightControl.leverAnimation.animationName);
251 | if animTime < 0.5 then
252 | self:playAnimation(lightControl.leverAnimation.animationName, 1, animTime, true);
253 | self:setAnimationStopTime(lightControl.leverAnimation.animationName, 0.5);
254 | end;
255 | end;
256 | end;
257 | else -- if animation isn't shared animate normally and independently
258 | if lightControl.type == "turnLightLeft" then
259 | if state == Lights.TURNLIGHT_LEFT then
260 | self:playAnimation(lightControl.leverAnimation.animationName, 1, self:getAnimationTime(lightControl.leverAnimation.animationName), true);
261 | elseif state == Lights.TURNLIGHT_OFF then
262 | self:playAnimation(lightControl.leverAnimation.animationName, -1, self:getAnimationTime(lightControl.leverAnimation.animationName), true);
263 | end;
264 | end;
265 | if lightControl.type == "turnLightRight" then
266 | if state == Lights.TURNLIGHT_RIGHT then
267 | self:playAnimation(lightControl.leverAnimation.animationName, 1, self:getAnimationTime(lightControl.leverAnimation.animationName), true);
268 | elseif state == Lights.TURNLIGHT_OFF then
269 | self:playAnimation(lightControl.leverAnimation.animationName, -1, self:getAnimationTime(lightControl.leverAnimation.animationName), true);
270 | end;
271 | end;
272 | end;
273 |
274 | -- hazards animation is independent
275 | if lightControl.type == "turnLightHazard" then
276 | if state == Lights.TURNLIGHT_HAZARD then
277 | self:playAnimation(lightControl.leverAnimation.animationName, 1, self:getAnimationTime(lightControl.leverAnimation.animationName), true);
278 | elseif state == Lights.TURNLIGHT_OFF then
279 | self:playAnimation(lightControl.leverAnimation.animationName, -1, self:getAnimationTime(lightControl.leverAnimation.animationName), true);
280 | end;
281 | end;
282 | end;
283 | end;
284 | end;
285 |
286 | end;
287 | Lights.setTurnLightState = Utils.overwrittenFunction(Lights.setTurnLightState, sic_lightControl.setTurnLightStateAppend);
--------------------------------------------------------------------------------
/FS19_simpleIC/simpleIC.lua:
--------------------------------------------------------------------------------
1 | -- by modelleicher
2 | -- 13.04.2019
3 |
4 | -- Script for Interactive Control. Released on Github January 2020.
5 |
6 |
7 | simpleIC = {};
8 |
9 | function simpleIC.prerequisitesPresent(specializations)
10 | return true;
11 | end;
12 |
13 |
14 |
15 | function simpleIC.registerEventListeners(vehicleType)
16 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", simpleIC);
17 | SpecializationUtil.registerEventListener(vehicleType, "onDraw", simpleIC);
18 | SpecializationUtil.registerEventListener(vehicleType, "onUpdate", simpleIC);
19 | SpecializationUtil.registerEventListener(vehicleType, "onEnterVehicle", simpleIC);
20 | SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", simpleIC);
21 | SpecializationUtil.registerEventListener(vehicleType, "onLeaveVehicle", simpleIC);
22 | SpecializationUtil.registerEventListener(vehicleType, "onDelete", simpleIC);
23 | SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", simpleIC);
24 | SpecializationUtil.registerEventListener(vehicleType, "saveToXMLFile", simpleIC);
25 | SpecializationUtil.registerEventListener(vehicleType, "onReadStream", simpleIC);
26 | SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", simpleIC);
27 | end;
28 |
29 |
30 | function simpleIC.onRegisterActionEvents(self, isActiveForInput)
31 | local spec = self.spec_simpleIC;
32 | spec.actionEvents = {};
33 | self:clearActionEventsTable(spec.actionEvents);
34 |
35 | if self:getIsActive() and self.spec_simpleIC.hasIC then
36 | self:addActionEvent(spec.actionEvents, InputAction.TOGGLE_ONOFF, self, simpleIC.TOGGLE_ONOFF, true, true, false, true, nil);
37 | if spec.icTurnedOn_inside then
38 | local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.INTERACT_IC_VEHICLE, self, simpleIC.INTERACT, true, true, false, true, nil);
39 | g_inputBinding:setActionEventTextVisibility(actionEventId, false);
40 | spec.interactionButtonActive = true;
41 | end;
42 | end;
43 | end;
44 |
45 | function simpleIC:onLoad(savegame)
46 | self.setICAnimation = simpleIC.setICAnimation;
47 | self.outsideInteractionTriggerCallback = simpleIC.outsideInteractionTriggerCallback;
48 | self.updateSoundAttributes = simpleIC.updateSoundAttributes;
49 | self.addSoundChangeIndex = simpleIC.addSoundChangeIndex;
50 | self.renderTextAtProjectedPosition = simpleIC.renderTextAtProjectedPosition;
51 | self.checkInteraction = simpleIC.checkInteraction;
52 | self.updateActionEventsSIC = simpleIC.updateActionEventsSIC;
53 | self.setICState = simpleIC.setICState;
54 | self.resetCanBeTriggered = simpleIC.resetCanBeTriggered;
55 | self.doInteraction = simpleIC.doInteraction;
56 | self.isCameraInsideCheck = simpleIC.isCameraInsideCheck;
57 | self.loadICAnimation = simpleIC.loadAnimation;
58 | self.loadICFunctions = simpleIC.loadICFunctions;
59 |
60 |
61 | self.spec_simpleIC = {};
62 |
63 | local spec = self.spec_simpleIC;
64 |
65 | -- for now all we have is animations, no other types of functions
66 | spec.icFunctions = {};
67 |
68 | -- load the animations from XML
69 | self:loadICFunctions("vehicle.simpleIC.animation", self.loadICAnimation);
70 |
71 | -- load attacherControl
72 | self:loadICFunctions("vehicle.simpleIC.attacherControl", self.loadAttacherControl);
73 |
74 | -- load pto control
75 | self:loadICFunctions("vehicle.simpleIC.ptoControl", self.loadPTOControl);
76 |
77 | -- load light control
78 | self:loadICFunctions("vehicle.simpleIC.lightControl", self.loadLightControl);
79 |
80 | -- load motor start control
81 | self:loadICFunctions("vehicle.simpleIC.motorStartControl", self.loadMotorStartControl);
82 |
83 | -- load implement control
84 | self:loadICFunctions("vehicle.simpleIC.implementControl", self.loadImplementControl);
85 |
86 | -- load drivable control
87 | self:loadICFunctions("vehicle.simpleIC.drivableControl", self.loadDrivableControl);
88 |
89 | if #spec.icFunctions > 0 then
90 | spec.hasIC = true;
91 |
92 | spec.disableInvisibleTriggers = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.simpleIC#disableInvisibleTriggers"), false);
93 |
94 | spec.outsideInteractionTrigger = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.simpleIC#outsideInteractionTrigger"), self.i3dMappings);
95 |
96 | spec.playerInOutsideInteractionTrigger = false;
97 |
98 | spec.interactionMarker = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.simpleIC#interactionMarker"), self.i3dMappings)
99 |
100 | if spec.outsideInteractionTrigger ~= nil then
101 | spec.outsideInteractionTriggerId = addTrigger(spec.outsideInteractionTrigger, "outsideInteractionTriggerCallback", self);
102 | end;
103 |
104 | spec.soundVolumeIncreasePercentageAll = 1;
105 | spec.soundChangeIndexList = {};
106 |
107 | spec.reachDistance = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.simpleIC#reachDistance"), 1.8)
108 |
109 |
110 | --
111 | spec.icTurnedOn_inside = false;
112 | spec.icTurnedOn_outside = false;
113 |
114 | spec.icTurnedOn_inside_backup = false;
115 |
116 | spec.interact_present = false;
117 | spec.interact_default = false;
118 |
119 | if self.spec_motorized ~= nil then -- back up samples if we are a motorized vehicle
120 | for i, sample in pairs(self.spec_motorized.samples) do
121 | sample.indoorAttributes.volumeBackup = sample.indoorAttributes.volume;
122 | end;
123 | for i, sample in pairs(self.spec_motorized.motorSamples) do
124 | sample.indoorAttributes.volumeBackup = sample.indoorAttributes.volume;
125 | end;
126 | end;
127 | end;
128 |
129 | spec.cylinderAnimations = {};
130 | local c = 0;
131 | while true do
132 | local node1 = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.simpleIC.cylinderAnimations.cylinder("..c..")#node1"), self.i3dMappings)
133 | local node2 = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.simpleIC.cylinderAnimations.cylinder("..c..")#node2"), self.i3dMappings)
134 | if node1 ~= nil and node2 ~= nil then
135 | spec.cylinderAnimations[c+1] = {node1 = node1, node2 = node2}
136 | else
137 | break;
138 | end;
139 |
140 | c = c + 1;
141 | end;
142 | end;
143 |
144 | function simpleIC:loadICFunctions(keyOrig, loadFunc)
145 | local spec = self.spec_simpleIC;
146 | local i = 0;
147 | while true do
148 | local icFunction = {};
149 | local hasFunction = false;
150 | local key = keyOrig.."("..i..")"
151 |
152 | hasFunction = loadFunc(self, key, icFunction);
153 |
154 | if hasFunction then
155 | icFunction.currentState = false;
156 |
157 | icFunction.inTP = {};
158 | icFunction.inTP.triggerPoint = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key..".insideTrigger#triggerPoint"), self.i3dMappings);
159 | icFunction.inTP.triggerPointRadius = Utils.getNoNil(getXMLFloat(self.xmlFile, key..".insideTrigger#triggerPointSize"), 0.04);
160 | icFunction.inTP.triggerDistance = Utils.getNoNil(getXMLFloat(self.xmlFile, key..".insideTrigger#triggerDistance"), 1);
161 |
162 | if icFunction.inTP.triggerPoint == nil then
163 | icFunction.inTP.triggerPoint_ON = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key..".insideTrigger#triggerPoint_ON"), self.i3dMappings);
164 | icFunction.inTP.triggerPoint_OFF = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key..".insideTrigger#triggerPoint_OFF"), self.i3dMappings);
165 | end;
166 |
167 |
168 | icFunction.outTP = {};
169 | icFunction.outTP.triggerPoint = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key..".outsideTrigger#triggerPoint"), self.i3dMappings);
170 | icFunction.outTP.triggerPointRadius = Utils.getNoNil(getXMLFloat(self.xmlFile, key..".outsideTrigger#triggerPointSize"), 0.04);
171 | icFunction.outTP.triggerDistance = Utils.getNoNil(getXMLFloat(self.xmlFile, key..".outsideTrigger#triggerDistance"), 1);
172 |
173 | if icFunction.outTP.triggerPoint == nil then
174 | icFunction.outTP.triggerPoint_ON = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key..".outsideTrigger#triggerPoint_ON"), self.i3dMappings);
175 | icFunction.outTP.triggerPoint_OFF = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key..".outsideTrigger#triggerPoint_OFF"), self.i3dMappings);
176 | end;
177 |
178 | table.insert(spec.icFunctions, icFunction);
179 | else
180 | break;
181 | end;
182 | i = i+1;
183 | end;
184 |
185 | end;
186 |
187 |
188 |
189 |
190 |
191 | function simpleIC:loadAnimation(key, table)
192 |
193 | local anim = {};
194 | anim.animationName = getXMLString(self.xmlFile, key.."#animationName");
195 | if anim.animationName ~= "" and anim.animationName ~= nil then
196 |
197 | anim.animationSpeed = Utils.getNoNil(getXMLFloat(self.xmlFile, key.."#animationSpeed"), 1);
198 | anim.sharedAnimation = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#sharedAnimation"), false);
199 | anim.currentState = false;
200 |
201 | if not anim.sharedAnimation then
202 | self:playAnimation(anim.animationName, -anim.animationSpeed, self:getAnimationTime(anim.animationName), true);
203 | end;
204 |
205 | anim.duration = self:getAnimationDuration(anim.animationName);
206 | anim.soundVolumeIncreasePercentage = Utils.getNoNil(getXMLFloat(self.xmlFile, key.."#soundVolumeIncreasePercentage"), false);
207 |
208 | table.animation = anim;
209 | return true;
210 | end;
211 |
212 | return false;
213 | end;
214 |
215 | function simpleIC:onEnterVehicle(isControlling, playerStyle, farmId)
216 | local spec = self.spec_simpleIC;
217 | if self.spec_enterable ~= nil and spec.hasIC then
218 |
219 | local inside = self:isCameraInsideCheck();
220 | if inside then
221 | self:setICState(spec.icTurnedOn_inside, false);
222 | end;
223 | spec.lastCameraInside = Utils.getNoNil(inside, false);
224 | end;
225 | end;
226 |
227 | -- indoor camera -> IC is always on by default
228 | -- outdoor camera -> IC is on when button is pressed
229 | -- inside IC can be turned off
230 | -- marker turn of "globally"
231 |
232 | function simpleIC:onPostLoad(savegame)
233 | if self.spec_simpleIC ~= nil and savegame ~= nil and self.spec_simpleIC.hasIC then
234 | local spec = self.spec_simpleIC;
235 | local xmlFile = savegame.xmlFile;
236 |
237 | local i = 1;
238 | local key1 = savegame.key..".FS19_simpleIC.simpleIC.icFunctions"
239 | for _, icFunction in pairs(spec.icFunctions) do
240 |
241 | -- load animation state
242 | if icFunction.animation ~= nil then
243 | local state = getXMLBool(xmlFile, key1..".icFunction"..i.."#animationState");
244 | if state ~= nil then
245 | self:setICAnimation(state, i, true)
246 | end;
247 | end;
248 |
249 | i = i+1;
250 | end;
251 | end;
252 | end;
253 |
254 | function simpleIC:saveToXMLFile(xmlFile, key)
255 | if self.spec_simpleIC ~= nil and self.spec_simpleIC.hasIC then
256 | local spec = self.spec_simpleIC;
257 |
258 | local i = 1;
259 | local key1 = key..".icFunctions";
260 | for _, icFunction in pairs(spec.icFunctions) do
261 | -- save animations state
262 | if icFunction.animation ~= nil then
263 | setXMLBool(xmlFile, key1..".icFunction"..i.."#animationState", icFunction.animation.currentState);
264 | end;
265 | i = i+1;
266 | end;
267 |
268 | end;
269 | end;
270 |
271 | function simpleIC:onReadStream(streamId, connection)
272 | local spec = self.simpleIC
273 | if spec ~= nil and spec.hasIC then
274 | if connection:getIsServer() then
275 | for _, icFunction in pairs(self.spec_simpleIC.icFunctions) do
276 | if icFunction.animation ~= nil then
277 | local state = streamReadBool(streamId)
278 | icFunction.animation.currentState = state;
279 | end;
280 | end;
281 | end;
282 | end;
283 | end
284 |
285 | function simpleIC:onWriteStream(streamId, connection)
286 | local spec = self.simpleIC;
287 | if spec ~= nil and spec.hasIC then
288 | if not connection:getIsServer() then
289 | for _, icFunction in pairs(self.spec_simpleIC.icFunctions) do
290 | if icFunction.animation ~= nil then
291 | streamWriteBool(streamId, icFunction.animation.currentState)
292 | end;
293 | end;
294 | end;
295 | end;
296 | end
297 |
298 | function simpleIC:onDelete()
299 | local spec = self.spec_simpleIC;
300 | if spec.outsideInteractionTrigger ~= nil then
301 | removeTrigger(spec.outsideInteractionTrigger)
302 | end;
303 | end;
304 |
305 | function simpleIC:INTERACT(actionName, inputValue)
306 | if inputValue > 0.5 then
307 | self.spec_simpleIC.interact_default = true;
308 | if not self.spec_simpleIC.interact_present then
309 | self:doInteraction()
310 | end;
311 | else
312 | self.spec_simpleIC.interact_default = false;
313 | end;
314 | end;
315 |
316 |
317 |
318 | function simpleIC:doInteraction()
319 | local spec = self.spec_simpleIC;
320 |
321 | if spec ~= nil and spec.hasIC then
322 | if spec.icTurnedOn_inside or spec.icTurnedOn_outside or spec.playerInOutsideInteractionTrigger then
323 | local i = 1;
324 | for _, icFunction in pairs(self.spec_simpleIC.icFunctions) do
325 | if icFunction.canBeTriggered then
326 | -- trigger animation
327 | if icFunction.animation ~= nil then
328 | self:setICAnimation(not icFunction.animation.currentState, i);
329 | end;
330 |
331 | if icFunction.attacherControl ~= nil then
332 | self:setAttacherControl(nil, i)
333 | end;
334 |
335 | if icFunction.ptoControl ~= nil then
336 | self:setPTOControl(nil, i)
337 | end;
338 |
339 | if icFunction.lightControl ~= nil then
340 | self:setLightControl(nil, i)
341 | end;
342 |
343 | if icFunction.motorStartControl ~= nil then
344 | self:setMotorStartControl(nil, i)
345 | end;
346 |
347 | if icFunction.implementControl ~= nil then
348 | self:setImplementControl(nil, i)
349 | end;
350 | if icFunction.drivableControl ~= nil then
351 | self:setDrivableControl(nil, i)
352 | end;
353 | end;
354 | if icFunction.canBeTriggered_ON then
355 | if icFunction.animation ~= nil then
356 | self:setICAnimation(true, i);
357 | end;
358 | if icFunction.attacherControl ~= nil then
359 | self:setAttacherControl(true, i)
360 | end;
361 | if icFunction.ptoControl ~= nil then
362 | self:setPTOControl(true, i)
363 | end;
364 | if icFunction.lightControl ~= nil then
365 | self:setLightControl(true, i)
366 | end;
367 | if icFunction.motorStartControl ~= nil then
368 | self:setMotorStartControl(true, i)
369 | end;
370 | if icFunction.implementControl ~= nil then
371 | self:setImplementControl(true, i)
372 | end;
373 | if icFunction.drivableControl ~= nil then
374 | self:setDrivableControl(true, i)
375 | end;
376 | end;
377 | if icFunction.canBeTriggered_OFF then
378 | if icFunction.animation ~= nil then
379 | self:setICAnimation(false, i);
380 | end;
381 | if icFunction.attacherControl ~= nil then
382 | self:setAttacherControl(false, i)
383 | end;
384 | if icFunction.ptoControl ~= nil then
385 | self:setPTOControl(false, i)
386 | end;
387 | if icFunction.lightControl ~= nil then
388 | self:setLightControl(false, i)
389 | end;
390 | if icFunction.motorStartControl ~= nil then
391 | self:setMotorStartControl(false, i)
392 | end;
393 | if icFunction.implementControl ~= nil then
394 | self:setImplementControl(false, i)
395 | end;
396 | if icFunction.drivableControl ~= nil then
397 | self:setDrivableControl(false, i)
398 | end;
399 | end;
400 | i = i+1;
401 | end;
402 | end;
403 | end;
404 |
405 | -- implement balls
406 | if self.spec_implementBalls ~= nil then
407 | local spec1 = self.spec_implementBalls;
408 | for index, implementJoint in pairs(spec1.implementJoints) do
409 | if implementJoint.canBeClicked then
410 | self:setImplementBalls(index)
411 | end;
412 | end;
413 | end;
414 | end
415 |
416 | -- returns true if camera is inside, returns false if camera is not inside, returns nil if active camera is nil
417 | function simpleIC:isCameraInsideCheck()
418 | if self.spec_enterable ~= nil and self.getActiveCamera ~= nil then
419 | local activeCamera = self:getActiveCamera();
420 | if activeCamera ~= nil then
421 | return activeCamera.isInside;
422 | end;
423 | end;
424 | return nil;
425 | end;
426 |
427 | function simpleIC:TOGGLE_ONOFF(actionName, inputValue)
428 | local spec = self.spec_simpleIC;
429 | if spec ~= nil and spec.hasIC and self.getAttacherVehicle == nil then
430 | if not self:isCameraInsideCheck() then
431 | if inputValue == 1 then
432 | self:setICState(true, true);
433 | else
434 | self:setICState(false, true);
435 | end;
436 | else
437 | if inputValue == 1 then
438 | self:setICState(not spec.icTurnedOn_inside, false);
439 | end;
440 | end;
441 | end;
442 | end;
443 |
444 |
445 | function simpleIC:setICState(wantedState, wantedOutside)
446 | local spec = self.spec_simpleIC;
447 |
448 | if wantedState ~= nil and wantedOutside ~= nil then
449 | if wantedOutside then
450 | spec.icTurnedOn_inside = false;
451 | spec.icTurnedOn_outside = wantedState;
452 | g_inputBinding:setShowMouseCursor(wantedState)
453 | self.spec_enterable.cameras[self.spec_enterable.camIndex].isActivated = not wantedState;
454 | else
455 | spec.icTurnedOn_outside = false;
456 | spec.icTurnedOn_inside = wantedState;
457 | g_inputBinding:setShowMouseCursor(false)
458 | self.spec_enterable.cameras[self.spec_enterable.camIndex].isActivated = true;
459 | end;
460 |
461 | if wantedState then
462 | if not spec.interactionButtonActive then
463 | local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.INTERACT_IC_VEHICLE, self, simpleIC.INTERACT, true, false, false, true, nil);
464 | g_inputBinding:setActionEventTextVisibility(actionEventId, false);
465 | spec.interactionButtonActive = true;
466 | end;
467 | else
468 | if spec.interactionButtonActive then
469 | self:removeActionEvent(spec.actionEvents, InputAction.INTERACT_IC_VEHICLE);
470 | spec.interactionButtonActive = false;
471 | end;
472 | end;
473 | end;
474 |
475 | end;
476 |
477 | function simpleIC:onUpdate(dt)
478 |
479 | if self.spec_simpleIC ~= nil and self.spec_simpleIC.hasIC then
480 |
481 | local spec = self.spec_simpleIC;
482 | if self.spec_simpleIC.playerInOutsideInteractionTrigger then
483 | self:checkInteraction()
484 | self:raiseActive() -- keep vehicle awake as long as player is in trigger
485 | end;
486 |
487 | -- we need to track camera changes from inside to outside and adjust IC accordingly
488 | if self:getIsActiveForInput(true) then
489 | -- if isInside is true and outside turned on or vice versa we changed camera
490 | local inside = self:isCameraInsideCheck()
491 | if inside ~= nil and inside ~= spec.lastCameraInside then
492 | -- if we toggled from inside to outside, store inside state in backup variable and turn off inside
493 | if not inside then
494 | spec.icTurnedOn_inside_backup = spec.icTurnedOn_inside;
495 | self:setICState(false, true);
496 | else -- if we toggled to inside restore backup value
497 | self:setICState(spec.icTurnedOn_inside_backup, false);
498 | end;
499 | spec.lastCameraInside = inside;
500 | self:resetCanBeTriggered();
501 | end;
502 | end;
503 |
504 | if #spec.cylinderAnimations > 0 then
505 | for i=1, #spec.cylinderAnimations do
506 | local node1 = spec.cylinderAnimations[i].node1;
507 | local node2 = spec.cylinderAnimations[i].node2;
508 |
509 | local ax, ay, az = getWorldTranslation(node1);
510 | local bx, by, bz = getWorldTranslation(node2);
511 | x, y, z = worldDirectionToLocal(getParent(node1), bx-ax, by-ay, bz-az);
512 |
513 | local ux, uy, uz = localDirectionToWorld(node1, 0,1,0)
514 | ux, uy, uz = worldDirectionToLocal(getParent(node1), ux, uy, uz)
515 |
516 | setDirection(node1, x, y, z, ux, uy, uz);
517 |
518 | local ax2, ay2, az2 = getWorldTranslation(node2);
519 | local bx2, by2, bz2 = getWorldTranslation(node1);
520 | x2, y2, z2 = worldDirectionToLocal(getParent(node2), bx2-ax2, by2-ay2, bz2-az2);
521 |
522 | local ux2, uy2, uz2 = localDirectionToWorld(node2, 0,1,0)
523 | ux2, uy2, uz2 = worldDirectionToLocal(getParent(node2), ux2, uy2, uz2)
524 |
525 | setDirection(node2, x2, y2, z2, ux2, uy2, uz2);
526 | end;
527 | end;
528 | end;
529 | end;
530 |
531 | function simpleIC:resetCanBeTriggered()
532 | for _, icFunction in pairs(self.spec_simpleIC.icFunctions) do -- reset all the IC-Functions so they can't be triggered
533 | icFunction.canBeTriggered = false;
534 | icFunction.canBeTriggered_ON = false;
535 | icFunction.canBeTriggered_OFF = false;
536 | end;
537 | end;
538 |
539 | function simpleIC:onLeaveVehicle()
540 | if self.spec_simpleIC ~= nil and self.spec_simpleIC.hasIC then
541 | self:resetCanBeTriggered();
542 | self.spec_simpleIC.interactionButtonActive = false;
543 | end;
544 | end;
545 |
546 | function simpleIC:setICAnimation(wantedState, animationIndex, noEventSend)
547 | setICAnimationEvent.sendEvent(self, wantedState, animationIndex, noEventSend);
548 | local animation = self.spec_simpleIC.icFunctions[animationIndex].animation;
549 | local spec = self.spec_simpleIC;
550 |
551 | if wantedState then -- if currentState is true (max) then play animation to min
552 | self:playAnimation(animation.animationName, animation.animationSpeed, self:getAnimationTime(animation.animationName), true);
553 | animation.currentState = true;
554 | self:addSoundChangeIndex(animationIndex);
555 | else
556 | self:playAnimation(animation.animationName, -animation.animationSpeed, self:getAnimationTime(animation.animationName), true);
557 | animation.currentState = false;
558 | self:addSoundChangeIndex(animationIndex);
559 | end;
560 |
561 | if self.spec_motorized ~= nil then
562 | spec.soundVolumeIncreasePercentageAll = math.max(1, spec.soundVolumeIncreasePercentageAll);
563 | end;
564 |
565 | end;
566 |
567 | -- goal
568 | -- sound volume needs to change dynamically while the animation is playing
569 | -- sound volume needs to change globally with multiple animations playing at the same time
570 |
571 | -- so when we activate an animation we add that animation index to a sound update index list
572 |
573 | function simpleIC:addSoundChangeIndex(index)
574 | if self.spec_motorized ~= nil then
575 | local animation = self.spec_simpleIC.icFunctions[index].animation;
576 | if animation.soundVolumeIncreasePercentage ~= false then -- check if this even has sound change effects
577 | -- now add it to the table
578 | self.spec_simpleIC.soundChangeIndexList[index] = animation; -- we add it at the index of the animation that way if we try adding the same animation twice it does overwrite itself
579 | end;
580 | end;
581 | end;
582 |
583 | -- next we want to run through that list, get the current animation status of that animation and update the sound volume value
584 | -- if the animation stopped playing, remove it from the list
585 |
586 | function simpleIC:updateSoundAttributes()
587 | local spec = self.spec_simpleIC;
588 | local soundVolumeIncreaseAll = 0;
589 | local updateSound = false;
590 | for _, animation in pairs(spec.soundChangeIndexList) do
591 | -- get time
592 | local animationTime = self:getAnimationTime(animation.animationName);
593 | -- get current sound volume increase
594 | local soundVolumeIncrease = animation.soundVolumeIncreasePercentage * (animationTime ^ 0.5);
595 | soundVolumeIncreaseAll = soundVolumeIncreaseAll + soundVolumeIncrease;
596 | if animationTime == 1 or animationTime == 0 then
597 | animation = nil; -- delete animation from index table if we reached max pos or min pos
598 | end;
599 | updateSound = true;
600 | end;
601 |
602 | if updateSound then
603 | for i, sample in pairs(self.spec_motorized.samples) do
604 | sample.indoorAttributes.volume = math.min(sample.indoorAttributes.volumeBackup * (1 + soundVolumeIncreaseAll), sample.outdoorAttributes.volume);
605 | end;
606 | for i, sample in pairs(self.spec_motorized.motorSamples) do
607 | sample.indoorAttributes.volume = math.min(sample.indoorAttributes.volumeBackup * (1 + soundVolumeIncreaseAll), sample.outdoorAttributes.volume);
608 | end;
609 | end;
610 | end;
611 |
612 | function simpleIC:outsideInteractionTriggerCallback(triggerId, otherId, onEnter, onLeave, onStay)
613 | local spec = self.spec_simpleIC;
614 |
615 | if onEnter and g_currentMission.controlPlayer and g_currentMission.player ~= nil and otherId == g_currentMission.player.rootNode then
616 | spec.playerInOutsideInteractionTrigger = true;
617 | self:raiseActive()
618 | spec.actionEvents = {}; -- create actionEvents table since in case we didn't enter the vehicle yet it does not exist
619 | self:clearActionEventsTable(spec.actionEvents); -- also clear it for good measure
620 | local _ , eventId = self:addActionEvent(spec.actionEvents, InputAction.INTERACT_IC_ONFOOT, self, simpleIC.INTERACT, false, true, false, true); -- now add the actionEvent
621 | elseif onLeave and g_currentMission.player ~= nil and otherId == g_currentMission.player.rootNode then
622 | spec.playerInOutsideInteractionTrigger = false;
623 | self:removeActionEvent(spec.actionEvents, InputAction.INTERACT_IC_ONFOOT); -- remove the actionEvent again once we leave the trigger
624 | end;
625 | end;
626 |
627 | function simpleIC:onDraw()
628 | self:checkInteraction()
629 | end;
630 |
631 | function simpleIC:checkInteraction()
632 | if self.spec_simpleIC ~= nil and self.spec_simpleIC.hasIC then
633 | local spec = self.spec_simpleIC;
634 |
635 | self:updateSoundAttributes();
636 |
637 | -- we need to check the positions of our triggerPoints if
638 | -- + somebody is in the outsideInteractionTrigger
639 | -- + the vehicle is active and simpleIC is active
640 | if (self:getIsActive() and spec.icTurnedOn_inside) or (self:getIsActive() and spec.icTurnedOn_outside) or spec.playerInOutsideInteractionTrigger then -- check the points
641 |
642 | -- see if we need to check the outside or the inside points
643 | -- see if we are inside the vehicle or not
644 | local isInside = false;
645 | local isPlayerTrigger = false;
646 | if spec.playerInOutsideInteractionTrigger then
647 | isPlayerTrigger = true;
648 | end;
649 |
650 | if not isPlayerTrigger then
651 | if self:getActiveCamera() ~= nil and self:getActiveCamera().isInside then
652 | isInside = true;
653 | end;
654 | end;
655 |
656 | if not spec.playerInOutsideInteractionTrigger and not spec.icTurnedOn_outside then -- don't render the crosshair if we are outside
657 | renderText(0.5, 0.5, 0.02, "+");
658 | end;
659 |
660 | -- go through all the functions
661 | local index = 0;
662 | for _, icFunction in pairs(spec.icFunctions) do
663 | index = index + 1;
664 | -- get inside or outside trigger points depending on if we're inside or outside
665 | local tp = icFunction.inTP;
666 | if not isInside then
667 | tp = icFunction.outTP;
668 | end;
669 |
670 |
671 |
672 | if tp.triggerPoint ~= nil or tp.triggerPoint_ON ~= nil or tp.triggerPoint_OFF ~= nil then
673 |
674 | local triggerPoint = {};
675 | triggerPoint[1] = tp.triggerPoint;
676 |
677 | if tp.triggerPoint_OFF ~= nil and tp.triggerPoint_ON ~= nil then -- multiple trigger points
678 | triggerPoint[2] = tp.triggerPoint_ON;
679 | triggerPoint[3] = tp.triggerPoint_OFF;
680 | end;
681 |
682 | -- set it to false by default
683 | icFunction.canBeTriggered = false;
684 | icFunction.canBeTriggered_ON = false;
685 | icFunction.canBeTriggered_OFF = false;
686 |
687 | for index , triggerPoint in pairs(triggerPoint) do
688 |
689 | -- get visibility of our trigger-point, if it is invisible its deactivated
690 | if not spec.disableInvisibleTriggers or (getVisibility(triggerPoint) and spec.disableInvisibleTriggers) then
691 |
692 | -- get world translation of our trigger point, then project it to the screen
693 | local wX, wY, wZ = getWorldTranslation(triggerPoint);
694 | local cameraNode = 0;
695 | if spec.playerInOutsideInteractionTrigger then
696 | cameraNode = g_currentMission.player.cameraNode
697 | else
698 | cameraNode = self:getActiveCamera().cameraNode
699 | end;
700 | local cX, cY, cZ = getWorldTranslation(cameraNode);
701 | local x, y, z = project(wX, wY, wZ);
702 |
703 | local dist = MathUtil.vector3Length(wX-cX, wY-cY, wZ-cZ);
704 |
705 |
706 | if x > 0 and y > 0 and z > 0 then
707 |
708 | -- the higher the number the smaller the text should be to keep it the same size in 3d space
709 | -- base size is 0.025
710 | -- if the number is higher than 1, make smaller
711 | -- if the number is smaller than 1, make bigger
712 |
713 | local size = 0.028 / dist;
714 |
715 | -- default posX and posY is 0.5 e.g. middle of the screen for selection
716 | local posX, posY, posZ = 0.5, 0.5, 0.5;
717 |
718 | -- if we have MOUSE_Mode enabled, use mouse position instead
719 | if spec.icTurnedOn_outside then
720 | posX, posY, posZ = g_lastMousePosX, g_lastMousePosY, 0;
721 | end;
722 |
723 |
724 | -- check if our position is within the position of the triggerRadius
725 | if posX < (x + tp.triggerPointRadius) and posX > (x - tp.triggerPointRadius) then
726 | if posY < (y + tp.triggerPointRadius) and posY > (y - tp.triggerPointRadius) then
727 | if dist < spec.reachDistance or spec.icTurnedOn_outside then
728 | -- can be clicked
729 | if index == 1 then -- toggle mark
730 | icFunction.canBeTriggered = true;
731 | elseif index == 2 then -- on mark
732 | icFunction.canBeTriggered_ON = true;
733 | elseif index == 3 then -- off mark
734 | icFunction.canBeTriggered_OFF = true;
735 | end;
736 | self:renderTextAtProjectedPosition(x,y,z, "X", size, 1, 0, 0)
737 | end;
738 | end;
739 | end;
740 | if (index == 1 and not icFunction.canBeTriggered) or (index == 2 and not icFunction.canBeTriggered_ON) or (index == 3 and not icFunction.canBeTriggered_OFF) then
741 | self:renderTextAtProjectedPosition(x,y,z, "X", size, 1, 1, 1)
742 | end;
743 | end;
744 | end;
745 | end;
746 | end;
747 | end;
748 | end;
749 | end;
750 |
751 | end;
752 |
753 | function simpleIC:renderTextAtProjectedPosition(projectX,projectY,projectZ, text, textSize, r, g, b)
754 | --local projectX,projectY,projectZ = project(x,y,z);
755 | if projectX > -1 and projectX < 2 and projectY > -1 and projectY < 2 and projectZ <= 1 then
756 | setTextAlignment(RenderText.ALIGN_CENTER);
757 | setTextBold(false);
758 | setTextColor(r, g, b, 1.0);
759 | renderText(projectX, projectY, textSize, text);
760 | setTextAlignment(RenderText.ALIGN_LEFT);
761 | end
762 | end
763 |
764 |
765 |
766 | setICAnimationEvent = {};
767 | setICAnimationEvent_mt = Class(setICAnimationEvent, Event);
768 | InitEventClass(setICAnimationEvent, "setICAnimationEvent");
769 |
770 | function setICAnimationEvent:emptyNew()
771 | local self = Event:new(setICAnimationEvent_mt );
772 | self.className="setICAnimationEvent";
773 | return self;
774 | end;
775 | function setICAnimationEvent:new(vehicle, wantedState, animationIndex)
776 | self.vehicle = vehicle;
777 | self.wantedState = wantedState;
778 | self.animationIndex = animationIndex;
779 | return self;
780 | end;
781 | function setICAnimationEvent:readStream(streamId, connection)
782 | self.vehicle = NetworkUtil.readNodeObject(streamId);
783 | self.wantedState = streamReadBool(streamId);
784 | self.animationIndex = streamReadUIntN(streamId, 6);
785 | self:run(connection);
786 | end;
787 | function setICAnimationEvent:writeStream(streamId, connection)
788 | NetworkUtil.writeNodeObject(streamId, self.vehicle);
789 | streamWriteBool(streamId, self.wantedState );
790 | streamWriteUIntN(streamId, self.animationIndex, 6);
791 | end;
792 | function setICAnimationEvent:run(connection)
793 | self.vehicle:setICAnimation(self.wantedState, self.animationIndex, true);
794 | if not connection:getIsServer() then
795 | g_server:broadcastEvent(setICAnimationEvent:new(self.vehicle, self.wantedState, self.animationIndex), nil, connection, self.object);
796 | end;
797 | end;
798 | function setICAnimationEvent.sendEvent(vehicle, wantedState, animationIndex, noEventSend)
799 | if noEventSend == nil or noEventSend == false then
800 | if g_server ~= nil then
801 | g_server:broadcastEvent(setICAnimationEvent:new(vehicle, wantedState, animationIndex), nil, nil, vehicle);
802 | else
803 | g_client:getServerConnection():sendEvent(setICAnimationEvent:new(vehicle, wantedState, animationIndex));
804 | end;
805 | end;
806 | end;
807 |
808 |
809 |
810 |
811 |
812 |
813 |
814 |
815 |
816 |
817 |
818 |
819 |
820 |
--------------------------------------------------------------------------------