├── ContractorMod.xml
├── FS22_ContractorMod.debug.xml
├── FS22_ContractorMod.zip
├── README.md
├── images
└── icon_ContractorMod.dds
├── modDesc.xml
├── modDesc_l10n_br.xml
├── modDesc_l10n_de.xml
├── modDesc_l10n_en.xml
├── modDesc_l10n_es.xml
├── modDesc_l10n_fr.xml
├── modDesc_l10n_pl.xml
├── passenger.i3d
├── passengerseats.xml
└── scripts
├── ContractorMod.lua
└── ContractorModWorker.lua
/ContractorMod.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/FS22_ContractorMod.debug.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/FS22_ContractorMod.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yumi-modding/FS22_ContractorMod/580e800eda7926cd7c453a40e7d4c15f1b944c2b/FS22_ContractorMod.zip
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FS22_ContractorMod
2 | ContractorMod for Farming Simulator 22
3 |
4 | This is a very first beta version with basic features of the mod already existing on previous FS version and few regressions described below.
5 |
6 | Working as of May 19th:
7 | - [x] Initialize new game with 4 characters near the map spawning location
8 | - [x] Save characters location/vehicle when saving game
9 | - [x] Load characters location/vehicle when loading game
10 | - [x] Switch between characters instead of between vehicles
11 | - [x] Enter some vehicles (basegame/mods) with several characters (4 + 1 vehicles configured)
12 | - [x] Hire/dismis worker for field/road task
13 | - [x] Leaving hired vehicle (with driver character) dismiss the job
14 | - [x] Compatibility with FollowMe mod
15 | - [x] Customizing/selling vehicle and returning hired vehicle with character inside
16 | - [x] Customizing character styles by editing ContractorMod.xml file in modSettings or savegame dir
17 | - [x] Change character name by using wardrobe screen
18 | - [x] First character should have selected player style when starting a new game instead of default style
19 | - [x] Using wardrobe to change each character style
20 |
21 | Partially working:
22 | - [x] Characters style can quickly mix up
23 | - [x] Several characters can get the same style after performing several enter/switch vehicle scenarios
24 |
25 | Not working/known issues:
26 | - [x] Changing character style by using wardrobe not only change current character but can also impact others
27 | - [x] Display characters not in a vehicle disabled for now (can crash the game quickly)
28 | - [ ] On foot characters can be shaking
29 | - [x] On foot characters not touching the ground
30 | - [ ] Display characters on map not implemented
31 | - [ ] Configure all basegame vehicles (+ some mods) to accept passengers
32 | - [ ] Compatibility with Courseplay mod not tested yet
33 | - [ ] Construction mode not tested yet
34 | - [ ] Train/horse not tested yet
35 | - [x] Display other characters names like in MP game
36 | - [ ] Debug command to ease passenger positioning in vehicles
37 |
38 |
39 | You can open issues based on your tests but please be the more precise possible so I can reproduce and understand it. You can inform if you find things working correctly that I did not tested yet.
40 | Thanks for your support and help
41 |
--------------------------------------------------------------------------------
/images/icon_ContractorMod.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yumi-modding/FS22_ContractorMod/580e800eda7926cd7c453a40e7d4c15f1b944c2b/images/icon_ContractorMod.dds
--------------------------------------------------------------------------------
/modDesc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | yumi
4 | 0.0.0.4
5 | yumi, mrbear, jujuokl, alpha117,FomaDNS
6 |
7 | ContractorMod
8 |
9 |
10 |
31 |
52 |
73 |
94 |
95 | images/icon_ContractorMod.dds
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/modDesc_l10n_br.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/modDesc_l10n_de.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/modDesc_l10n_en.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/modDesc_l10n_es.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/modDesc_l10n_fr.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/modDesc_l10n_pl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/passenger.i3d:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/passengerseats.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/scripts/ContractorMod.lua:
--------------------------------------------------------------------------------
1 | --
2 | -- ContractorMod
3 | -- Specialization for managing several characters when playing solo game
4 | -- Update attached to update event of the map
5 | --
6 | -- @author yumi
7 | -- free for noncommercial-usage
8 | --
9 |
10 | -- TODO:
11 | -- Add selector panel for number of workers (from 2 to 8). Might be reused in game
12 |
13 | source(Utils.getFilename("scripts/ContractorModWorker.lua", g_currentModDirectory))
14 |
15 | ContractorMod = {};
16 | ContractorMod.myCurrentModDirectory = g_currentModDirectory;
17 |
18 | ContractorMod.debug = false --true --
19 | ContractorMod.useDebugCommands = false
20 | -- TODO:
21 | -- Passenger: Try to add cameras
22 | -- Try to have workers on different farms (farmId)
23 |
24 | -- TO FIX:
25 | -- Wrong rotation of on Foot Characters
26 |
27 | function ContractorMod:loadedMission() --[[----------------------------------------------------------------]] print("This is a development version of ContractorMod for FS22, which may and will contain errors, bugs.") end
28 | Mission00.loadMission00Finished = Utils.appendedFunction(Mission00.loadMission00Finished, ContractorMod.loadedMission)
29 |
30 | function ContractorMod:startMission()
31 | if ContractorMod.debug then print("ContractorMod:startMission") end
32 |
33 | if ContractorMod.workers == nil then -- and g_currentMission.player.controllerIndex > 0 and g_currentMission.player.time > 1000 then
34 | -- DebugUtil.printTableRecursively(g_currentMission.player, " ", 1, 3)
35 | -- default values
36 | ContractorMod:init()
37 | -- DebugUtil.printTableRecursively(ContractorMod.workers, " ", 1, 3)
38 | for i = 2, ContractorMod.numWorkers do
39 | local worker = ContractorMod.workers[i]
40 | print(worker.name)
41 | if worker.currentVehicle == nil then
42 | -- OK but rotation
43 | if ContractorMod.debug then print("ContractorMod: setTranslation"); end
44 | setTranslation(worker.player.rootNode, worker.x, worker.y, worker.z);
45 | -- worker.player:moveRootNodeToAbsolute(worker.x, worker.y, worker.z)
46 | -- -- worker.player.moveTo(worker.x, worker.y, worker.z, true, true)
47 | -- ContractorMod:setRotation(worker.player)--.rootNode, worker.rotX, worker.rotY)
48 | local spawnPoint = g_farmManager:getSpawnPoint(worker.player.farmId)
49 | local dx, _, dz = localDirectionToWorld(spawnPoint, 0, 0, -1)
50 | local ry = MathUtil.getYRotationFromDirection(dx, dz)
51 | print("ry: "..tostring(ry))
52 | -- ry = ry + math.rad(180.0)
53 | -- print("ry: "..tostring(ry))
54 | worker.player:setRotation(0, ry)
55 | worker.player:setVisibility(true)
56 | else
57 | -- KO
58 | if ContractorMod.debug then print("ContractorMod: setVisibility false"); end
59 | worker.player.isEntered = false
60 | worker.player.isControlled = true
61 | worker.player:setVisibility(false)
62 | worker.player:moveToAbsoluteInternal(0, -200, 0); -- isFalling if 2000, visible if -200
63 | end
64 | end
65 | local firstWorker = ContractorMod.workers[ContractorMod.currentID]
66 | if g_currentMission.player and g_currentMission.player ~= nil then
67 | if ContractorMod.debug then print("ContractorMod: setVisibility false"); end
68 | firstWorker.player.isEntered = false
69 | firstWorker.player.isControlled = true
70 | firstWorker.player:setVisibility(false)
71 | firstWorker.player:moveToAbsoluteInternal(0, -200, 0);
72 | -- g_currentMission.player:getStyle():copyFrom(ContractorMod.workers[ContractorMod.currentID].playerStyle)
73 | if ContractorMod.debug then print("ContractorMod: moveToAbsolute"); end
74 | setTranslation(g_currentMission.player.rootNode, firstWorker.x, firstWorker.y, firstWorker.z);
75 | g_currentMission.player:moveRootNodeToAbsolute(firstWorker.x, firstWorker.y, firstWorker.z);
76 | firstWorker.x, firstWorker.y, firstWorker.z, firstWorker.rotY = g_currentMission.player:getPositionData()
77 | g_currentMission.player:moveTo(firstWorker.x, firstWorker.y, firstWorker.z, true, true)
78 | -- DebugUtil.printTableRecursively(firstWorker, " ", 1, 2)
79 | g_currentMission.player:setRotation(firstWorker.rotX, firstWorker.rotY)
80 | if firstWorker.currentVehicle ~= nil then
81 | -- firstWorker:afterSwitch()
82 | --firstWorker.playerStyle:print()
83 | g_client:getServerConnection():sendEvent(VehicleEnterRequestEvent.new(firstWorker.currentVehicle, firstWorker.playerStyle, firstWorker.farmId));
84 | end
85 | end
86 | g_asyncTaskManager:addTask(function ()
87 | if ContractorMod.debug then print("ContractorMod is initialized") end
88 | ContractorMod.initializing = false
89 | end)
90 | end
91 | end
92 | Mission00.onStartMission = Utils.appendedFunction(Mission00.onStartMission, ContractorMod.startMission)
93 |
94 | -- @doc First code called during map loading (before we can actually interact)
95 | function ContractorMod:loadMap(name)
96 | if ContractorMod.debug then print("ContractorMod:loadMap(name)") end
97 | self.initializing = true
98 | if self.initialized then
99 | return;
100 | end;
101 |
102 | self.initialized = true;
103 | end;
104 |
105 | function ContractorMod:deleteMap()
106 | if ContractorMod.debug then print("ContractorMod:deleteMap()") end
107 | self.initialized = false;
108 | self.workers = nil;
109 | end;
110 |
111 | -- @doc register InputBindings
112 | function ContractorMod:registerActionEvents()
113 | if ContractorMod.debug then print("ContractorMod:registerActionEvents()") end
114 | for _,actionName in pairs({ "ContractorMod_WORKER1",
115 | "ContractorMod_WORKER2",
116 | "ContractorMod_WORKER3",
117 | "ContractorMod_WORKER4",
118 | "ContractorMod_WORKER5",
119 | "ContractorMod_WORKER6",
120 | "ContractorMod_WORKER7",
121 | "ContractorMod_WORKER8" }) do
122 | -- print("actionName "..actionName)
123 | local __, eventName, event, action = InputBinding.registerActionEvent(g_inputBinding, actionName, self, ContractorMod.activateWorker ,false ,true ,false ,true)
124 | if __ then
125 | g_inputBinding.events[eventName].displayIsVisible = false
126 | end
127 | end
128 |
129 | if ContractorMod.useDebugCommands then
130 | print("ContractorMod:registerActionEvents() for DEBUG")
131 | for _,actionName in pairs({ "ContractorMod_DEBUG_MOVE_PASS_LEFT",
132 | "ContractorMod_DEBUG_MOVE_PASS_RIGHT",
133 | "ContractorMod_DEBUG_MOVE_PASS_TOP",
134 | "ContractorMod_DEBUG_MOVE_PASS_BOTTOM",
135 | "ContractorMod_DEBUG_MOVE_PASS_FRONT",
136 | "ContractorMod_DEBUG_MOVE_PASS_BACK",
137 | "ContractorMod_DEBUG_DUMP_PASS" }) do
138 | -- print("actionName "..actionName)
139 | local __, eventName, event, action = InputBinding.registerActionEvent(g_inputBinding, actionName, self, ContractorMod.debugCommands ,false ,true ,false ,true)
140 | end
141 | end
142 | end
143 |
144 | -- @doc registerActionEvents need to be called regularly
145 | function ContractorMod:appRegisterActionEvents()
146 | if ContractorMod.debug then print("ContractorMod:appRegisterActionEvents()") end
147 | ContractorMod:registerActionEvents()
148 | end
149 | -- Only needed for global action event
150 | FSBaseMission.registerActionEvents = Utils.appendedFunction(FSBaseMission.registerActionEvents, ContractorMod.appRegisterActionEvents);
151 |
152 | -- @doc Called by update method only once at the beginning when nothing is initialized yet
153 | function ContractorMod:init()
154 | if ContractorMod.debug then print("ContractorMod:init()") end
155 |
156 | -- Look for file FS22_ContractorMod.debug in mod directory to activate debug commands
157 | if g_currentMission ~= nil and g_currentMission:getIsServer() then
158 | if ContractorMod.myCurrentModDirectory then
159 | local debugFilePath = ContractorMod.myCurrentModDirectory .. "../FS22_ContractorMod.debug.xml"
160 | if fileExists(debugFilePath) then
161 | print("ContractorMod: Activating DEBUG commands")
162 | ContractorMod.useDebugCommands = true
163 | self:addDebugInputBinding()
164 | end
165 | end
166 | end
167 |
168 | self.currentID = 1.
169 | self.numWorkers = 4.
170 | self.workers = {}
171 | self.initializing = true
172 | self.shouldStopWorker = true --Enable to distinguish LeaveVehicle when switchingWorker and when leaving due to player request
173 | self.switching = false
174 | self.passengerLeaving = false
175 | ContractorMod.passengerEntering = false
176 | ContractorMod.displayPlayerNames = true
177 | ContractorMod.UniversalPassenger = nil
178 | ContractorMod.UniversalPassenger_VehiclesOfModHub = nil
179 |
180 | self:manageSpecialVehicles()
181 |
182 | local savegameDir;
183 | if g_currentMission.missionInfo.savegameDirectory then
184 | savegameDir = g_currentMission.missionInfo.savegameDirectory;
185 | end;
186 | if not savegameDir and g_careerScreen.currentSavegame and g_careerScreen.currentSavegame.savegameIndex then
187 | savegameDir = ('%ssavegame%d'):format(getUserProfileAppPath(), g_careerScreen.currentSavegame.savegameIndex);
188 | end;
189 | if not savegameDir and g_currentMission.missionInfo.savegameIndex ~= nil then
190 | savegameDir = ('%ssavegame%d'):format(getUserProfileAppPath(), g_careerScreen.missionInfo.savegameIndex);
191 | end;
192 | self.savegameFolderPath = savegameDir;
193 | self.ContractorModXmlFilePath = self.savegameFolderPath .. '/ContractorMod.xml';
194 |
195 | if not self:initFromSave() or #self.workers <= 0 then
196 | if not self:initFromParam() or #self.workers <= 0 then
197 | -- default values
198 | if ContractorMod.debug then print("ContractorMod: No savegame: set default values") end
199 | local workerStyle = g_currentMission.player:getStyle()
200 | local worker = ContractorModWorker:new("Alex", 1, workerStyle)
201 | table.insert(self.workers, worker)
202 | worker = ContractorModWorker:new("Brenda", 2, PlayerStyle.newRandomHelper())
203 | table.insert(self.workers, worker)
204 | worker = ContractorModWorker:new("Chris", 3, PlayerStyle.newRandomHelper())
205 | table.insert(self.workers, worker)
206 | worker = ContractorModWorker:new("David", 4, PlayerStyle.newRandomHelper())
207 | table.insert(self.workers, worker)
208 | self.numWorkers = 4
209 | self.displaySettings = {}
210 | self.displaySettings.characterName = {}
211 | self.displaySettings.characterName.x = 0.9828
212 | self.displaySettings.characterName.y = 0.90
213 | self.displaySettings.characterName.size = 0.024
214 | end
215 | end
216 | -- DebugUtil.printTableRecursively(g_currentMission.players, " ", 1, 2)
217 | -- Associate 1 player to each character and show it if needed
218 | local index = 1
219 | for k, p in pairs(g_currentMission.players) do
220 | if p ~= nil then
221 | if p.rootNode ~= g_currentMission.player.rootNode then
222 | local worker = self.workers[index]
223 | p.isControlled = true
224 | p:moveTo(worker.x, worker.y-0.8, worker.z, true, true)
225 |
226 | if index > 1 and worker.currentVehicle == nil then
227 | p:setVisibility(true)
228 | p.isEntered = false
229 | -- setRotation(p.graphicsRootNode, 0, worker.rotY + math.rad(180.0), 0) -- + math.rad(120.0), 0) -- Why 120? difference ???
230 | -- setRotation(p.cameraNode, worker.rotX, worker.rotY, 0)
231 | else
232 | p:moveToAbsoluteInternal(0, -200, 0);
233 | p:setVisibility(false)
234 | p.isEntered = true
235 | setRotation(p.graphicsRootNode, 0, worker.rotY + math.rad(180.0), 0) -- + math.rad(120.0), 0) -- Why 120? difference ???
236 | setRotation(p.cameraNode, worker.rotX, worker.rotY, 0)
237 | end
238 | -- print("Set style "..worker.name)
239 | -- worker.playerStyle:print()
240 | p:setStyleAsync(worker.playerStyle, nil, false)
241 | worker.player = p
242 | index = index + 1
243 | end
244 | end
245 | end
246 | if ContractorMod.debug then print("ContractorMod:init()------------") end
247 | -- DebugUtil.printTableRecursively(self.workers, " ", 1, 3)
248 | end
249 |
250 |
251 | function ContractorMod:onSwitchVehicle(action)
252 | if ContractorMod.debug then print("ContractorMod:onSwitchVehicle()") end
253 | self.switching = true
254 | if action == "SWITCH_VEHICLE" then
255 | if ContractorMod.debug then print('ContractorMod_NEXTWORKER pressed') end
256 | local nextID = 0
257 | if ContractorMod.debug then print("ContractorMod: self.currentID " .. tostring(self.currentID)) end
258 | if ContractorMod.debug then print("ContractorMod: self.numWorkers " .. tostring(self.numWorkers)) end
259 | if self.currentID < self.numWorkers then
260 | nextID = self.currentID + 1
261 | else
262 | nextID = 1
263 | end
264 | if ContractorMod.debug then print("ContractorMod: nextID " .. tostring(nextID)) end
265 | self:setCurrentContractorModWorker(nextID)
266 | elseif action == "SWITCH_VEHICLE_BACK" then
267 | if ContractorMod.debug then print('ContractorMod_PREVWORKER pressed') end
268 | local prevID = 0
269 | if self.currentID > 1 then
270 | prevID = self.currentID - 1
271 | else
272 | prevID = self.numWorkers
273 | end
274 | self:setCurrentContractorModWorker(prevID)
275 | end
276 | end
277 |
278 | -- @doc Replace switch vehicle by switch worker
279 | function ContractorMod:replaceOnSwitchVehicle(superfunc, action, direction)
280 | ContractorMod:onSwitchVehicle(action)
281 | end
282 | BaseMission.onSwitchVehicle = Utils.overwrittenFunction(BaseMission.onSwitchVehicle, ContractorMod.replaceOnSwitchVehicle);
283 |
284 | -- @doc Switch directly to another worker
285 | function ContractorMod:activateWorker(actionName, keyStatus)
286 | if ContractorMod.debug then print("ContractorMod:activateWorker") end
287 | if ContractorMod.debug then print("actionName "..tostring(actionName)) end
288 | if string.sub(actionName, 1, 20) == "ContractorMod_WORKER" then
289 | local workerIndex = tonumber(string.sub(actionName, -1))
290 | if self.numWorkers >= workerIndex and workerIndex ~= self.currentID then
291 | self:setCurrentContractorModWorker(workerIndex)
292 | end
293 | end
294 | end
295 |
296 | -- @doc Debug commands to set passenger location
297 | function ContractorMod:debugCommands(actionName, keyStatus)
298 | if ContractorMod.debug then print("ContractorMod:debugCommands") end
299 | if ContractorMod.debug then print("actionName "..tostring(actionName)) end
300 | if g_currentMission.controlledVehicle then
301 | local x1, y1, z1 = getTranslation(g_currentMission.controlledVehicle.passengers[1].characterNode)
302 | if string.sub(actionName, 1, 30) == "ContractorMod_DEBUG_MOVE_PASS_" then
303 | if actionName == "ContractorMod_DEBUG_MOVE_PASS_LEFT" then
304 | -- print("+x")
305 | x1 = x1 + 0.05
306 | elseif actionName == "ContractorMod_DEBUG_MOVE_PASS_RIGHT" then
307 | -- print("-x")
308 | x1 = x1 - 0.05
309 | elseif actionName == "ContractorMod_DEBUG_MOVE_PASS_TOP" then
310 | -- print("+z")
311 | z1 = z1 + 0.05
312 | elseif actionName == "ContractorMod_DEBUG_MOVE_PASS_BOTTOM" then
313 | -- print("-z")
314 | z1 = z1 - 0.05
315 | elseif actionName == "ContractorMod_DEBUG_MOVE_PASS_FRONT" then
316 | -- print("+y")
317 | y1 = y1 + 0.05
318 | elseif actionName == "ContractorMod_DEBUG_MOVE_PASS_BACK" then
319 | -- print("-y")
320 | y1 = y1 - 0.05
321 | end
322 | setTranslation(g_currentMission.controlledVehicle.passengers[1].characterNode, x1, y1, z1)
323 | print("x1: "..tostring(x1).." y1: "..tostring(y1).." z1: "..tostring(z1))
324 | DebugUtil.drawDebugReferenceAxisFromNode(g_currentMission.controlledVehicle.passengers[1].characterNode)
325 | end
326 | if actionName == "ContractorMod_DEBUG_DUMP_PASS" then
327 | print("passenger location")
328 | local configFileName = g_currentMission.controlledVehicle.configFileName
329 | print("")
330 | end
331 | end
332 | end
333 |
334 | -- @doc Load ContractorMod parameters from savegame
335 | function ContractorMod:initFromSave()
336 | if ContractorMod.debug then print("ContractorMod:initFromSave") end
337 | if g_currentMission ~= nil and g_currentMission:getIsServer() then
338 | -- Copy ContractorMod.xml from zip to modSettings dir
339 | ContractorMod:CopyContractorModXML()
340 | if self.savegameFolderPath and self.ContractorModXmlFilePath then
341 | createFolder(self.savegameFolderPath);
342 | local xmlFile;
343 | if fileExists(self.ContractorModXmlFilePath) then
344 | xmlFile = XMLFile.load('ContractorMod', self.ContractorModXmlFilePath);
345 | else
346 | xmlFile = XMLFile.create('ContractorMod', self.ContractorModXmlFilePath, 'ContractorMod');
347 | xmlFile:save()
348 | xmlFile:delete();
349 | return false;
350 | end;
351 |
352 | if xmlFile ~= nil then
353 | local xmlKey = "ContractorMod.workers"
354 | local numWorkers = 0
355 | numWorkers = xmlFile:getInt(xmlKey .. string.format("#numWorkers"));
356 | if numWorkers ~= nil then
357 | --print("numWorkers " .. tostring(numWorkers))
358 | for i = 1, numWorkers do
359 | local key = xmlKey .. string.format(".worker(%d)", i - 1)
360 | local workerName = xmlFile:getString(key.."#name");
361 |
362 | if ContractorMod.debug then print(workerName) end
363 | local workerStyle = PlayerStyle.new()
364 | workerStyle:loadFromXMLFile(xmlFile, key .. ".style")
365 | local worker = ContractorModWorker:new(workerName, i, workerStyle)
366 | if ContractorMod.debug then print(xmlFile:getString(key.."#position")) end
367 | local x, y, z = string.getVector(xmlFile:getString(key.."#position"));
368 | if ContractorMod.debug then print("x "..tostring(x)) end
369 | local xRot, yRot, zRot = string.getVector(xmlFile:getString(key.."#rotation"));
370 | if x ~= nil and y ~= nil and z ~= nil and xRot ~= nil and yRot ~= nil and zRot ~= nil then
371 | worker.x = x
372 | worker.y = y
373 | worker.z = z
374 | worker.dx = xRot
375 | worker.dy = yRot
376 | worker.rotY = yRot
377 | worker.dz = zRot
378 | local vehicleID = xmlFile:getString(key.."#vehicleID");
379 | if vehicleID ~= "0" then
380 | if ContractorMod.mapVehicleLoad ~= nil then
381 | -- map savegame vehicle id and network id
382 | local saveId = ContractorMod.mapVehicleLoad[vehicleID]
383 | local vehicle = NetworkUtil.getObject(tonumber(saveId))
384 | if vehicle ~= nil then
385 | if ContractorMod.debug then print("ContractorMod: vehicle not nil") end
386 | worker.currentVehicle = vehicle
387 | local currentSeat = xmlFile:getInt(key.."#currentSeat");
388 | if currentSeat ~= nil then
389 | worker.currentSeat = currentSeat
390 | end
391 | end
392 | end
393 | end
394 | end;
395 | table.insert(self.workers, worker)
396 | -- Display visual drivers when loading savegame
397 | -- Done here since we don't know which of the drivers entering during initialization
398 | if worker.currentVehicle ~= nil and worker.currentSeat ~= nil then
399 | ContractorMod:placeVisualWorkerInVehicle(worker, worker.currentVehicle, worker.currentSeat)
400 | end
401 | end
402 | xmlKey = "ContractorMod.displaySettings.characterName"
403 | self.displaySettings = {}
404 | self.displaySettings.characterName = {}
405 | local x = xmlFile:getFloat(xmlKey .. string.format("#x"));
406 | if x == nil then
407 | x = 0.9828
408 | end
409 | self.displaySettings.characterName.x = x
410 | local y = xmlFile:getFloat(xmlKey .. string.format("#y"));
411 | if y == nil then
412 | y = 0.90
413 | end
414 | self.displaySettings.characterName.y = y
415 | local size = xmlFile:getFloat(xmlKey .. string.format("#size"));
416 | if size == nil then
417 | size = 0.024
418 | end
419 | self.displaySettings.characterName.size = size
420 | xmlKey = "ContractorMod.displaySettings.playerName"
421 | ContractorMod.displayPlayerNames = Utils.getNoNil(xmlFile:getBool(xmlKey .. string.format("#displayPlayerNames")), true);
422 | end
423 | self.numWorkers = numWorkers
424 | return true
425 | end
426 | end
427 | end
428 | end
429 |
430 | -- @doc Load ContractorMod parameters from default parameters (for new game)
431 | function ContractorMod:initFromParam()
432 | if ContractorMod.debug then print("ContractorMod:initFromParam") end
433 | if g_currentMission ~= nil and g_currentMission:getIsServer() then
434 | -- Copy ContractorMod.xml from zip to modSettings dir
435 | ContractorMod:CopyContractorModXML()
436 | if ContractorMod.myCurrentModDirectory then
437 | local xmlFilePath = ContractorMod.myCurrentModDirectory .. "../../modSettings/ContractorMod.xml"
438 | local xmlFile;
439 | if fileExists(xmlFilePath) then
440 | xmlFile = XMLFile.load('ContractorMod', xmlFilePath);
441 | else
442 | return false;
443 | end;
444 |
445 | if xmlFile ~= nil then
446 | local xmlKey = "ContractorMod.workers"
447 | local numWorkers = 0
448 | numWorkers = xmlFile:getInt(xmlKey .. string.format("#numWorkers"));
449 | if numWorkers ~= nil then
450 | if ContractorMod.debug then print("ContractorMod: numWorkers " .. tostring(numWorkers)) end
451 | for i = 1, numWorkers do
452 | local key = xmlKey .. string.format(".worker(%d)", i - 1)
453 | local workerName = xmlFile:getString(key.."#name");
454 | if ContractorMod.debug then print(workerName) end
455 | local workerStyle = PlayerStyle.new()
456 | if i < 2 then
457 | -- First character get configured style and name for new game
458 | if g_gameSettings.lastPlayerStyle ~= nil and g_gameSettings.lastPlayerStyle:isValid() then
459 | workerStyle:copyFrom(g_gameSettings.lastPlayerStyle)
460 | else
461 | workerStyle = PlayerStyle.defaultStyle()
462 | end
463 | workerName = g_currentMission.playerNickname
464 | else
465 | workerStyle:loadFromXMLFile(xmlFile, key .. ".style")
466 | -- workerStyle:print()
467 | end
468 | if ContractorMod.debug then print(workerName) end
469 | local worker = ContractorModWorker:new(workerName, i, workerStyle)
470 | if ContractorMod.debug then print(xmlFile:getString(key.."#position")) end
471 | local x, y, z = string.getVector(xmlFile:getString(key.."#position"));
472 | if ContractorMod.debug then print("x "..tostring(x)) end
473 | local xRot, yRot, zRot = string.getVector(xmlFile:getString(key.."#rotation"));
474 | if x ~= nil and y ~= nil and z ~= nil and xRot ~= nil and yRot ~= nil and zRot ~= nil then
475 | worker.x = x
476 | worker.y = y
477 | worker.z = z
478 | worker.dx = xRot
479 | worker.dy = yRot
480 | worker.dz = zRot
481 | end;
482 | table.insert(self.workers, worker)
483 | end
484 | xmlKey = "ContractorMod.displaySettings.characterName"
485 | self.displaySettings = {}
486 | self.displaySettings.characterName = {}
487 | local x = xmlFile:getFloat(xmlKey .. string.format("#x"));
488 | if x == nil then
489 | x = 0.9828
490 | end
491 | self.displaySettings.characterName.x = x
492 | local y = xmlFile:getFloat(xmlKey .. string.format("#y"));
493 | if y == nil then
494 | y = 0.90
495 | end
496 | self.displaySettings.characterName.y = y
497 | local size = xmlFile:getFloat(xmlKey .. string.format("#size"));
498 | if size == nil then
499 | size = 0.024
500 | end
501 | self.displaySettings.characterName.size = size
502 | xmlKey = "ContractorMod.displaySettings.playerName"
503 | ContractorMod.displayPlayerNames = Utils.getNoNil(xmlFile:getBool(xmlKey .. string.format("#displayPlayerNames")), true);
504 | end
505 | self.numWorkers = numWorkers
506 | return true
507 | end
508 | end
509 | end
510 | end
511 |
512 | -- @doc Copy default parameters from mod mod zip file to mods directory so end-user can edit it
513 | function ContractorMod:CopyContractorModXML()
514 | if ContractorMod.debug then print("ContractorMod:CopyContractorModXML") end
515 | if g_currentMission ~= nil and g_currentMission:getIsServer() then
516 | if ContractorMod.myCurrentModDirectory then
517 | local modSettingsDir = ContractorMod.myCurrentModDirectory .. "../../modSettings"
518 | local xmlFilePath = modSettingsDir.."/ContractorMod.xml"
519 | if ContractorMod.debug then print("ContractorMod:CopyContractorModXML_1") end
520 | local xmlFile;
521 | if not fileExists(xmlFilePath) then
522 | if ContractorMod.debug then print("ContractorMod:CopyContractorModXML_2") end
523 | local xmlSourceFilePath = ContractorMod.myCurrentModDirectory .. "ContractorMod.xml"
524 | local xmlSourceFile;
525 | if fileExists(xmlSourceFilePath) then
526 | if ContractorMod.debug then print("ContractorMod:CopyContractorModXML_3") end
527 | xmlSourceFile = loadXMLFile('ContractorMod', xmlSourceFilePath);
528 | createFolder(modSettingsDir)
529 | saveXMLFileTo(xmlSourceFile, xmlFilePath);
530 | if ContractorMod.debug then print("ContractorMod:CopyContractorModXML_4") end
531 | end
532 | end;
533 | end
534 | end
535 | end
536 |
537 | -- @doc Remove characters (driver & passengers) from vehicle when sold or when exiting game
538 | function ContractorMod:ManageSoldVehicle(vehicle, callDelete)
539 | local vehicleName = ""
540 | if vehicle ~= nil then
541 | if vehicle.name ~= nil then
542 | vehicleName = vehicle.name
543 | end
544 | end
545 | if ContractorMod.debug then print("ContractorMod:ManageSoldVehicle " .. vehicleName) end
546 | if self.workers ~= nil then
547 | if #self.workers > 0 then
548 | for i = 1, self.numWorkers do
549 | local worker = self.workers[i]
550 | if worker.currentVehicle == vehicle then
551 | if ContractorMod.debug then print("ContractorMod: This worker was in a vehicle that has been removed : " .. worker.name) end
552 | if callDelete == nil then
553 | worker.x, worker.y, worker.z = getWorldTranslation(worker.currentVehicle.rootNode);
554 | if worker.y ~= nil then
555 | worker.y = worker.y + 2 --to avoid being under the ground
556 | end
557 | worker.dx, worker.dy, worker.dz = localDirectionToWorld(worker.currentVehicle.rootNode, 0, 0, 1);
558 | end
559 | -- Remove passengers
560 | for p = 1, #worker.currentVehicle.passengers do
561 | if worker.currentVehicle.passengers[p] ~= nil then
562 | worker.currentVehicle.passengers[p]:delete()
563 | end
564 | end
565 | worker.currentVehicle = nil
566 | -- Remove mapHotSpot
567 | -- g_currentMission:removeMapHotspot(worker.mapHotSpot)
568 | -- worker.mapHotSpot:delete()
569 | -- worker.mapHotSpot = nil
570 | --break
571 | end
572 | end
573 | end
574 | end
575 | end
576 | function ContractorMod:removeVehicle(vehicle, callDelete)
577 | -- callDelete is always nil now
578 | ContractorMod:ManageSoldVehicle(vehicle, callDelete)
579 | end
580 | BaseMission.removeVehicle = Utils.prependedFunction(BaseMission.removeVehicle, ContractorMod.removeVehicle);
581 |
582 | -- @doc Load VehicleCharacter for a passenger and put it at the given location
583 | function ContractorMod.addPassenger(vehicle, x, y, z, rx, ry, rz)
584 | if ContractorMod.debug then print("ContractorMod.addPassenger") end
585 | local id = loadI3DFile(ContractorMod.myCurrentModDirectory.."passenger.i3d", false, false, false)
586 | local passengerNode = getChildAt(id, 0)
587 | link(vehicle.components[1].node, passengerNode)
588 | local ChildIndex = getChildIndex(passengerNode)
589 | setTranslation(passengerNode, x, y, z)
590 | setRotation(passengerNode, rx, ry, rz)
591 |
592 | local xmltext = " \z
593 | \z
594 | \z
595 | "..ChildIndex.."\" cameraMinDistance=\"1.5\" spineRotation=\"-90 0 90\" > \z
596 | "..ChildIndex.."|1\" /> \z
597 | "..ChildIndex.."|2\" /> \z
598 | "..ChildIndex.."|3\" poseId=\"wideFingers\"/> \z
599 | "..ChildIndex.."|4\" poseId=\"wideFingers\"/> \z
600 | \z
601 | "
602 | local xmlFile = loadXMLFileFromMemory("passengerConfig", xmltext)
603 | local passengerXMLFile = XMLFile.new("passengerXMLFile", "", xmlFile, Vehicle.xmlSchema)
604 | local passenger = VehicleCharacter.new(vehicle)
605 | passenger:load(passengerXMLFile, "vehicle.enterable.characterNode")
606 |
607 | --[[ Trying to add camera like passenger
608 | local cameraId = loadI3DFile(ContractorMod.myCurrentModDirectory.."camera.i3d", false, false, false)
609 | local cameraNode = getChildAt(cameraId, 0)
610 | link(vehicle.components[1].node, cameraNode)
611 | local cameraChildIndex = getChildIndex(cameraNode)
612 | setTranslation(cameraNode, x, y, z)
613 | setRotation(cameraNode, rx, ry, rz)
614 | print("child "..cameraChildIndex)
615 | print("Passenger: x:"..tostring(x).." y:"..tostring(y).." z:"..tostring(z))
616 | local xmlCameraText = " \z
617 | \z
618 | \z
619 | "..cameraChildIndex.."\" rotatable=\"true\" limit=\"true\" rotMinX=\"-1.1\" rotMaxX=\"0.4\" transMin=\"0\" transMax=\"0\" useMirror=\"true\" isInside=\"true\" /> \z
620 | \z
621 | "
622 | local xmlCameraFile = loadXMLFileFromMemory("passengerCameraConfig", xmlCameraText)
623 | local camera = VehicleCamera.new(vehicle)
624 | camera:loadFromXML(xmlCameraFile, "vehicle.cameras")]]
625 | -- get vehicleCharacter position (from xml ?)
626 | -- local characterNode = vehicle.vehicleCharacter.nodeId
627 | -- print(tostring(characterNode))
628 | -- local x1, y2, z1 = getTranslation(characterNode)
629 | -- print("x1:"..tostring(x1).." y1:"..tostring(y1).." z1:"..tostring(z1))
630 | -- compute transform
631 | -- local transformCam = localToLocal(passengerNode, characterNode)
632 | -- print(tostring(transformCam))
633 | -- add new camera
634 |
635 | return passenger
636 | end
637 |
638 | -- @doc Called when loading a vehicle (load game or buy new vehicle) to retrieve and add passengers info
639 | function ContractorMod:ManageNewVehicle(vehicle)
640 | if ContractorMod.debug then print("ContractorMod.ManageNewVehicle") end
641 |
642 | if SpecializationUtil.hasSpecialization(Enterable, vehicle.specializations) then
643 | vehicle.passengers = {}
644 | local foundConfig = false
645 | -- Don't display warning by default in log, only if displayWarning = true
646 | local xmlPath = "ContractorMod.passengerSeats"
647 | local modDirectoryXMLFilePath = ContractorMod.myCurrentModDirectory .. "../../modSettings/ContractorMod.xml"
648 | local displayWarning = false
649 | if fileExists(modDirectoryXMLFilePath) then
650 | local xmlFile = loadXMLFile('ContractorMod', modDirectoryXMLFilePath);
651 | displayWarning = Utils.getNoNil(getXMLBool(xmlFile, xmlPath.."#displayWarning"), false);
652 | end
653 | -- xml file in zip containing mainly base game vehicles
654 | foundConfig = ContractorMod:loadPassengersFromXML(vehicle, ContractorMod.myCurrentModDirectory.."passengerseats.xml");
655 | if foundConfig == false then
656 | -- Try xml file in mods dir containing user mods
657 | foundConfig = ContractorMod:loadPassengersFromXML(vehicle, modDirectoryXMLFilePath);
658 | if foundConfig == false and ContractorMod.UniversalPassenger then
659 | -- Try xml file from UniversalPassenger
660 | local UniversalPassengerXML = ContractorMod.UniversalPassenger.modDir .. "xml/BaseVehicles.xml"
661 | foundConfig = ContractorMod:loadPassengersFromUniversalPassengerXML(vehicle, UniversalPassengerXML);
662 | if foundConfig == false and ContractorMod.UniversalPassenger_VehiclesOfModHub then
663 | UniversalPassengerXML = ContractorMod.UniversalPassenger_VehiclesOfModHub.modDir .. "xml/VehiclesOfModHub.xml"
664 | -- Try xml file from UniversalPassenger
665 | foundConfig = ContractorMod:loadPassengersFromUniversalPassengerXML(vehicle, UniversalPassengerXML);
666 | end
667 | end
668 | end
669 | if foundConfig == false then
670 | if displayWarning == true then
671 | print("[ContractorMod]No passenger seat configured for vehicle "..vehicle.configFileName)
672 | print("[ContractorMod]Please edit modSettings/ContractorMod.xml to set passenger position")
673 | end
674 | if ContractorMod.useDebugCommands then
675 | local characterNode = vehicle.spec_enterable.defaultCharacterNode
676 | -- print("Driver position node is: "..tostring(characterNode))
677 | -- local x1, y1, z1 = getTranslation(characterNode)
678 | -- print("x1: "..tostring(x1).." y1: "..tostring(y1).." z1: "..tostring(z1))
679 | local dx,dy,dz = localToLocal(vehicle.rootNode, characterNode, 0,0,0);
680 | -- print("x=\""..tostring(dx).."\" y=\""..tostring(dy).."\" z=\""..tostring(dz))
681 | x = -dx
682 | y = -dy
683 | z = -dz
684 | seatIndex = 1
685 | if ContractorMod.debug then print('Adding default seat '..tostring(seatIndex)..' for '..vehicle.configFileName) end
686 | vehicle.passengers[seatIndex] = ContractorMod.addPassenger(vehicle, x, y, z, rx, ry, rz)
687 | end
688 | end
689 | end
690 | end
691 | BaseMission.addVehicle = Utils.appendedFunction(BaseMission.addVehicle, ContractorMod.ManageNewVehicle);
692 |
693 | -- @doc Define empty passenger for special vehicles like trains, crane
694 | function ContractorMod:manageSpecialVehicles()
695 | if ContractorMod.debug then print("ContractorMod:manageSpecialVehicles") end
696 | for k, v in pairs(g_currentMission.nodeToObject) do
697 | if v ~= nil then
698 | --DebugUtil.printTableRecursively(v, " ", 1, 2);
699 | local loco = v.typeName
700 | if loco ~= nil and loco == "locomotive" then
701 | -- no passengers for train
702 | v.passengers = {}
703 | else
704 | -- @FS19: to identify crane if any
705 | if v.stationCraneId ~= nil then
706 | -- no passengers for Station Crane
707 | v.passengers = {}
708 | end
709 | end
710 | end
711 | end
712 | end
713 |
714 | -- @doc Retrieve passengers info from xml files for standard and mods enterable vehicles
715 | function ContractorMod:loadPassengersFromXML(vehicle, xmlFilePath)
716 | if ContractorMod.debug then print("ContractorMod:loadPassengersFromXML") end
717 | local foundConfig = false
718 | if fileExists(xmlFilePath) then
719 | local xmlFile = loadXMLFile('ContractorMod', xmlFilePath);
720 | local i = 0
721 | local xmlVehicleName = ''
722 | while hasXMLProperty(xmlFile, "ContractorMod.passengerSeats"..string.format(".Passenger(%d)", i)) do
723 | xmlPath = "ContractorMod.passengerSeats"..string.format(".Passenger(%d)", i)
724 | xmlVehicleName = getXMLString(xmlFile, xmlPath.."#vehiclesName")
725 | --> ==Manage DLC & mods thanks to dural==
726 | --replace $pdlcdir by the full path
727 | if string.sub(xmlVehicleName, 1, 8):lower() == "$pdlcdir" then
728 | --xmlVehicleName = getUserProfileAppPath() .. "pdlc/" .. string.sub(xmlVehicleName, 10)
729 | --required for steam users
730 | xmlVehicleName = NetworkUtil.convertFromNetworkFilename(xmlVehicleName)
731 | elseif string.sub(xmlVehicleName, 1, 7):lower() == "$moddir" then --20171116 - fix for Horsch CTF vehicle pack
732 | xmlVehicleName = NetworkUtil.convertFromNetworkFilename(xmlVehicleName)
733 | end
734 | -- if ContractorMod.debug then print("Trying to add passenger to "..xmlVehicleName) end
735 | --< ======================================
736 | -- if ContractorMod.debug then print("Compare to vehicle config "..vehicle.configFileName) end
737 | if vehicle.configFileName == xmlVehicleName then
738 | foundConfig = true
739 | local seatIndex = getXMLInt(xmlFile, xmlPath.."#seatIndex")
740 | local x = getXMLFloat(xmlFile, xmlPath.."#x")
741 | local y = getXMLFloat(xmlFile, xmlPath.."#y")
742 | local z = getXMLFloat(xmlFile, xmlPath.."#z")
743 | local rx = getXMLFloat(xmlFile, xmlPath.."#rx")
744 | local ry = getXMLFloat(xmlFile, xmlPath.."#ry")
745 | local rz = getXMLFloat(xmlFile, xmlPath.."#rz")
746 | if seatIndex == 1 and x == 0.0 and y == 0.0 and z == 0.0 then
747 | print("[ContractorMod]Passenger seat not configured yet for vehicle "..xmlVehicleName)
748 | local characterNode = vehicle.spec_enterable.defaultCharacterNode
749 | -- print("Driver position node is: "..tostring(characterNode))
750 | -- local x1, y1, z1 = getTranslation(characterNode)
751 | -- print("x1: "..tostring(x1).." y1: "..tostring(y1).." z1: "..tostring(z1))
752 | local dx,dy,dz = localToLocal(vehicle.rootNode, characterNode, 0,0,0);
753 | -- print("x=\""..tostring(dx).."\" y=\""..tostring(dy).."\" z=\""..tostring(dz))
754 | if ContractorMod.useDebugCommands then
755 | x = -dx
756 | y = -dy
757 | z = -dz
758 | seatIndex = 1
759 | end
760 | end
761 | if seatIndex > 0 then
762 | if ContractorMod.debug then print('Adding seat '..tostring(seatIndex)..' for '..xmlVehicleName) end
763 | vehicle.passengers[seatIndex] = ContractorMod.addPassenger(vehicle, x, y, z, rx, ry, rz)
764 | end
765 | end
766 | i = i + 1
767 | end
768 | end
769 | return foundConfig
770 | end
771 |
772 | -- @doc Load and display characters in vehicle for drivers & passengers instead of default methods
773 | function ContractorMod:placeVisualWorkerInVehicle(worker, vehicle, seat)
774 | if ContractorMod.debug then print("ContractorMod:placeVisualWorkerInVehicle") end
775 | if vehicle.spec_enterable.vehicleCharacter == nil and ContractorMod.debug then print("ContractorMod: vehicle.spec_enterable.vehicleCharacter == nil" ) end
776 | if vehicle.passengers == nil then print("ContractorMod: vehicle.passengers == nil" ) end
777 |
778 | -- if ContractorMod.debug then print("ContractorMod: playerStyle "..tostring(worker.playerStyle.selectedColorIndex)) end
779 |
780 | local character = vehicle:getVehicleCharacter()
781 | if seat == 0 and character ~= nil then
782 | -- Driver
783 | if ContractorMod.debug then print("ContractorMod: setVehicleCharacter as driver") end
784 | character = vehicle:setVehicleCharacter(worker.playerStyle)
785 | else
786 | -- Passenger
787 | if vehicle.passengers ~= nil then
788 | if vehicle.passengers[seat] ~= nil then
789 | if ContractorMod.debug then print("ContractorMod: setVehicleCharacter as passenger") end
790 | vehicle.passengers[seat]:loadCharacter(worker.playerStyle, vehicle, ContractorMod.vehicleCharacterLoaded, seat)
791 | end
792 | end
793 | end
794 | end
795 |
796 | function ContractorMod:vehicleCharacterLoaded(success, seat)
797 | if ContractorMod.debug then print("ContractorMod:vehicleCharacterLoaded "..tostring(success)) end
798 | -- printCallstack()
799 | if success and seat then
800 | self.passengers[seat]:updateVisibility()
801 | self.passengers[seat]:updateIKChains()
802 | end
803 |
804 | -- SpecializationUtil.raiseEvent(self, "onVehicleCharacterChanged", self.passengers[seat])
805 | -- g_messageCenter:subscribe(MessageType.PLAYER_STYLE_CHANGED, self.onPlayerStyleChanged, self)
806 | end
807 |
808 | -- @doc Decide to load driver or passenger character when entering a vehicle
809 | function ContractorMod:ReplaceEnterVehicle(superFunc, isControlling, playerStyle, farmId)
810 | if ContractorMod.debug then print("ContractorMod:ReplaceEnterVehicle") end
811 |
812 | -- @FS19
813 | -- local tmpXmlFilename = PlayerUtil.playerIndexToDesc[playerIndex].xmlFilename
814 | -- PlayerUtil.playerIndexToDesc[playerIndex].xmlFilename = ContractorMod.workers[ContractorMod.currentID].xmlFile
815 | local tmpXmlFilename = g_currentMission.player.xmlFilename
816 | g_currentMission.player.xmlFilename = ContractorMod.workers[ContractorMod.currentID].xmlFile
817 | -- Find free passengerSeat.
818 | -- 0 is drivers seat
819 | local seat
820 | local firstFreepassengerSeat = -1 -- no seat assigned. nil: not in vehicle.
821 | local nbSeats = 0
822 | if self.passengers ~= nil then
823 | nbSeats = #self.passengers
824 | -- print("nbSeats "..tostring(nbSeats))
825 | end
826 | for seat = 0, nbSeats do
827 | local seatUsed = false
828 | if ContractorMod.debug then print("loop on workers") end
829 | for i = 1, ContractorMod.numWorkers do
830 | local worker = ContractorMod.workers[i]
831 | if ContractorMod.debug then print(worker.name) end
832 | if ContractorMod.debug then print("currentSeat "..tostring(worker.currentSeat)) end
833 | if ContractorMod.debug then print("seat "..tostring(seat)) end
834 | if worker.currentVehicle ~= nil then
835 | if ContractorMod.debug then print("currentVehicle "..worker.currentVehicle:getFullName()) end
836 | end
837 | if self ~= nil then
838 | if ContractorMod.debug then print("self "..self:getFullName()) end
839 | end
840 | if worker.currentSeat == seat and worker.currentVehicle == self then
841 | seatUsed = true
842 | break
843 | end
844 | end
845 | if seatUsed == false and ( self.passengers[1] ~= nil or seat == 0 ) then
846 | firstFreepassengerSeat = seat
847 | for i = 1, ContractorMod.numWorkers do
848 | local worker = ContractorMod.workers[i]
849 | if seat == 0 and worker.currentVehicle == self then
850 | --Check if character is not already passenger
851 | if worker.currentSeat > 0 and ContractorMod.switching then
852 | --set him as driver instead since no driver in the vehicle (only when switching, not when entering the vehicle again)
853 | self.passengers[worker.currentSeat]:delete()
854 | worker.currentSeat = 0
855 | break
856 | end
857 | end
858 | end
859 | if ContractorMod.debug then print("firstFreepassengerSeat "..tostring(firstFreepassengerSeat)) end
860 | break
861 | end
862 | end
863 |
864 | if ContractorMod.useDebugCommands and firstFreepassengerSeat <0 then firstFreepassengerSeat = 1 end
865 |
866 | if self.typeName == "horse" then
867 | if ContractorMod.debug then print("ContractorMod: horse: "..self:getFullName()) end
868 | superFunc(self, isControlling, ContractorMod.workers[ContractorMod.currentID].playerStyle, farmId)
869 | return
870 | end
871 | if firstFreepassengerSeat > 0 then
872 | if ContractorMod.debug then print("passenger entering "..tostring(firstFreepassengerSeat)) end
873 | -- We should set true if no more driver but passenger still in the vehicle
874 | ContractorMod.passengerEntering = true
875 | if ContractorMod.debug then print("ContractorMod.passengerEntering "..tostring(ContractorMod.passengerEntering)) end
876 | end
877 | -- local tmpVehicleCharacter = self.spec_enterable.vehicleCharacter
878 | local tmpPlayerStyle = self.spec_enterable.playerStyle
879 | self.spec_enterable.playerStyle = nil
880 | local tmpFarmId = self.farmId
881 | -- self.spec_enterable.vehicleCharacter = nil -- Keep it from beeing modified
882 | superFunc(self, isControlling, ContractorMod.workers[ContractorMod.currentID].playerStyle, farmId)
883 | -- self.spec_enterable.vehicleCharacter = tmpVehicleCharacter
884 | self.spec_enterable.playerStyle = tmpPlayerStyle
885 | self.farmId = tmpFarmId
886 |
887 | -- When Initializing we are called when ContractorMod.currentID is not set.
888 | -- When switching vehicle we are called for drivers already entered but then currentSeat ~= nil.
889 | if ContractorMod.workers[ContractorMod.currentID].currentSeat == nil and not ContractorMod.initializing then
890 | ContractorMod.workers[ContractorMod.currentID].currentSeat = firstFreepassengerSeat
891 | ContractorMod:placeVisualWorkerInVehicle(ContractorMod.workers[ContractorMod.currentID], self, firstFreepassengerSeat)
892 | --if firstFreepassengerSeat > 0 and ContractorMod.workers[ContractorMod.currentID].currentSeat == nil and not ContractorMod.initializing then
893 | if firstFreepassengerSeat > 0 then
894 | if ContractorMod.debug then print("passenger entering") end
895 | ContractorMod.workers[ContractorMod.currentID].isNewPassenger = true
896 | -- TODO: Test somewhere if current worker is passenger/driver => update camera position
897 | -- get playerRoot vehicle
898 | -- compute seat - playerRoot transfo
899 | -- apply transfo to inside camera
900 | if ContractorMod.debug then print("Passenger should not be able to drive") end
901 | end
902 | end
903 | -- @FS19
904 | -- PlayerUtil.playerIndexToDesc[playerIndex].xmlFilename = tmpXmlFilename
905 | g_currentMission.player.xmlFilename = tmpXmlFilename
906 | ContractorMod.passengerEntering = false
907 | end
908 | Enterable.enterVehicle = Utils.overwrittenFunction(Enterable.enterVehicle, ContractorMod.ReplaceEnterVehicle)
909 |
910 | -- Manage wardrobe change when character is in a vehicle
911 | function ContractorMod:ReplaceOnPlayerStyleChanged(superFunc, style, userId)
912 | if ContractorMod.debug then print("ContractorMod:ReplaceOnPlayerStyleChanged "..userId) end
913 | -- printCallstack()
914 | local worker = ContractorMod.workers[ContractorMod.currentID]
915 | -- print(worker.name)
916 | -- style:print()
917 | if ContractorMod.initializing then
918 | if ContractorMod.debug then print("return ContractorMod:ReplaceOnPlayerStyleChanged") end
919 | return
920 | end
921 | worker.playerStyle:copyFrom(style)
922 | if worker.currentVehicle ~= nil and worker.currentSeat ~= nil then
923 | ContractorMod:placeVisualWorkerInVehicle(worker, worker.currentVehicle, worker.currentSeat)
924 | end
925 | -- superFunc(style, userId)
926 | end
927 | Enterable.onPlayerStyleChanged = Utils.overwrittenFunction(Enterable.onPlayerStyleChanged, ContractorMod.ReplaceOnPlayerStyleChanged)
928 |
929 | -- Display character name in wardrobe screen
930 | function ContractorMod:beforeOnOpenWardrobeScreen()
931 | if ContractorMod.debug then print("ContractorMod:beforeOnOpenWardrobeScreen ") end
932 |
933 | --print("player"..tostring(g_currentMission.player))
934 | --print("model "..tostring(g_currentMission.player.model))
935 | --print("style "..tostring(g_currentMission.player.model.style))
936 | --DebugUtil.printTableRecursively(g_currentMission.player.model, " ", 1, 2)
937 | g_currentMission.player.model.style:copyFrom(ContractorMod.workers[ContractorMod.currentID].playerStyle)
938 | g_currentMission.playerNickname = ContractorMod.workers[ContractorMod.currentID].name
939 | end
940 | ShopOthersFrame.onOpenWardrobeScreen = Utils.prependedFunction(ShopOthersFrame.onOpenWardrobeScreen, ContractorMod.beforeOnOpenWardrobeScreen)
941 |
942 | -- Update character when opening wardrobe screen
943 | function ContractorMod:appOnOpenWardrobeScreen()
944 | if ContractorMod.debug then print("ContractorMod:appOnOpenWardrobeScreen ") end
945 | g_wardrobeScreen.temporaryPlayerStyle:copyFrom(ContractorMod.workers[ContractorMod.currentID].playerStyle)
946 | g_wardrobeScreen:updateCharacter()
947 | end
948 | ShopOthersFrame.onOpenWardrobeScreen = Utils.appendedFunction(ShopOthersFrame.onOpenWardrobeScreen, ContractorMod.appOnOpenWardrobeScreen)
949 |
950 | -- Change character name from wardrobe screen player nickname
951 | function ContractorMod:setPlayerNickname(player, nickname, userId, noEventSend)
952 | if ContractorMod.debug then print("ContractorMod:setPlayerNickname "..tostring(nickname)) end
953 | if ContractorMod.workers then
954 | ContractorMod.workers[ContractorMod.currentID].name = nickname
955 | end
956 | end
957 | FSBaseMission.setPlayerNickname = Utils.prependedFunction(FSBaseMission.setPlayerNickname, ContractorMod.setPlayerNickname)
958 | -- @doc Prevent to replace driver character when activating a worker
959 | function ContractorMod:ReplaceSetRandomVehicleCharacter()
960 | if ContractorMod.debug then print("ContractorMod:ReplaceSetRandomVehicleCharacter") end
961 | end
962 | Enterable.setRandomVehicleCharacter = Utils.overwrittenFunction(Enterable.setRandomVehicleCharacter, ContractorMod.ReplaceSetRandomVehicleCharacter)
963 |
964 | -- @doc Prevent to replace driver character when stopping a worker
965 | function ContractorMod:ReplaceRestoreVehicleCharacter()
966 | if ContractorMod.debug then print("ContractorMod:ReplaceRestoreVehicleCharacter") end
967 | end
968 | Enterable.restoreVehicleCharacter = Utils.overwrittenFunction(Enterable.restoreVehicleCharacter, ContractorMod.ReplaceRestoreVehicleCharacter)
969 |
970 | -- @doc Prevent to replace driver character when entering as passenger
971 | function ContractorMod:ReplaceSetVehicleCharacter(superFunc, playerStyle)
972 | if ContractorMod.debug then print("ContractorMod:ReplaceSetVehicleCharacter") end
973 | if not ContractorMod.passengerEntering then
974 | if ContractorMod.debug then print("ContractorMod: not passengerEntering") end
975 | if playerStyle == nil then
976 | print("ContractorMod: playerStyle is nil")
977 | playerStyle = g_currentMission.player:getStyle()
978 | end
979 | superFunc(self, playerStyle)
980 | end
981 | if ContractorMod.debug then print("ContractorMod: passengerEntering return") end
982 | ContractorMod.passengerEntering = false
983 | end
984 | Enterable.setVehicleCharacter = Utils.overwrittenFunction(Enterable.setVehicleCharacter, ContractorMod.ReplaceSetVehicleCharacter)
985 |
986 | -- @doc Prevent error with FS19_Inspector
987 | function ContractorMod:ReplaceGetControllerName(superFunc)
988 | if ContractorMod.debug then print("ContractorMod:ReplaceGetControllerName") end
989 | if self.spec_enterable.playerStyle ~= nil then
990 | return superFunc(self)
991 | end
992 | if #ContractorMod.workers > 0 then
993 | return ContractorMod.workers[ContractorMod.currentID].name
994 | end
995 | return "NO PLAYER NAME"
996 | end
997 | Enterable.getControllerName = Utils.overwrittenFunction(Enterable.getControllerName, ContractorMod.ReplaceGetControllerName)
998 |
999 | -- Enterable:enter() => loadCharacter if isHired == false
1000 | -- Enterable:leaveVehicle() => deleteCharacter if disableCharacterOnLeave == true
1001 | function ContractorMod:ManageBeforeEnterVehicle(vehicle, playerStyle)
1002 | local vehicleName = ""
1003 | if vehicle ~= nil then
1004 | if vehicle.name ~= nil then
1005 | vehicleName = vehicle.name
1006 | end
1007 | end
1008 | if ContractorMod.debug then print("ContractorMod:prependedEnterVehicle >>" .. vehicleName) end
1009 | -- if ContractorMod.debug then DebugUtil.printTableRecursively(vehicle, " ", 1, 1) end
1010 |
1011 | local doExit = false
1012 | if self.workers ~= nil then
1013 | if #self.workers > 0 and not self.initializing and false then
1014 | for i = 1, self.numWorkers do
1015 | local worker = self.workers[i]
1016 | if worker.currentVehicle == vehicle then
1017 | if worker.name ~= self.workers[self.currentID].name then
1018 | if ContractorMod.debug then print("ContractorMod: "..worker.name .. " already in ") end
1019 | if worker.isPassenger == false then
1020 | if ContractorMod.debug then print("as driver") end
1021 | doExit = true
1022 | else
1023 | if ContractorMod.debug then print("as passenger") end
1024 | doExit = false
1025 | end
1026 | else
1027 | doExit = false
1028 | end
1029 | end
1030 | end
1031 | end
1032 | end
1033 | if doExit then
1034 | if ContractorMod.debug then print("ContractorMod: Player will leave before enter" ) end
1035 | g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_INFO, g_i18n:getText("ContractorMod_VEHICLE_NOT_FREE"))
1036 | if vehicle.spec_enterable.vehicleCharacter ~= nil then
1037 | vehicle.spec_enterable.vehicleCharacter:delete();
1038 | end
1039 | end
1040 |
1041 | vehicle.spec_enterable.disableCharacterOnLeave = true;
1042 |
1043 | if ContractorMod.debug then print("ContractorMod:prependedEnterVehicle <<" .. vehicle:getFullName()) end
1044 | end
1045 |
1046 | function ContractorMod:beforeEnterVehicle(vehicle, playerStyle)
1047 | if ContractorMod.debug then print("ContractorMod:beforeEnterVehicle " .. vehicle:getFullName()) end
1048 |
1049 | if ContractorMod.debug and g_currentMission.player:getStyle() and ContractorMod.workers and playerStyle then
1050 | -- print("\ng_currentMission.player:getStyle()")
1051 | -- -- DebugUtil.printTableRecursively(g_currentMission.player:getStyle(), " ", 1, 2)
1052 | -- print("\nworker:getStyle()")
1053 | -- -- DebugUtil.printTableRecursively(ContractorMod.workers[ContractorMod.currentID].playerStyle, " ", 1, 2)
1054 | -- print("\nplayerStyle")
1055 | -- DebugUtil.printTableRecursively(playerStyle, " ", 1, 2)
1056 | end
1057 | ContractorMod:ManageBeforeEnterVehicle(vehicle, playerStyle)
1058 | end
1059 | BaseMission.onEnterVehicle = Utils.prependedFunction(BaseMission.onEnterVehicle, ContractorMod.beforeEnterVehicle);
1060 |
1061 | -- @doc Prevent from removing driver character
1062 | function ContractorMod:replaceGetDisableVehicleCharacterOnLeave(superfunc)
1063 | if ContractorMod.debug then print("ContractorMod:replaceGetDisableVehicleCharacterOnLeave ") end
1064 | if ContractorMod.switching then
1065 | ContractorMod.switching = false
1066 | if ContractorMod.debug then print("switching return false") end
1067 | return false
1068 | end
1069 | if ContractorMod.passengerLeaving then
1070 | ContractorMod.passengerLeaving = false
1071 | if ContractorMod.debug then print("passengerLeaving return false") end
1072 | return false
1073 | end
1074 | return true
1075 | end
1076 | Enterable.getDisableVehicleCharacterOnLeave = Utils.overwrittenFunction(Enterable.getDisableVehicleCharacterOnLeave, ContractorMod.replaceGetDisableVehicleCharacterOnLeave);
1077 |
1078 | -- @doc Prevent to enter a vehicle when no more space
1079 | function ContractorMod:replaceVehicleEnterRequestEventRun(superfunc, connection)
1080 | if ContractorMod.debug then print("ContractorMod:replaceVehicleEnterRequestEventRun ") end
1081 | -- TODO: Manage forestry truck
1082 | local canEnterWhenSwitching = false
1083 | -- 0 is drivers seat
1084 | local seat
1085 | local firstFreepassengerSeat = -1 -- no seat assigned. nil: not in vehicle.
1086 | local nbSeats = 0
1087 | if self.object ~= nil and self.object.passengers ~= nil then
1088 | nbSeats = #self.object.passengers
1089 | -- print("nbSeats "..tostring(nbSeats))
1090 | end
1091 | for seat = 0, nbSeats do
1092 | local seatUsed = false
1093 | if ContractorMod.debug then print("loop on workers") end
1094 | for i = 1, ContractorMod.numWorkers do
1095 | local worker = ContractorMod.workers[i]
1096 | if ContractorMod.debug then print(worker.name) end
1097 | if ContractorMod.debug then print("currentSeat "..tostring(worker.currentSeat)) end
1098 | if ContractorMod.debug then print("seat "..tostring(seat)) end
1099 | if worker.currentVehicle ~= nil then
1100 | if ContractorMod.debug then print("currentVehicle "..worker.currentVehicle:getFullName()) end
1101 | end
1102 | if self.object ~= nil then
1103 | local fullName = "nil"
1104 | if self.object.getFullName ~= nil then
1105 | fullName = self.object:getFullName()
1106 | end
1107 | if ContractorMod.debug then print("self "..fullName) end
1108 | end
1109 | if worker.currentSeat == seat and worker.currentVehicle == self.object and worker == ContractorMod.workers[ContractorMod.currentID] then
1110 | canEnterWhenSwitching = true
1111 | end
1112 | if worker.currentSeat == seat and worker.currentVehicle == self.object then
1113 | seatUsed = true
1114 | break
1115 | end
1116 | end
1117 | if seatUsed == false and ( seat == 0 or self.object.passengers[1] ~= nil ) then
1118 | firstFreepassengerSeat = seat
1119 | break
1120 | end
1121 | end
1122 | if ContractorMod.debug then print("firstFreepassengerSeat "..tostring(firstFreepassengerSeat)) end
1123 |
1124 | if not canEnterWhenSwitching and not ContractorMod.useDebugCommands then
1125 | if firstFreepassengerSeat < 0 and not ContractorMod.initializing then
1126 | if ContractorMod.debug then print("ContractorMod:replaceVehicleEnterRequestEventRun ") end
1127 | g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_INFO, g_i18n:getText("ContractorMod_NO_MORE_PASSENGER"))
1128 | return
1129 | end
1130 | end
1131 | return superfunc(self, connection)
1132 | end
1133 | VehicleEnterRequestEvent.run = Utils.overwrittenFunction(VehicleEnterRequestEvent.run, ContractorMod.replaceVehicleEnterRequestEventRun);
1134 |
1135 | -- @doc Make some checks before leaving a vehicle to manage passengers and hired worker
1136 | function ContractorMod:ManageLeaveVehicle(controlledVehicle)
1137 | if ContractorMod.debug then print("ContractorMod:prependedLeaveVehicle >>") end
1138 |
1139 | if controlledVehicle ~= nil then
1140 | if self.shouldStopWorker then
1141 |
1142 | local occupants = 0
1143 |
1144 | for i = 1, self.numWorkers do
1145 | local worker = self.workers[i]
1146 | if worker.currentVehicle == controlledVehicle then
1147 | occupants = occupants + 1
1148 | end
1149 | end
1150 | if occupants == 1 then -- Last driver leaving
1151 | --Leaving vehicle
1152 | if ContractorMod.debug then print("controlled vehicle " .. controlledVehicle:getFullName()) end
1153 | if ContractorMod.debug then print("controlledVehicle.spec_enterable.isControlled " .. tostring(controlledVehicle.spec_enterable.isControlled)) end
1154 | --if not controlledVehicle.spec_enterable.isControlled then
1155 | if controlledVehicle:getIsAIActive() then
1156 | --Leaving and AI activated
1157 | g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_INFO, g_i18n:getText("ContractorMod_WORKER__STOP"))
1158 | --Manage CoursePlay vehicles
1159 | if controlledVehicle.cp ~= nil then
1160 | if controlledVehicle.cp.isDriving then
1161 | -- Try to stop the CP vehicle
1162 | if ContractorMod.debug then print("setCourseplayFunc stop") end
1163 | controlledVehicle:setCourseplayFunc('stop', nil, false, 1);
1164 | else
1165 | controlledVehicle:stopCurrentAIJob(AIMessageSuccessStoppedByUser.new())
1166 | end
1167 | else
1168 | controlledVehicle:stopCurrentAIJob(AIMessageSuccessStoppedByUser.new())
1169 | end
1170 | --Leaving and no AI activated
1171 | --Bear
1172 | controlledVehicle.spec_enterable.disableCharacterOnLeave = true;
1173 | end
1174 | else
1175 | -- Drivers left
1176 | controlledVehicle.spec_enterable.disableCharacterOnLeave = false;
1177 | end
1178 | if ContractorMod.workers[ContractorMod.currentID].currentSeat == 0 then
1179 | if ContractorMod.debug then print("ContractorMod: driver leaving") end
1180 | if controlledVehicle:getIsAIActive() then
1181 | --Driver Leaving and AI activated
1182 | g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_INFO, g_i18n:getText("ContractorMod_WORKER__STOP"))
1183 | controlledVehicle:stopCurrentAIJob(AIMessageSuccessStoppedByUser.new())
1184 | end
1185 | if controlledVehicle.vehicleCharacter ~= nil then
1186 | -- to manage vehicles without character like belt system
1187 | controlledVehicle.vehicleCharacter:delete()
1188 | end
1189 | else
1190 | if controlledVehicle.passengers[ContractorMod.workers[ContractorMod.currentID].currentSeat] ~= nil then
1191 | local passengerNode = controlledVehicle.passengers[ContractorMod.workers[ContractorMod.currentID].currentSeat].characterNode
1192 | local xPassenger, _, _ = getTranslation(passengerNode)
1193 | local exitPoint = controlledVehicle:getExitNode()
1194 | local x, y, z = getTranslation(exitPoint)
1195 | -- print(string.format("x: %3.4f, y: %3.4f, z: %3.4f", x, y, z))
1196 | -- print(string.format("xPassenger: %3.4f", xPassenger))
1197 | if (x - xPassenger) > x then
1198 | -- Set exit point on the other side for vehicles where passenger is on the other side
1199 | -- Backup exitPoint
1200 | controlledVehicle.backupExitPoint = createTransformGroup("backupExitPoint")
1201 | link(controlledVehicle.rootNode, controlledVehicle.backupExitPoint)
1202 | setTranslation(controlledVehicle.backupExitPoint, x, y, z)
1203 | setTranslation(exitPoint, -x, y, z)
1204 | x, y, z = getWorldTranslation(exitPoint)
1205 | -- print(string.format("x: %3.4f, y: %3.4f, z: %3.4f", x, y, z))
1206 | x, y, z = getTranslation(controlledVehicle.backupExitPoint)
1207 | -- print(string.format("x: %3.4f, y: %3.4f, z: %3.4f", x, y, z))
1208 | end
1209 |
1210 | controlledVehicle.passengers[ContractorMod.workers[ContractorMod.currentID].currentSeat]:delete()
1211 | ContractorMod.workers[ContractorMod.currentID].isNewPassenger = false
1212 | if ContractorMod.debug then print("passenger leaving") end
1213 | self.passengerLeaving = true
1214 | end
1215 | end
1216 | ContractorMod.workers[ContractorMod.currentID].currentSeat = nil
1217 | else
1218 | --Switching
1219 | if controlledVehicle.spec_enterable.isControlled then
1220 | controlledVehicle.spec_enterable.disableCharacterOnLeave = false;
1221 | end
1222 | end
1223 | -- if self.switching then
1224 | -- controlledVehicle.spec_enterable.disableCharacterOnLeave = false;
1225 | -- else
1226 | -- controlledVehicle.spec_enterable.disableCharacterOnLeave = true;
1227 | -- end
1228 | if ContractorMod.debug then print("ContractorMod:prependedLeaveVehicle <<" .. controlledVehicle:getFullName()) end
1229 | end
1230 | end
1231 | function ContractorMod:onLeaveVehicle(superFunc, ...)
1232 | if ContractorMod.debug then print("ContractorMod:onLeaveVehicle ") end
1233 | local controlledVehicle = g_currentMission.controlledVehicle
1234 | if controlledVehicle ~= nil then
1235 | ContractorMod:ManageLeaveVehicle(controlledVehicle)
1236 | end
1237 | superFunc(self, ...)
1238 | if controlledVehicle ~= nil and controlledVehicle.backupExitPoint then
1239 | -- Restore exitPoint
1240 | local x, y, z = getTranslation(controlledVehicle.backupExitPoint)
1241 | local exitPoint = controlledVehicle:getExitNode()
1242 | setTranslation(exitPoint, x, y, z)
1243 | end
1244 | end
1245 | BaseMission.onLeaveVehicle = Utils.overwrittenFunction(BaseMission.onLeaveVehicle, ContractorMod.onLeaveVehicle);
1246 |
1247 | -- @doc Set mapping between savegame vehicle id and vehicle network id when vehicle is loaded
1248 | ContractorMod.appEnterableOnLoad = function(self, savegame)
1249 | if ContractorMod.debug then print("ContractorMod:appEnterableOnLoad ") end
1250 | if savegame ~= nil then
1251 | -- When loading savegame
1252 | if ContractorMod.mapVehicleLoad == nil then
1253 | ContractorMod.mapVehicleLoad = {}
1254 | end
1255 | local key = savegame.key
1256 | -- key is something like vehicles.vehicle(saveId)
1257 | local saveId = 1 + tonumber(string.sub(key, string.find(key, '(', 1, true) + 1, string.find(key, ')', 1, true) - 1))
1258 | local vehicleID = self.id
1259 | -- Set mapping between savegame vehicle id and vehicle network id once loaded
1260 | ContractorMod.mapVehicleLoad[tostring(saveId)] = vehicleID
1261 | -- DebugUtil.printTableRecursively(ContractorMod.mapVehicleLoad, " ", 1, 2);
1262 | end
1263 | end
1264 | Enterable.onLoad = Utils.appendedFunction(Enterable.onLoad, ContractorMod.appEnterableOnLoad)
1265 |
1266 | -- @doc Save workers info to restore them when starting game
1267 | function ContractorMod:onSaveCareerSavegame()
1268 | if ContractorMod.debug then print("ContractorMod:onSaveCareerSavegame ") end
1269 | if self.workers ~= nil then
1270 | local xmlFile;
1271 | if fileExists(self.ContractorModXmlFilePath) then
1272 | xmlFile = XMLFile.load('ContractorMod', self.ContractorModXmlFilePath);
1273 | else
1274 | xmlFile = XMLFile.create('ContractorMod', self.ContractorModXmlFilePath, 'ContractorMod');
1275 | xmlFile:save()
1276 | end;
1277 |
1278 | if xmlFile ~= nil then
1279 | local rootXmlKey = "ContractorMod"
1280 |
1281 | -- update current worker position
1282 | local currentWorker = self.workers[self.currentID]
1283 | if currentWorker ~= nil then
1284 | currentWorker:beforeSwitch(true)
1285 | end
1286 |
1287 | local workerKey = rootXmlKey .. ".workers"
1288 | xmlFile:setInt(workerKey.."#numWorkers", self.numWorkers);
1289 | for i = 1, self.numWorkers do
1290 | local worker = self.workers[i]
1291 | local key = string.format(rootXmlKey .. ".workers.worker(%d)", i - 1);
1292 | xmlFile:setString(key.."#name", worker.name);
1293 | worker.playerStyle:saveToXMLFile(xmlFile, key .. ".style")
1294 | if worker.currentSeat ~= nil then
1295 | xmlFile:setInt(key.."#currentSeat", worker.currentSeat);
1296 | end
1297 | local pos = worker.x..' '..worker.y..' '..worker.z
1298 | xmlFile:setString(key.."#position", pos);
1299 | local rot = worker.dx..' '..worker.dy..' '..worker.dz
1300 | xmlFile:setString(key.."#rotation", rot);
1301 | local vehicleID = "0"
1302 | if worker.currentVehicle ~= nil then
1303 | vehicleID = worker.saveId
1304 | end
1305 | xmlFile:setString(key.."#vehicleID", vehicleID);
1306 | end
1307 | currentWorker.player:moveToAbsoluteInternal(0, -200, 0);
1308 | local xmlKey = rootXmlKey .. ".displaySettings.characterName"
1309 | xmlFile:setFloat(xmlKey .. "#x", self.displaySettings.characterName.x);
1310 | xmlFile:setFloat(xmlKey .. "#y", self.displaySettings.characterName.y);
1311 | xmlFile:setFloat(xmlKey .. "#size", self.displaySettings.characterName.size);
1312 | xmlKey = rootXmlKey .. ".displaySettings.playerName"
1313 | xmlFile:setBool(xmlKey .. "#displayPlayerNames", ContractorMod.displayPlayerNames);
1314 | xmlFile:save()
1315 | xmlFile:delete()
1316 | end
1317 | end
1318 | end
1319 |
1320 | -- @doc Will call dedicated save method
1321 | SavegameController.onSaveComplete = Utils.prependedFunction(SavegameController.onSaveComplete, function(self)
1322 | -- if self.isValid and self.xmlKey ~= nil then
1323 | ContractorMod:onSaveCareerSavegame()
1324 | -- end
1325 | end);
1326 |
1327 | -- @doc store savegame vehicle id if worker is in this vehicle
1328 | function ContractorMod:mapVehicleSave(vehicle, saveId)
1329 | if ContractorMod.debug then print("ContractorMod:mapVehicleSave ") end
1330 | if self.workers ~= nil then
1331 | if #self.workers > 0 then
1332 | for i = 1, self.numWorkers do
1333 | local worker = self.workers[i]
1334 | if worker ~= nil and worker.currentVehicle ~= nil then
1335 | if vehicle == worker.currentVehicle then
1336 | -- store savegame vehicle id
1337 | worker.saveId = saveId
1338 | end
1339 | end
1340 | end
1341 | end
1342 | end
1343 | end
1344 |
1345 | -- @doc Set mapping between savegame vehicle id and vehicle network id when vehicle is saved
1346 | function ContractorMod:preVehicleSave(xmlFile, key, usedModNames)
1347 | -- key is something like vehicles.vehicle(saveId)
1348 | local saveId = 1 + tonumber(string.sub(key, string.find(key, '(', 1, true) + 1, string.find(key, ')', 1, true) - 1))
1349 | if SpecializationUtil.hasSpecialization(Enterable, self.specializations) then
1350 | ContractorMod:mapVehicleSave(self, tostring(saveId))
1351 | end
1352 | end
1353 | Vehicle.saveToXMLFile = Utils.prependedFunction(Vehicle.saveToXMLFile, ContractorMod.preVehicleSave);
1354 |
1355 | -- Append character name when worker is active (not really visible)
1356 | function ContractorMod:setAIHelperName(superfunc, name)
1357 | self.name = name .. " (" .. ContractorMod.workers[ContractorMod.currentID].name .. ")"
1358 | end
1359 | AIHotspot.setAIHelperName = Utils.overwrittenFunction(AIHotspot.setAIHelperName, ContractorMod.setAIHelperName);
1360 |
1361 |
1362 | -- Enable to set color on PlayerHotSpot. Now need to display all PlayerHotSpots, not only current one and map them to workers
1363 | function ContractorMod:getColor()
1364 | -- if ContractorMod.debug then print("ContractorMod:getColor()") end
1365 | local color = { 1, 1, 1, 1}
1366 | if ContractorMod.workers ~= nil then
1367 | if self.player then
1368 | for i = 1, #ContractorMod.workers do
1369 | local worker = ContractorMod.workers[i]
1370 | -- print("worker.name "..tostring(worker.name))
1371 | -- print("nickname "..tostring(nickname))
1372 | if worker.name == nickname then
1373 | color = worker.color
1374 | end
1375 | end
1376 | elseif self.vehicle then
1377 | for i = 1, #ContractorMod.workers do
1378 | local worker = ContractorMod.workers[i]
1379 | if worker.currentVehicle == self.vehicle then
1380 | color = worker.color
1381 | end
1382 | end
1383 | end
1384 | end
1385 | -- print(tostring(unpack(color)))
1386 | return color --ContractorMod.workers[ContractorMod.currentID].color
1387 | end
1388 | PlayerHotspot.getColor = Utils.overwrittenFunction(PlayerHotspot.getColor, ContractorMod.getColor);
1389 | VehicleHotspot.getColor = Utils.overwrittenFunction(VehicleHotspot.getColor, ContractorMod.getColor);
1390 |
1391 | -- @doc Draw worker name and hotspots on map
1392 | function ContractorMod:draw()
1393 | --if ContractorModWorker.debug then print("ContractorMod:draw()") end
1394 | --Display current worker name
1395 | if self.workers ~= nil then
1396 | if #self.workers > 0 and g_currentMission.hud.isVisible then
1397 | local currentWorker = self.workers[self.currentID]
1398 | if currentWorker ~= nil then
1399 | --Display current worker name
1400 | currentWorker:displayName(self)
1401 | end
1402 | -- for i = 1, self.numWorkers do
1403 | -- local worker = self.workers[i]
1404 | -- if worker.mapHotSpot ~= nil then
1405 | -- -- g_currentMission:removeMapHotspot(worker.mapHotSpot)
1406 | -- -- worker.mapHotSpot:delete()
1407 | -- worker.mapHotSpot = nil
1408 | -- end
1409 | -- --@FS19 Display workers on the minimap: To review marker and text size
1410 | -- local _, textSize = getNormalizedScreenValues(0, 9);
1411 | -- local _, textOffsetY = getNormalizedScreenValues(0, 24);
1412 | -- local width, height = getNormalizedScreenValues(12, 12);
1413 | -- if worker.currentVehicle == nil then
1414 | -- --worker.mapHotSpot = g_currentMission.ingameMap:createMapHotspot(tostring(worker.name), tostring(worker.name), ContractorMod.myCurrentModDirectory .. "images/worker" .. tostring(i) .. ".dds", nil, nil, worker.x, worker.z, g_currentMission.ingameMap.mapArrowWidth / 3, g_currentMission.ingameMap.mapArrowHeight / 3, false, false, false, 0);
1415 | -- worker.mapHotSpot = MapHotspot:new(tostring(worker.name), MapHotspot.CATEGORY_AI)
1416 | -- worker.mapHotSpot:setSize(width, height)
1417 | -- -- worker.mapHotSpot:setLinkedNode(0)
1418 | -- worker.mapHotSpot:setText(tostring(worker.name))
1419 | -- -- worker.mapHotSpot:setBorderedImage(nil, getNormalizedUVs({768, 768, 256, 256}), {worker.color[1], worker.color[2], worker.color[3], 1.0})
1420 | -- worker.mapHotSpot:setImage(nil, getNormalizedUVs({768, 768, 256, 256}), {worker.color[1], worker.color[2], worker.color[3], 1.0})
1421 | -- worker.mapHotSpot:setBackgroundImage(nil, getNormalizedUVs({768, 768, 256, 256}))
1422 | -- worker.mapHotSpot:setIconScale(0.7)
1423 | -- worker.mapHotSpot:setTextOptions(textSize, nil, textOffsetY, {worker.color[1], worker.color[2], worker.color[3], 1.0}, Overlay.ALIGN_VERTICAL_MIDDLE)
1424 | -- worker.mapHotSpot:setWorldPosition(worker.x, worker.z)
1425 | -- -- nil, getNormalizedUVs({768, 768, 256, 256}), {worker.color[1], worker.color[2], worker.color[3], 1.0},
1426 | -- -- worker.x, worker.z, width, height, false, false, true, 0, true,
1427 | -- -- MapHotspot.CATEGORY_DEFAULT, textSize, textOffsetY, {worker.color[1], worker.color[2], worker.color[3], 1.0},
1428 | -- --nil, getNormalizedUVs({768, 768, 256, 256}), Overlay.ALIGN_VERTICAL_MIDDLE, 0.7));
1429 | -- else
1430 | -- if worker.currentVehicle.components ~= nil then
1431 | -- --worker.mapHotSpot = g_currentMission:addMapHotspot(tostring(worker.name), tostring(worker.name), ContractorMod.myCurrentModDirectory .. "images/worker" .. tostring(i) .. ".dds", nil, nil, worker.x, worker.z, g_currentMission.ingameMap.mapArrowWidth / 3, g_currentMission.ingameMap.mapArrowHeight / 3, false, false, false, worker.currentVehicle.components[1].node, true);
1432 | -- worker.mapHotSpot = MapHotspot:new(tostring(worker.name), MapHotspot.CATEGORY_AI)
1433 | -- worker.mapHotSpot:setSize(width, height)
1434 | -- worker.mapHotSpot:setLinkedNode(worker.currentVehicle.components[1].node)
1435 | -- worker.mapHotSpot:setText(tostring(worker.name))
1436 | -- worker.mapHotSpot:setImage(nil, getNormalizedUVs({768, 768, 256, 256}), {worker.color[1], worker.color[2], worker.color[3], 1.0})
1437 | -- worker.mapHotSpot:setBackgroundImage(nil, getNormalizedUVs({768, 768, 256, 256}))
1438 | -- worker.mapHotSpot:setIconScale(0.7)
1439 | -- worker.mapHotSpot:setTextOptions(textSize, nil, textOffsetY, {worker.color[1], worker.color[2], worker.color[3], 1.0}, Overlay.ALIGN_VERTICAL_MIDDLE)
1440 | -- -- nil, getNormalizedUVs({768, 768, 256, 256}), {worker.color[1], worker.color[2], worker.color[3], 1.0},
1441 | -- -- worker.x, worker.z, width, height, false, false, true, worker.currentVehicle.components[1].node, true,
1442 | -- -- MapHotspot.CATEGORY_DEFAULT, textSize, textOffsetY, {worker.color[1], worker.color[2], worker.color[3], 1.0},
1443 | -- -- nil, getNormalizedUVs({768, 768, 256, 256}), Overlay.ALIGN_VERTICAL_MIDDLE, 0.7);
1444 | -- else
1445 | -- -- TODO: Analyze in which situation this happens
1446 | -- if ContractorMod.debug then print("ContractorMod: worker.currentVehicle.components == nil" ) end
1447 | -- end
1448 | -- end
1449 | -- if (worker.mapHotSpot ~= nil) then
1450 | -- g_currentMission:addMapHotspot(worker.mapHotSpot)
1451 | -- end
1452 | -- end
1453 | end
1454 | end
1455 | end
1456 |
1457 | -- Display character name instead of player name when not i a vehicle
1458 | function ContractorMod:drawUIInfo()
1459 | if ContractorMod.displayPlayerNames and self.isClient and self.isControlled and not self.isEntered and not g_gui:getIsGuiVisible() and not g_noHudModeEnabled and g_gameSettings:getValue(GameSettings.SETTING.SHOW_MULTIPLAYER_NAMES) then
1460 | local x, y, z = getTranslation(self.graphicsRootNode)
1461 | local x1, y1, z1 = getWorldTranslation(getCamera())
1462 | local diffX = x - x1
1463 | local diffY = y - y1
1464 | local diffZ = z - z1
1465 | local dist = MathUtil.vector3LengthSq(diffX, diffY, diffZ)
1466 |
1467 | if dist <= 10000 then
1468 | y = y + self.baseInformation.tagOffset[2]
1469 | local currentWorker = nil
1470 | if ContractorMod.workers ~= nil then
1471 | for i = 1, #ContractorMod.workers do
1472 | local worker = ContractorMod.workers[i]
1473 | if worker.player.rootNode == self.rootNode then
1474 | currentWorker = worker
1475 | break
1476 | end
1477 | end
1478 | end
1479 | if currentWorker ~= nil then
1480 | Utils.renderTextAtWorldPosition(x, y, z, currentWorker.name, getCorrectTextSize(0.02), 0)
1481 | end
1482 | end
1483 | end
1484 | end
1485 | Player.drawUIInfo = Utils.overwrittenFunction(Player.drawUIInfo, ContractorMod.drawUIInfo);
1486 |
1487 | -- function ContractorMod:setVisibility(superFunc, visibility)
1488 | -- print("ContractorMod:setVisibility player "..self.rootNode..": "..tostring(visibility))
1489 | -- printCallstack()
1490 | -- superFunc(self, visibility)
1491 | -- end
1492 | -- Player.setVisibility = Utils.overwrittenFunction(Player.setVisibility, ContractorMod.setVisibility);
1493 |
1494 | -- function ContractorMod:getPlayerStyle(superFunc, userId)
1495 | -- print("ContractorMod:getPlayerStyle")
1496 | -- -- Too soon, ContractorMod not initialized yet
1497 | -- local firstWorker = ContractorMod.workers[1]
1498 | -- return firstWorker.playerStyle
1499 | -- -- printCallstack()
1500 | -- -- superFunc(self, userId)
1501 | -- end
1502 | -- PlayerInfoStorage.getPlayerStyle = Utils.overwrittenFunction(PlayerInfoStorage.getPlayerStyle, ContractorMod.getPlayerStyle);
1503 | -- function ContractorMod:setPlayerStyle(superFunc, userId, style)
1504 | -- print("ContractorMod:setPlayerStyle")
1505 | -- Too soon, ContractorMod not initialized yet
1506 | -- local firstWorker = ContractorMod.workers[1]
1507 | -- return firstWorker.playerStyle
1508 | -- printCallstack()
1509 | -- superFunc(self, userId)
1510 | -- end
1511 | -- PlayerInfoStorage.setPlayerStyle = Utils.overwrittenFunction(PlayerInfoStorage.setPlayerStyle, ContractorMod.setPlayerStyle);
1512 |
1513 | -- @doc Launch init at first call and then update workers positions and states
1514 | function ContractorMod:update(dt)
1515 | -- DebugUtil.printTableRecursively(g_currentMission.player, " ", 1, 3)
1516 |
1517 | if self.workers ~= nil and #self.workers > 0 then
1518 | for i = 1, self.numWorkers do
1519 | worker = self.workers[i]
1520 | if i == self.currentID then
1521 | -- For current player character
1522 | if g_currentMission.controlledVehicle == nil then
1523 | -- local passengerHoldingVehicle = g_currentMission.passengerHoldingVehicle;
1524 | -- if passengerHoldingVehicle ~= nil then
1525 | -- worker.isPassenger = true
1526 | -- worker.currentVehicle = passengerHoldingVehicle;
1527 | -- worker.passengerPlace = g_currentMission.passengerPlace
1528 | -- else
1529 | -- not in a vehicle
1530 | -- worker.x, worker.y, worker.z = getWorldTranslation(g_currentMission.player.rootNode);
1531 | worker.x, worker.y, worker.z, worker.rotY = g_currentMission.player:getPositionData()
1532 | worker.rotX = g_currentMission.player.rotX
1533 | -- worker.rotY = g_currentMission.player.rotY
1534 | worker.isPassenger = false
1535 | worker.passengerPlace = 0
1536 | worker.currentVehicle = nil;
1537 | -- print("Current worker")
1538 | -- DebugUtil.printTableRecursively(worker.playerStateMachine, " ", 1, 3);
1539 | -- end
1540 | else
1541 | -- in a vehicle
1542 | worker.x, worker.y, worker.z = getWorldTranslation(g_currentMission.controlledVehicle.rootNode); -- for miniMap update
1543 | worker.currentVehicle = g_currentMission.controlledVehicle;
1544 | -- forbid motor stop when switching between workers
1545 | -- FS22 should be on Motorized
1546 | worker.currentVehicle.motorStopTimer = worker.currentVehicle.motorStopTimerDuration
1547 | end
1548 | else
1549 | -- For other characters
1550 | if worker.currentVehicle ~= nil and worker.currentVehicle.rootNode ~= nil then
1551 | -- update if in a vehicle
1552 | worker.x, worker.y, worker.z = getWorldTranslation(worker.currentVehicle.rootNode); -- for miniMap update
1553 | -- forbid motor stop when switching between workers
1554 | -- FS22 should be on Motorized
1555 | worker.currentVehicle.motorStopTimer = worker.currentVehicle.motorStopTimerDuration
1556 | end
1557 | end
1558 | end
1559 | end
1560 | end
1561 |
1562 | -- @doc Change active worker
1563 | function ContractorMod:setCurrentContractorModWorker(setID)
1564 | if ContractorMod.debug then print("ContractorMod:setCurrentContractorModWorker(setID) " .. tostring(setID) .. " - " .. tostring(self.currentID)) end
1565 | local currentWorker = self.workers[self.currentID]
1566 | if currentWorker ~= nil then
1567 | self.shouldStopWorker = false
1568 | self.switching = true
1569 | currentWorker:beforeSwitch()
1570 | end
1571 | self.currentID = setID
1572 | currentWorker = self.workers[self.currentID]
1573 | if currentWorker ~= nil then
1574 | currentWorker:afterSwitch()
1575 | self.shouldStopWorker = true
1576 | self.switching = false
1577 | end
1578 | --DebugUtil.printTableRecursively(self.workers, " ", 1, 3)
1579 | end
1580 |
1581 | function ContractorMod:doNothing()
1582 | if ContractorMod.debug then print("ContractorMod:doNothing ") end
1583 | -- print("Prevent entering as passenger")
1584 | end
1585 |
1586 | function ContractorMod:onPlayerEnter(isControlling)
1587 | if ContractorMod.debug then print("ContractorMod:onPlayerEnter ") end
1588 | if g_currentMission.player:getStyle() and ContractorMod.workers then
1589 | if ContractorMod.debug then
1590 | print("\ng_currentMission.player:getStyle()")
1591 | -- DebugUtil.printTableRecursively(g_currentMission.player:getStyle(), " ", 1, 2)
1592 | print("\nworker:getStyle()")
1593 | -- DebugUtil.printTableRecursively(ContractorMod.workers[ContractorMod.currentID].playerStyle, " ", 1, 2)
1594 | end
1595 | -- printCallstack()
1596 | g_currentMission.player:getStyle():copyFrom(ContractorMod.workers[ContractorMod.currentID].playerStyle)
1597 | end
1598 | end
1599 | Player.onEnter = Utils.appendedFunction(Player.onEnter, ContractorMod.onPlayerEnter)
1600 |
1601 | function ContractorMod:onItemSelectionConfirmed()
1602 | ContractorMod.workers[ContractorMod.currentID].playerStyle:copyFrom(self.currentPlayerStyle)
1603 | end
1604 | WardrobeScreen.onItemSelectionConfirmed = Utils.appendedFunction(WardrobeScreen.onItemSelectionConfirmed, ContractorMod.onItemSelectionConfirmed)
1605 |
1606 | function ContractorMod:addDebugInputBinding()
1607 | if ContractorMod.debug then print("ContractorMod:addDebugInputBinding ") end
1608 |
1609 | local xmltext = " \z
1610 | \z
1611 | \z
1612 | \z
1613 | \z
1614 | \z
1615 | \z
1616 | \z
1617 | \z
1618 | \z
1619 | \z
1620 | \z
1621 | "
1622 | local xmlFile = loadXMLFileFromMemory("actions", xmltext)
1623 |
1624 | InputBinding.loadActions(g_inputBinding, xmlFile, "FS22_ContractorMod")
1625 |
1626 | xmltext = " \z
1627 | \z
1628 | \z
1629 | \z
1630 | \z
1631 | \z
1632 | \z
1633 | \z
1634 | \z
1635 | \z
1636 | \z
1637 | \z
1638 | \z
1639 | \z
1640 | \z
1641 | \z
1642 | \z
1643 | \z
1644 | \z
1645 | \z
1646 | \z
1647 | \z
1648 | \z
1649 | \z
1650 | \z
1651 | \z
1652 | "
1653 | xmlFile = loadXMLFileFromMemory("inputBinding", xmltext)
1654 |
1655 | InputBinding.loadActionBindingsFromXML(g_inputBinding, xmlFile, true, "FS22_ContractorMod")
1656 | InputBinding.assignActionPrimaryBindings(g_inputBinding)
1657 | InputBinding.commitBindingChanges(g_inputBinding)
1658 |
1659 | end
1660 |
1661 | addModEventListener(ContractorMod);
1662 |
--------------------------------------------------------------------------------
/scripts/ContractorModWorker.lua:
--------------------------------------------------------------------------------
1 | --
2 | -- ContractorMod
3 | -- Specialization for storing each character data
4 | -- No event plugged, only called when interacting with ContractorMod
5 | --
6 | -- @author yumi
7 | -- free for noncommercial-usage
8 | --
9 |
10 | ContractorModWorker = {};
11 | ContractorModWorker_mt = Class(ContractorModWorker);
12 |
13 | ContractorModWorker.debug = false --true --
14 |
15 | function ContractorModWorker:getParentComponent(node)
16 | return self.graphicsRootNode;
17 | end;
18 |
19 | function ContractorModWorker:new(name, index, workerStyle)
20 | if ContractorModWorker.debug then print("ContractorModWorker:new()") end
21 | local self = {};
22 | setmetatable(self, ContractorModWorker_mt);
23 |
24 | self.name = name
25 | self.currentVehicle = nil
26 | self.isPassenger = false -- to be removed when all code clean
27 | self.isNewPassenger = false -- to replace isPassenger waiting code cleaning
28 |
29 | local connection = g_server.clientConnections[NetworkNode.LOCAL_STREAM_ID]
30 | local user = g_currentMission.userManager:getUserByConnection(connection)
31 | local farm = g_farmManager:getFarmByUserId(user:getId())
32 | local farmId = FarmManager.SPECTATOR_FARM_ID
33 |
34 | if farm ~= nil then
35 | farmId = farm.farmId
36 | end
37 |
38 | local userId = user:getId()
39 | -- g_currentMission.playerInfoStorage:setPlayerStyle(userId, workerStyle)
40 | g_currentMission:createPlayer(connection, false, farmId, userId)
41 | user:setState(FSBaseMission.USER_STATE_INGAME)
42 |
43 |
44 | -- p.model.style.playerName = name
45 | self.mapHotSpot = nil
46 | self.color = Farm.COLORS[index]
47 | if g_currentMission.controlPlayer and g_currentMission.player ~= nil then
48 | -- self.x, self.y, self.z = getWorldTranslation(g_currentMission.player.rootNode);
49 | self.x, self.y, self.z, self.rotY = g_currentMission.player:getPositionData()
50 | self.dx, self.dy, self.dz = localDirectionToWorld(g_currentMission.player.rootNode, 0, 0, 1);
51 | self.rotX = 0.;
52 | -- self.rotY = 0.73;
53 | self.x = self.x + (1 * index)
54 | self.playerStyle = PlayerStyle.new()
55 | self.playerStyle:copyFrom(workerStyle)
56 | self.farmId = farmId
57 | self.player = nil
58 | end
59 | return self
60 | end
61 |
62 |
63 | function ContractorModWorker:displayName(contractorMod)
64 | --if ContractorModWorker.debug then print("ContractorModWorker:displayName()") end
65 | if self.name == "PLAYER" then return end
66 | setTextBold(true);
67 | setTextAlignment(RenderText.ALIGN_RIGHT);
68 |
69 | setTextColor(self.color[1], self.color[2], self.color[3], 1.0);
70 | local x = 0.9828
71 | local y = 0.45
72 | local size = 0.024
73 | if contractorMod.displaySettings ~= nil and contractorMod.displaySettings.characterName ~= nil then
74 | x = contractorMod.displaySettings.characterName.x
75 | y = contractorMod.displaySettings.characterName.y
76 | size = contractorMod.displaySettings.characterName.size
77 | end
78 | renderText(x, y, size, self.name);
79 |
80 | if ContractorModWorker.debug then
81 | if self.currentVehicle ~= nil then
82 | local vehicleName = ""
83 | if self.currentVehicle ~= nil then
84 | vehicleName = self.currentVehicle:getFullName()
85 | end
86 | renderText(0.9828, 0.43, 0.012, vehicleName);
87 | renderText(0.9828, 0.42, 0.012, "seat:" .. tostring(self.currentSeat) );
88 | end
89 | renderText(0.9828, 0.41, 0.012, self.name);
90 | renderText(0.9828, 0.40, 0.012, "x:" .. tostring(self.x) .. " y:" .. tostring(self.y) .. " z:" .. tostring(self.z));
91 | renderText(0.9828, 0.39, 0.012, "dx:" .. tostring(self.dx) .. " dy:" .. tostring(self.dy) .. " dz:" .. tostring(self.dz));
92 | renderText(0.9828, 0.38, 0.012, "rotX:" .. tostring(self.rotX) .. " rotY:" .. tostring(self.rotY));
93 | -- renderText(0.9828, 0.37, 0.012, "graphicsRotY:" .. tostring(self.player.graphicsRotY));
94 | -- renderText(0.9828, 0.36, 0.012, "targetGraphicsRotY:" .. tostring(self.player.targetGraphicsRotY));
95 | renderText(0.9828, 0.35, 0.012, "shouldStopWorker: " .. tostring(contractorMod.shouldStopWorker));
96 | renderText(0.9828, 0.33, 0.012, "switching: " .. tostring(contractorMod.switching));
97 | renderText(0.9828, 0.31, 0.012, "passengerLeaving: " .. tostring(contractorMod.passengerLeaving));
98 | renderText(0.9828, 0.29, 0.012, "passengerEntering: " .. tostring(contractorMod.passengerEntering));
99 | end
100 | -- Restore default alignment (to avoid impacting other mods like FarmingTablet)
101 | setTextAlignment(RenderText.ALIGN_LEFT);
102 | end
103 |
104 | -- @doc Capture worker position before switching to another one
105 | function ContractorModWorker:beforeSwitch(noEventSend)
106 | if ContractorModWorker.debug then print("ContractorModWorker:beforeSwitch()") end
107 | self.currentVehicle = g_currentMission.controlledVehicle
108 |
109 | if self.currentVehicle == nil then
110 | -- Old passenger condition
111 | local passengerHoldingVehicle = g_currentMission.passengerHoldingVehicle;
112 | if passengerHoldingVehicle ~= nil then
113 | -- source worker is passenger in a vehicle
114 | else
115 | -- source worker is not in a vehicle
116 | self.x, self.y, self.z, self.rotY = g_currentMission.player:getPositionData()
117 | if ContractorModWorker.debug then print("ContractorModWorker: "..tostring(self.x)..", "..tostring(self.y)..", "..tostring(self.z)) end
118 | self.rotX = g_currentMission.player.rotX;
119 | self.rotY = g_currentMission.player.rotY;
120 | self.player.isEntered = false
121 | self.player:setStyleAsync(self.playerStyle, nil, noEventSend)
122 | -- self.playerStyle:print()
123 | if noEventSend == nil or noEventSend == false then
124 | -- print("set visible 1: "..self.name)
125 | self.player:setVisibility(true)
126 | end
127 | -- if ContractorModWorker.debug then print("ContractorModWorker: moveTo "..tostring(self.player.model.style.playerName)); end
128 |
129 | -- local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, self.x, 300, self.z)
130 | -- self.y = math.max(terrainHeight + 0.1, self.y + 0.9)
131 |
132 | -- self.player:moveRootNodeToAbsolute(self.x, self.y, self.z)
133 | self.player:moveTo(self.x, self.y-0.8, self.z, true, true)
134 |
135 | -- local x, y, z = getWorldTranslation(spawnPoint)
136 | -- local dx, _, dz = localDirectionToWorld(spawnPoint, 0, 0, -1)
137 | -- local dx, _, dz = localDirectionToWorld(g_currentMission.player.rootNode, 0, 0, -1)
138 | -- local ry = MathUtil.getYRotationFromDirection(dx, dz)
139 | -- local y = math.max(self.y, getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, self.x, 0, self.z) + 0.2)
140 |
141 | -- self.player:moveTo(self.x, y, self.z, true, true)
142 | -- self.player:setRotation(0, ry)
143 | --[[
144 | self.player.baseInformation.isOnGround = true
145 | self.player:moveToAbsoluteInternal(self.x, self.y, self.z)
146 |
147 | local dx, _, dz = localDirectionToWorld(g_currentMission.player.rootNode, 0, 0, -1) --]]
148 | -- self.rotY = MathUtil.getYRotationFromDirection(dx, dz)
149 |
150 | setRotation(self.player.graphicsRootNode, 0, self.rotY + math.rad(180.0), 0)
151 | setRotation(self.player.cameraNode, self.rotX, self.rotY, 0)
152 | end
153 | else
154 | -- source worker is in a vehicle
155 | self.x, self.y, self.z = getWorldTranslation(self.currentVehicle.rootNode);
156 | self.y = self.y + 2 --to avoid being under the ground
157 | self.dx, self.dy, self.dz = localDirectionToWorld(self.currentVehicle.rootNode, 0, 0, 1);
158 |
159 | if noEventSend == nil or noEventSend == false then
160 | if ContractorModWorker.debug then print("ContractorModWorker: sendEvent(onLeaveVehicle") end
161 | g_currentMission:onLeaveVehicle()
162 | end
163 | end
164 | end
165 |
166 | -- @doc Teleport to target worker when switching
167 | function ContractorModWorker:afterSwitch(noEventSend)
168 | if ContractorModWorker.debug then print("ContractorModWorker:afterSwitch()") end
169 |
170 | if self.currentVehicle == nil then
171 | -- target worker is not in a vehicle
172 | if g_currentMission.controlPlayer and g_currentMission.player ~= nil then
173 | -- if ContractorModWorker.debug then print("ContractorModWorker: moveTo "..tostring(g_currentMission.player.model.style.playerName)); end
174 | -- setTranslation(g_currentMission.player.rootNode, self.x, self.y, self.z);
175 | -- g_currentMission.player:moveRootNodeToAbsolute(self.x, self.y-0.2, self.z);
176 | g_currentMission.player:moveTo(self.x, self.y, self.z, true, true)
177 | g_currentMission.player:setRotation(self.rotX, self.rotY)
178 | self.player.isEntered = true
179 | self.player.isControlled = true
180 | self.player:moveToAbsoluteInternal(0, -200, 0); -- to avoid having player at the same location than current player
181 | if ContractorModWorker.debug then print("ContractorModWorker: set visible 0: "..self.name); end
182 | -- TODO --self.player:setVisibility(false)
183 | if ContractorModWorker.debug then
184 | print("ContractorModWorker: setStyleAsync ");
185 | DebugUtil.printTableRecursively(self.playerStyle, " ", 1, 3)
186 | end
187 | g_currentMission.player:setStyleAsync(self.playerStyle, nil, false)
188 | end
189 |
190 | else
191 | -- if self.isPassenger then
192 | -- target worker is passenger
193 | -- else
194 | -- target worker is in a vehicle
195 | if noEventSend == nil or noEventSend == false then
196 | if ContractorModWorker.debug then print("ContractorModWorker: sendEvent(VehicleEnterRequestEvent:" ) end
197 | g_client:getServerConnection():sendEvent(VehicleEnterRequestEvent.new(self.currentVehicle, self.playerStyle, self.farmId));
198 | if ContractorModWorker.debug then print("ContractorModWorker: playerStyle "..tostring(self.playerStyle)) end
199 | end
200 | -- end
201 | end
202 | end
203 |
204 |
--------------------------------------------------------------------------------