Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
1 | -- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved. |
2 | |
3 | TipTrigger = {}; |
4 | |
5 | local TipTrigger_mt = Class(TipTrigger, Object); |
6 | |
7 | InitStaticObjectClass(TipTrigger, "TipTrigger", ObjectIds.OBJECT_TIP_TRIGGER); |
8 | |
9 | function TipTrigger:onCreate(id) |
10 | local trigger = TipTrigger:new(g_server ~= nil, g_client ~= nil); |
11 | local index = g_currentMission:addOnCreateLoadedObject(trigger); |
12 | trigger:load(id); |
13 | trigger:register(true); |
14 | end; |
15 | |
16 | function TipTrigger:new(isServer, isClient, customMt) |
17 | if customMt == nil then |
18 | customMt = TipTrigger_mt; |
19 | end |
20 | local self = Object:new(isServer, isClient, customMt); |
21 | self.triggerId = 0; |
22 | self.rootNode = 0; |
23 | g_currentMission:addTipTrigger(self); |
24 | return self; |
25 | end; |
26 | |
27 | function TipTrigger:load(id) |
28 | |
29 | self.rootNode = id; |
30 | self.triggerId = Utils.indexToObject(id, getUserAttribute(id, "triggerIndex")); |
31 | if self.triggerId == nil then |
32 | self.triggerId = id; |
33 | end |
34 | addTrigger(self.triggerId, "triggerCallback", self); |
35 | |
36 | self.appearsOnPDA = Utils.getNoNil(getUserAttribute(id, "appearsOnPDA"), false); |
37 | self.isFarmTrigger = Utils.getNoNil(getUserAttribute(id, "isFarmTrigger"), false); |
38 | self.suppressWarnings = Utils.getNoNil(getUserAttribute(id, "suppressWarnings"), false); |
39 | self.stationName = Utils.getNoNil(getUserAttribute(id, "stationName"), "Station"); |
40 | |
41 | self.isAreaTrigger = Utils.getNoNil(getUserAttribute(id, "isAreaTrigger"), false); |
42 | if self.isAreaTrigger then |
43 | self.triggerStartId = getChildAt(id, 0); |
44 | self.triggerEndId = getChildAt(id, 1); |
45 | self.triggerWidth = Utils.getNoNil(getUserAttribute(id, "triggerWidth"), 3); |
46 | else |
47 | self.triggerStartId = self.triggerId; |
48 | end |
49 | |
50 | self.triggerTipWidth = Utils.getNoNil(getUserAttribute(id, "triggerTipWidth"), math.huge); |
51 | |
52 | if self.priceMultipliers == nil or self.acceptedFillTypes == nil then |
53 | self.acceptedFillTypes = {}; |
54 | self.priceMultipliers = {}; |
55 | |
56 | local fillTypes = getUserAttribute(id, "fillTypes"); |
57 | if fillTypes == nil then |
58 | fillTypes = getUserAttribute(id, "fruitTypes"); |
59 | end |
60 | local priceMultipliersString = getUserAttribute(id, "priceMultipliers"); |
61 | if fillTypes ~= nil then |
62 | local types = Utils.splitString(" ", fillTypes); |
63 | |
64 | local multipliers = {}; |
65 | if priceMultipliersString ~= nil then |
66 | multipliers = Utils.splitString(" ", priceMultipliersString); |
67 | elseif not self.isFarmTrigger and self.defaultPriceMultiplier == nil then |
68 | print("Error: Missing priceMultipliers string user attribute for TipTrigger "..getName(id)); |
69 | end; |
70 | for k,v in pairs(types) do |
71 | local desc = Fillable.fillTypeNameToDesc[v]; |
72 | if desc ~= nil then |
73 | self.acceptedFillTypes[desc.index] = true; |
74 | self.priceMultipliers[desc.index] = tonumber(multipliers[k]); |
75 | if self.priceMultipliers[desc.index] == nil then |
76 | self.priceMultipliers[desc.index] = Utils.getNoNil(self.defaultPriceMultiplier, 0); |
77 | if not self.isFarmTrigger and self.defaultPriceMultiplier == nil then |
78 | print("Error: "..k.."th priceMultiplier is invalid in TipTrigger "..getName(id)); |
79 | end; |
80 | end; |
81 | end; |
82 | end; |
83 | end; |
84 | end |
85 | |
86 | local movingIndex = getUserAttribute(id, "movingIndex"); |
87 | if movingIndex ~= nil then |
88 | local movingRootNode = id; |
89 | if self.triggerId == id then |
90 | movingRootNode = getParent(id); |
91 | end |
92 | self.movingId = Utils.indexToObject(movingRootNode, movingIndex); |
93 | if self.movingId ~= nil then |
94 | self.moveMinY = Utils.getNoNil(getUserAttribute(id, "moveMinY"), 0); |
95 | self.moveMaxY = Utils.getNoNil(getUserAttribute(id, "moveMaxY"), 0); |
96 | self.moveScale = Utils.getNoNil(getUserAttribute(id, "moveScale"), 0.001)*0.01; |
97 | self.moveBackScale = (self.moveMaxY-self.moveMinY)/Utils.getNoNil(getUserAttribute(id, "moveBackTime"), 10000); |
98 | end; |
99 | end; |
100 | |
101 | self.forwardFillLevel = Utils.getNoNil(getUserAttribute(id, "forwardFillLevel"), false); |
102 | |
103 | if self.appearsOnPDA then |
104 | |
105 | local mapPosition = id; |
106 | local mapPositionIndex = getUserAttribute(id, "mapPositionIndex"); |
107 | if mapPositionIndex ~= nil then |
108 | mapPosition = Utils.indexToObject(id, mapPositionIndex); |
109 | if mapPosition == nil then |
110 | mapPosition = id; |
111 | end; |
112 | end; |
113 | |
114 | local x, _, z = getWorldTranslation(mapPosition); |
115 | |
116 | local fullViewName = self.stationName; |
117 | if g_i18n:hasText(fullViewName) then |
118 | fullViewName = g_i18n:getText(fullViewName) |
119 | end; |
120 | self.mapHotspot = g_currentMission.ingameMap:createMapHotspot("", "dataS2/menu/hud/hud_pda_spot_tipPlaceGold.png", x, z, nil, nil, false, false, true, 0, true); |
121 | self.mapHotspot.fullViewName = fullViewName; |
122 | end; |
123 | |
124 | self.isEnabled = true; |
125 | |
126 | self.updateEventListeners = {} |
127 | |
128 | self.tipTriggerDirtyFlag = self:getNextDirtyFlag(); |
129 | |
130 | self.moneyChangeId = getMoneyTypeId(); |
131 | self.lastMoneyChange = -1; |
132 | |
133 | return true; |
134 | end; |
135 | |
136 | function TipTrigger:delete() |
137 | if self.mapHotspot ~= nil then |
138 | g_currentMission.ingameMap:deleteMapHotspot(self.mapHotspot); |
139 | end; |
140 | for trailer,triggers in pairs(g_currentMission.trailerTipTriggers) do |
141 | if triggers ~= nil then |
142 | for i=1, table.getn(triggers) do |
143 | if triggers[i] == self then |
144 | table.remove(triggers, i); |
145 | if table.getn(triggers) == 0 then |
146 | g_currentMission.trailerTipTriggers[trailer] = nil; |
147 | end; |
148 | end; |
149 | end; |
150 | end; |
151 | end; |
152 | g_currentMission:removeTipTrigger(self); |
153 | if self.triggerId ~= 0 then |
154 | removeTrigger(self.triggerId); |
155 | end |
156 | if self.rootNode ~= 0 then |
157 | delete(self.rootNode); |
158 | end |
159 | TipTrigger:superClass().delete(self); |
160 | end; |
161 | |
162 | function TipTrigger:readStream(streamId, connection) |
163 | if connection:getIsServer() then |
164 | if self.movingId ~= nil then |
165 | local x,y,z = getTranslation(self.movingId); |
166 | y = streamReadFloat32(streamId); |
167 | setTranslation(self.movingId, x, y, z); |
168 | end; |
169 | end; |
170 | end; |
171 | |
172 | function TipTrigger:writeStream(streamId, connection) |
173 | if not connection:getIsServer() then |
174 | if self.movingId ~= nil then |
175 | local x,y,z = getTranslation(self.movingId); |
176 | streamWriteFloat32(streamId, y); |
177 | end; |
178 | end; |
179 | end; |
180 | |
181 | function TipTrigger:readUpdateStream(streamId, timestamp, connection) |
182 | self:readStream(streamId, connection); |
183 | end; |
184 | |
185 | function TipTrigger:writeUpdateStream(streamId, connection, dirtyMask) |
186 | self:writeStream(streamId, connection); |
187 | end; |
188 | |
189 | function TipTrigger:update(dt) |
190 | if self.movingId ~= nil then |
191 | local x,y,z = getTranslation(self.movingId); |
192 | local newY = math.max(y-dt*self.moveBackScale, self.moveMinY); |
193 | setTranslation(self.movingId, x, newY, z); |
194 | end; |
195 | |
196 | if self.lastMoneyChange > 0 then |
197 | self.lastMoneyChange = self.lastMoneyChange - 1; |
198 | if self.lastMoneyChange == 0 then |
199 | g_currentMission:showMoneyChange(self.moneyChangeId); |
200 | end; |
201 | end; |
202 | end; |
203 | |
204 | function TipTrigger:updateMoving(delta) |
205 | if self.movingId ~= nil and self.isServer then |
206 | local x,y,z = getTranslation(self.movingId); |
207 | local newY = math.min(y+delta*self.moveScale, self.moveMaxY); |
208 | setTranslation(self.movingId, x, newY, z); |
209 | self:raiseDirtyFlags(self.tipTriggerDirtyFlag); |
210 | end; |
211 | end; |
212 | |
213 | function TipTrigger:updateTrailerTipping(trailer, fillDelta, fillType) |
214 | if fillDelta < 0 then |
215 | if not self.forwardFillLevel then |
216 | if self.isFarmTrigger then |
217 | -- put load into storage |
218 | local siloFillType = fillType; |
219 | if fillType == Fillable.FILLTYPE_DRYGRASS then |
220 | siloFillType = Fillable.FILLTYPE_GRASS |
221 | end; |
222 | |
223 | g_currentMission:setSiloAmount(siloFillType, g_currentMission:getSiloAmount(siloFillType)- fillDelta); |
224 | |
225 | else |
226 | |
227 | -- update total amount of this fill type |
228 | local desc = Fillable.fillTypeIndexToDesc[fillType]; |
229 | desc.totalAmount = desc.totalAmount - fillDelta; |
230 | |
231 | -- increase money according to price of current fill type |
232 | local priceMultiplier = self.priceMultipliers[fillType]; |
233 | |
234 | local difficultyMultiplier = math.max(2 * (3 - g_currentMission.missionStats.difficulty), 1); -- 1 2 4 |
235 | local greatDemandMultiplier = 1; |
236 | |
237 | -- check if a great demand pertaining to this fill type / station is currently running |
238 | local greatDemand = g_currentMission.economyManager:getCurrentGreatDemand(self.stationName, fillType); |
239 | if greatDemand ~= nil then |
240 | greatDemandMultiplier = greatDemand.demandMultiplier; |
241 | end; |
242 | |
243 | local money = Fillable.fillTypeIndexToDesc[fillType].pricePerLiter * priceMultiplier * difficultyMultiplier * greatDemandMultiplier * -fillDelta; |
244 | --g_currentMission.missionStats.money = g_currentMission.missionStats.money + money; |
245 | g_currentMission:addSharedMoney(money, "harvestIncome"); |
246 | g_currentMission:addMoneyChange(money, self.moneyChangeId); |
247 | self.lastMoneyChange = 30; |
248 | |
249 | -- TOUR SPECIFIC STUFF |
250 | if g_currentMission.tourIconsBase ~= nil and g_currentMission.tourIconsBase.visible then |
251 | if self.stationName == "StationGrainElevator" and not g_currentMission.tourIconsBase.soldStuffAtGrainElevator then |
252 | g_currentMission.tourIconsBase.soldStuffAtGrainElevator = true; |
253 | end; |
254 | end; |
255 | |
256 | end; |
257 | end; |
258 | |
259 | for _, listener in pairs(self.updateEventListeners) do |
260 | listener:onUpdateEvent(self, fillDelta, fillType, trailer); |
261 | end; |
262 | |
263 | self:updateMoving(-fillDelta); |
264 | end |
265 | end |
266 | |
267 | function TipTrigger:getTipInfoForTrailer(trailer, tipReferencePointIndex) |
268 | local minDistance, bestPoint = self:getTipDistanceFromTrailer(trailer, tipReferencePointIndex); |
269 | |
270 | local isAllowed = false; |
271 | if self.acceptedFillTypes[trailer.currentFillType] then |
272 | isAllowed = true; |
273 | end |
274 | |
275 | return isAllowed, minDistance, bestPoint; |
276 | end |
277 | |
278 | function TipTrigger:getTipDistanceFromTrailer(trailer, tipReferencePointIndex) |
279 | |
280 | local minDistance = math.huge; |
281 | local bestPoint = nil; |
282 | local bestWidth = -1; |
283 | |
284 | local sx, _, sz = getWorldTranslation(self.triggerStartId); |
285 | if self.isAreaTrigger then |
286 | local ex, _, ez = getWorldTranslation(self.triggerEndId); |
287 | local dx, dz = ex-sx, ez-sz; |
288 | local length = math.sqrt(dx*dx + dz*dz); |
289 | if length > 0.00001 then |
290 | dx = dx / length; |
291 | dz = dz / length; |
292 | end |
293 | if tipReferencePointIndex ~= nil then |
294 | local trailerX, _, trailerZ = getWorldTranslation(trailer.tipReferencePoints[tipReferencePointIndex].node); |
295 | return Utils.getDistanceToRectangle2D(trailerX, trailerZ, sx, sz, dx, dz, length, self.triggerWidth), tipReferencePointIndex; |
296 | else |
297 | for i,point in pairs(trailer.tipReferencePoints) do |
298 | local trailerX, _, trailerZ = getWorldTranslation(point.node); |
299 | local distance = Utils.getDistanceToRectangle2D(trailerX, trailerZ, sx, sz, dx, dz, length, self.triggerWidth); |
300 | if point.width <= self.triggerTipWidth and point.width > bestWidth then |
301 | -- if the tip point matches the trigger better, then also accept it if the distance does not improve |
302 | if distance <= minDistance+0.001 then |
303 | bestPoint = i; |
304 | bestWidth = point.width; |
305 | minDistance = distance; |
306 | end |
307 | else |
308 | if distance < minDistance then |
309 | bestPoint = i; |
310 | minDistance = distance; |
311 | end |
312 | end |
313 | end |
314 | end |
315 | else |
316 | if tipReferencePointIndex ~= nil then |
317 | local trailerX, _, trailerZ = getWorldTranslation(trailer.tipReferencePoints[tipReferencePointIndex].node); |
318 | return Utils.vector2Length(trailerX-sx, trailerZ-sz), tipReferencePointIndex; |
319 | else |
320 | for i,point in pairs(trailer.tipReferencePoints) do |
321 | local trailerX, _, trailerZ = getWorldTranslation(point.node); |
322 | local distance = Utils.vector2Length(trailerX-sx, trailerZ-sz); |
323 | if point.width <= self.triggerTipWidth and point.width > bestWidth then |
324 | -- if the tip point matches the trigger better, then also accept it if the distance does not improve |
325 | if distance <= minDistance+0.001 then |
326 | bestPoint = i; |
327 | bestWidth = point.width; |
328 | minDistance = distance; |
329 | end |
330 | else |
331 | if distance < minDistance then |
332 | bestPoint = i; |
333 | minDistance = distance; |
334 | end |
335 | end |
336 | end |
337 | end |
338 | end |
339 | return minDistance, bestPoint; |
340 | end; |
341 | |
342 | function TipTrigger:getNoAllowedText(trailer) |
343 | if not self.suppressWarnings and trailer.currentFillType ~= Fillable.FILLTYPE_UNKNOWN and not self.acceptedFillTypes[trailer.currentFillType] then |
344 | return Fillable.fillTypeIndexToDesc[trailer.currentFillType].nameI18N .. g_i18n:getText("notAcceptedHere"); |
345 | end |
346 | return nil; |
347 | end |
348 | |
349 | function TipTrigger:addUpdateEventListener(listener) |
350 | if listener ~= nil then |
351 | self.updateEventListeners[listener] = listener; |
352 | end; |
353 | end; |
354 | |
355 | function TipTrigger:removeUpdateEventListener(listener) |
356 | if listener ~= nil then |
357 | self.updateEventListeners[listener] = nil; |
358 | end; |
359 | end; |
360 | |
361 | function TipTrigger:triggerCallback(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId) |
362 | if self.isEnabled then |
363 | if onEnter then |
364 | local trailer = g_currentMission.objectToTrailer[otherShapeId]; |
365 | if trailer ~= nil and trailer.allowTipDischarge then |
366 | if g_currentMission.trailerTipTriggers[trailer] == nil then |
367 | g_currentMission.trailerTipTriggers[trailer] = {}; |
368 | end; |
369 | table.insert(g_currentMission.trailerTipTriggers[trailer], self); |
370 | end; |
371 | elseif onLeave then |
372 | local trailer = g_currentMission.objectToTrailer[otherShapeId]; |
373 | if trailer ~= nil and trailer.allowTipDischarge then |
374 | local triggers = g_currentMission.trailerTipTriggers[trailer]; |
375 | if triggers ~= nil then |
376 | for i=1, table.getn(triggers) do |
377 | if triggers[i] == self then |
378 | table.remove(triggers, i); |
379 | if table.getn(triggers) == 0 then |
380 | g_currentMission.trailerTipTriggers[trailer] = nil; |
381 | end; |
382 | break; |
383 | end; |
384 | end; |
385 | end; |
386 | end; |
387 | end; |
388 | end; |
389 | end;
|
Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de