forked from Courseplay/courseplay
-
Notifications
You must be signed in to change notification settings - Fork 0
/
signs.lua
313 lines (266 loc) · 9.8 KB
/
signs.lua
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
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
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
courseplay.signs = {};
local deg, rad = math.deg, math.rad;
--[[ TODO
- run updateWaypointSigns() when course has been saved
]]
local signData = {
normal = { 10000, 'current', 4.5 }, -- orig height=5
start = { 500, 'current', 4.5 }, -- orig height=3
stop = { 500, 'current', 4.5 }, -- orig height=3
wait = { 1000, 'current', 4.5 }, -- orig height=3
cross = { 2000, 'crossing', 4.0 }
};
local diamondColors = {
regular = { 1.000, 0.212, 0.000, 1.000 }; -- orange
turnStart = { 0.200, 0.900, 0.000, 1.000 }; -- green
turnEnd = { 0.896, 0.000, 0.000, 1.000 }; -- red
};
function courseplay.signs:setup()
print('## Courseplay: setting up signs');
local globalRootNode = getRootNode();
self.buffer = {};
self.bufferMax = {};
self.sections = {};
self.heightPos = {};
self.protoTypes = {};
for signType,data in pairs(signData) do
self.buffer[signType] = {};
self.bufferMax[signType] = data[1];
self.sections[signType] = data[2];
self.heightPos[signType] = data[3];
local i3dNode = Utils.loadSharedI3DFile('img/signs/' .. signType .. '.i3d', courseplay.path);
local itemNode = getChildAt(i3dNode, 0);
link(globalRootNode, itemNode);
setRigidBodyType(itemNode, 'NoRigidBody');
setTranslation(itemNode, 0, 0, 0);
setVisibility(itemNode, false);
delete(i3dNode);
self.protoTypes[signType] = itemNode;
end;
end;
function courseplay.signs:addSign(vehicle, signType, x, z, rotX, rotY, insertIndex, distanceToNext, diamondColor)
signType = signType or 'normal';
local sign;
local signFromBuffer = {};
local receivedSignFromBuffer = courseplay.utils.table.move(self.buffer[signType], signFromBuffer);
if receivedSignFromBuffer then
sign = signFromBuffer[1].sign;
else
sign = clone(self.protoTypes[signType], true);
end;
self:setTranslation(sign, signType, x, z);
rotX = rotX or 0;
rotY = rotY or 0;
setRotation(sign, rad(rotX), rad(rotY), 0);
if signType == 'normal' or signType == 'start' or signType == 'wait' then
if signType == 'start' or signType == 'wait' then
local signPart = getChildAt(sign, 1);
setRotation(signPart, rad(-rotX), 0, 0);
end;
if distanceToNext and distanceToNext > 0.01 then
self:setWaypointSignLine(sign, distanceToNext, true);
else
self:setWaypointSignLine(sign, nil, false);
end;
end;
setVisibility(sign, true);
local signData = { type = signType, sign = sign, posX = x, posZ = z, rotY = rotY };
if diamondColor and signType ~= 'cross' then
self:setSignColor(signData, diamondColor);
end;
local section = self.sections[signType];
insertIndex = insertIndex or (#vehicle.cp.signs[section] + 1);
table.insert(vehicle.cp.signs[section], insertIndex, signData);
end;
function courseplay.signs:moveToBuffer(vehicle, vehicleIndex, signData)
-- self = courseplay.signs
local signType = signData.type;
local section = self.sections[signType];
if #self.buffer[signType] < self.bufferMax[signType] then
setVisibility(signData.sign, false);
courseplay.utils.table.move(vehicle.cp.signs[section], self.buffer[signType], vehicleIndex);
else
self:deleteSign(signData.sign);
vehicle.cp.signs[section][vehicleIndex] = nil;
end;
end;
function courseplay.signs:setTranslation(sign, signType, x, z)
local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, 300, z);
setTranslation(sign, x, terrainHeight + self.heightPos[signType], z);
end;
function courseplay.signs:changeSignType(vehicle, vehicleIndex, oldType, newType)
local section = self.sections[oldType];
local signData = vehicle.cp.signs[section][vehicleIndex];
self:moveToBuffer(vehicle, vehicleIndex, signData);
self:addSign(vehicle, newType, signData.posX, signData.posZ, signData.rotX, signData.rotY, vehicleIndex);
end;
function courseplay.signs:setWaypointSignLine(sign, distance, vis)
local line = getChildAt(sign, 0);
if line ~= 0 then
if vis and distance ~= nil then
setScale(line, 1, 1, distance);
end;
if vis ~= nil then
setVisibility(line, vis);
end;
end;
end;
function courseplay.signs:updateWaypointSigns(vehicle, section)
section = section or 'all'; --section: 'all', 'crossing', 'current'
vehicle.cp.numWaitPoints = 0;
vehicle.cp.numCrossingPoints = 0;
vehicle.maxnumber = #vehicle.Waypoints;
if section == 'all' or section == 'current' then
local neededPoints = vehicle.maxnumber;
--move not needed ones to buffer
if #vehicle.cp.signs.current > neededPoints then
for j=#vehicle.cp.signs.current, neededPoints+1, -1 do --go backwards so we can safely move/delete
local signData = vehicle.cp.signs.current[j];
self:moveToBuffer(vehicle, j, signData);
end;
end;
local np;
for i,wp in pairs(vehicle.Waypoints) do
local neededSignType = 'normal';
if i == 1 then
neededSignType = 'start';
elseif i == vehicle.maxnumber then
neededSignType = 'stop';
elseif wp.wait then
neededSignType = 'wait';
end;
-- direction + angle
if wp.rotX == nil then wp.rotX = 0; end;
if wp.cy == nil or wp.cy == 0 then
wp.cy = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, wp.cx, 0, wp.cz);
end;
if i < vehicle.maxnumber then
np = vehicle.Waypoints[i + 1];
if np.cy == nil or np.cy == 0 then
np.cy = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, np.cx, 0, np.cz);
end;
wp.dirX, wp.dirY, wp.dirZ, wp.distToNextPoint = courseplay:getWorldDirection(wp.cx, wp.cy, wp.cz, np.cx, np.cy, np.cz);
if wp.distToNextPoint <= 0.01 and i > 1 then
local pp = vehicle.Waypoints[i - 1];
wp.dirX, wp.dirY, wp.dirZ = pp.dirX, pp.dirY, pp.dirZ;
end;
wp.rotY = Utils.getYRotationFromDirection(wp.dirX, wp.dirZ);
wp.angle = deg(wp.rotY);
local dy = np.cy - wp.cy;
local dist2D = Utils.vector2Length(np.cx - wp.cx, np.cz - wp.cz);
wp.rotX = -Utils.getYRotationFromDirection(dy, dist2D);
else
local pp = vehicle.Waypoints[i - 1];
wp.dirX, wp.dirY, wp.dirZ, wp.distToNextPoint = pp.dirX, pp.dirY, pp.dirZ, 0;
wp.rotX = 0;
wp.rotY = pp.rotY;
end;
local diamondColor = 'regular';
if wp.turnStart then
diamondColor = 'turnStart';
elseif wp.turnEnd then
diamondColor = 'turnEnd';
end;
local existingSignData = vehicle.cp.signs.current[i];
if existingSignData ~= nil then
if existingSignData.type == neededSignType then
self:setTranslation(existingSignData.sign, existingSignData.type, wp.cx, wp.cz);
if wp.rotX and wp.rotY then
setRotation(existingSignData.sign, wp.rotX, wp.rotY, 0);
if neededSignType == 'normal' or neededSignType == 'start' or neededSignType == 'wait' then
if neededSignType == 'start' or neededSignType == 'wait' then
local signPart = getChildAt(existingSignData.sign, 1);
setRotation(signPart, -wp.rotX, 0, 0);
end;
self:setWaypointSignLine(existingSignData.sign, wp.distToNextPoint, true);
end;
if neededSignType ~= 'cross' then
self:setSignColor(existingSignData, diamondColor);
end;
end;
else
self:moveToBuffer(vehicle, i, existingSignData);
self:addSign(vehicle, neededSignType, wp.cx, wp.cz, deg(wp.rotX), wp.angle, i, wp.distToNextPoint, diamondColor);
end;
else
self:addSign(vehicle, neededSignType, wp.cx, wp.cz, deg(wp.rotX), wp.angle, i, wp.distToNextPoint, diamondColor);
end;
if wp.wait then
vehicle.cp.numWaitPoints = vehicle.cp.numWaitPoints + 1;
end;
if wp.crossing then
vehicle.cp.numCrossingPoints = vehicle.cp.numCrossingPoints + 1;
end;
end;
end;
if section == 'all' or section == 'crossing' then
--TODO: adapt to MP
if g_currentMission.cp_courses ~= nil then -- ??? MP Ready ???
if #vehicle.cp.signs.crossing > 0 then
for i=#vehicle.cp.signs.crossing, 1, -1 do --go backwards so we can safely move/delete
local signData = vehicle.cp.signs.crossing[i];
self:moveToBuffer(vehicle, i, signData);
end;
end;
for i,course in pairs(g_currentMission.cp_courses) do
for j,wp in pairs(course.waypoints) do
if wp.crossing then
self:addSign(vehicle, 'cross', wp.cx, wp.cz, nil, wp.angle);
end;
end;
end;
end;
end;
self:setSignsVisibility(vehicle);
end;
function courseplay.signs:setSignColor(signData, colorName)
if signData.type ~= 'cross' and (signData.color == nil or signData.color ~= colorName) then
local x,y,z,w = unpack(diamondColors[colorName]);
-- print(('setSignColor (%q): sign=%s, x=%.3f, y=%.3f, z=%.3f, w=%d'):format(color, tostring(sign), x, y, z, w));
setShaderParameter(signData.sign, 'diffuseColor', x,y,z,w, false);
signData.color = colorName;
end;
end;
function courseplay.signs:deleteSign(sign)
unlink(sign);
delete(sign);
end;
function courseplay.signs:setSignsVisibility(vehicle, forceHide)
if vehicle.cp == nil or vehicle.cp.signs == nil or (#vehicle.cp.signs.current == 0 and #vehicle.cp.signs.crossing == 0) then
return;
end;
local mode = vehicle.cp.visualWaypointsMode;
-- waypointModes: 1 = Start and end, 2 = Start and end [without crossing], 3 = all own waypoints [with crossing], 4 = none
local numSigns = #vehicle.cp.signs.current;
for k,signData in pairs(vehicle.cp.signs.current) do
local vis = false;
if mode == 1 or mode == 2 then
vis = k <= 3 or k >= (numSigns - 2) or signData.type == 'wait';
elseif mode == 3 then
vis = true;
elseif mode == 4 then
vis = false;
end;
if vehicle.cp.isRecording then
vis = true;
elseif forceHide or not vehicle.isEntered then
vis = false;
end;
setVisibility(signData.sign, vis);
if signData.type == 'wait' then
local line = getChildAt(signData.sign, 0);
if mode == 1 or mode == 2 then
setVisibility(line, k <= 2 or k >= (numSigns - 2));
elseif vis then
setVisibility(line, true);
end;
end;
end;
for k,signData in pairs(vehicle.cp.signs.crossing) do
local vis = mode == 1 or mode == 3;
if forceHide or not vehicle.isEntered then
vis = false;
end;
setVisibility(signData.sign, vis);
end;
end;