author | darkvater |
Wed, 08 Sep 2004 20:54:56 +0000 | |
changeset 187 | f790a76cc828 |
parent 164 | 0cbdf3c9bde1 |
child 193 | 0a7025304867 |
permissions | -rw-r--r-- |
0 | 1 |
#include "stdafx.h" |
2 |
#include "ttd.h" |
|
3 |
#include "vehicle.h" |
|
4 |
#include "engine.h" |
|
5 |
#include "command.h" |
|
6 |
#include "station.h" |
|
7 |
#include "news.h" |
|
8 |
#include "gfx.h" |
|
9 |
#include "pathfind.h" |
|
10 |
#include "player.h" |
|
11 |
||
12 |
void ShowRoadVehViewWindow(Vehicle *v); |
|
13 |
||
14 |
static const uint16 _roadveh_images[63] = { |
|
15 |
0xCD4, 0xCDC, 0xCE4, 0xCEC, 0xCF4, 0xCFC, 0xD0C, 0xD14, |
|
16 |
0xD24, 0xD1C, 0xD2C, 0xD04, 0xD1C, 0xD24, 0xD6C, 0xD74, |
|
17 |
0xD7C, 0xC14, 0xC1C, 0xC24, 0xC2C, 0xC34, 0xC3C, 0xC4C, |
|
18 |
0xC54, 0xC64, 0xC5C, 0xC6C, 0xC44, 0xC5C, 0xC64, 0xCAC, |
|
19 |
0xCB4, 0xCBC, 0xD94, 0xD9C, 0xDA4, 0xDAC, 0xDB4, 0xDBC, |
|
20 |
0xDCC, 0xDD4, 0xDE4, 0xDDC, 0xDEC, 0xDC4, 0xDDC, 0xDE4, |
|
21 |
0xE2C, 0xE34, 0xE3C, 0xC14, 0xC1C, 0xC2C, 0xC3C, 0xC4C, |
|
22 |
0xC5C, 0xC64, 0xC6C, 0xC74, 0xC84, 0xC94, 0xCA4 |
|
23 |
}; |
|
24 |
||
25 |
||
26 |
static const uint16 _roadveh_full_adder[63] = { |
|
27 |
0, 88, 0, 0, 0, 0, 48, 48, |
|
28 |
48, 48, 0, 0, 64, 64, 0, 16, |
|
29 |
16, 0, 88, 0, 0, 0, 0, 48, |
|
30 |
48, 48, 48, 0, 0, 64, 64, 0, |
|
31 |
16, 16, 0, 88, 0, 0, 0, 0, |
|
32 |
48, 48, 48, 48, 0, 0, 64, 64, |
|
33 |
0, 16, 16, 0, 8, 8, 8, 8, |
|
34 |
0, 0, 0, 8, 8, 8, 8 |
|
35 |
}; |
|
36 |
||
37 |
static const byte _roadveh_spritenum[88] = { |
|
38 |
0, 17, 17, 34, 51, 51, 51, 1, |
|
39 |
18, 35, 2, 19, 36, 57, 57, 57, |
|
40 |
3, 20, 37, 4, 21, 38, 5, 22, |
|
41 |
||
42 |
39, 6, 23, 40, 7, 24, 41, 8, |
|
43 |
25, 42, 9, 26, 43, 10, 27, 44, |
|
44 |
11, 28, 45, 12, 29, 46, 13, 30, |
|
45 |
47, 14, 31, 48, 15, 32, 49, 16, |
|
46 |
||
47 |
33, 50, 52, 52, 52, 53, 53, 53, |
|
48 |
54, 54, 54, 55, 55, 55, 56, 56, |
|
49 |
56, 58, 58, 58, 59, 59, 59, 60, |
|
50 |
60, 60, 61, 61, 61, 62, 62, 62, |
|
51 |
}; |
|
52 |
||
53 |
const byte _roadveh_speed[88] = { |
|
54 |
112, 176, 224, 255, 112, 192, 240, 96, |
|
55 |
176, 224, 96, 176, 224, 96, 176, 224, |
|
56 |
96, 176, 224, 96, 176, 224, 96, 176, |
|
57 |
224, 96, 176, 224, 96, 176, 224, 96, |
|
58 |
176, 224, 96, 176, 224, 96, 176, 224, |
|
59 |
96, 176, 224, 96, 176, 224, 96, 176, |
|
60 |
224, 96, 176, 224, 96, 176, 224, 96, |
|
61 |
176, 224, 96, 176, 224, 96, 176, 224, |
|
62 |
96, 176, 224, 96, 176, 224, 96, 176, |
|
63 |
224, 96, 176, 224, 96, 176, 224, 96, |
|
64 |
176, 224, 96, 176, 224, 96, 176, 224, |
|
65 |
}; |
|
66 |
||
67 |
||
68 |
const byte _roadveh_runningcost[88] = { |
|
69 |
91, 128, 178, 240, 91, 171, 240, 90, |
|
70 |
168, 240, 90, 168, 240, 90, 168, 240, |
|
71 |
90, 168, 240, 90, 168, 240, 90, 168, |
|
72 |
240, 90, 168, 240, 90, 168, 240, 90, |
|
73 |
168, 240, 90, 168, 240, 90, 168, 240, |
|
74 |
90, 168, 240, 90, 168, 240, 90, 168, |
|
75 |
240, 90, 168, 240, 90, 168, 240, 90, |
|
76 |
168, 240, 90, 168, 240, 90, 168, 240, |
|
77 |
90, 168, 240, 90, 168, 240, 90, 168, |
|
78 |
240, 90, 168, 240, 90, 168, 240, 90, |
|
79 |
168, 240, 90, 168, 240, 90, 168, 240, |
|
80 |
}; |
|
81 |
||
82 |
||
83 |
const byte _roadveh_capacity[88] = { |
|
84 |
31, 35, 37, 40, 30, 35, 38, 20, |
|
85 |
25, 28, 22, 28, 30, 22, 28, 30, |
|
86 |
21, 25, 27, 14, 16, 18, 14, 16, |
|
87 |
18, 20, 25, 30, 20, 22, 24, 22, |
|
88 |
25, 27, 15, 18, 20, 12, 15, 16, |
|
89 |
17, 20, 22, 15, 18, 20, 22, 25, |
|
90 |
27, 21, 25, 27, 18, 20, 23, 17, |
|
91 |
19, 22, 17, 19, 22, 17, 19, 22, |
|
92 |
17, 19, 22, 17, 19, 22, 17, 19, |
|
93 |
22, 17, 19, 22, 17, 19, 22, 17, |
|
94 |
19, 22, 17, 19, 22, 17, 19, 22, |
|
95 |
}; |
|
96 |
||
97 |
const byte _roadveh_cargo_type[88] = { |
|
98 |
0, 0, 0, 0, 0, 0, 0, 1, |
|
99 |
1, 1, 2, 2, 2, 2, 2, 2, |
|
100 |
3, 3, 3, 4, 4, 4, 5, 5, |
|
101 |
5, 6, 6, 6, 7, 7, 7, 8, |
|
102 |
8, 8, 9, 9, 9,10,10,10, |
|
103 |
11,11,11, 9, 9, 9, 8, 8, |
|
104 |
8, 9, 9, 9, 4, 4, 4, 1, |
|
105 |
1, 1, 1, 1, 1, 7, 7, 7, |
|
106 |
8, 8, 8, 6, 6, 6, 3, 3, |
|
107 |
3, 5, 5, 5, 4, 4, 4,11, |
|
108 |
11,11,10,10,10, 9, 9, 9, |
|
109 |
}; |
|
110 |
||
111 |
const byte _roadveh_price[88] = { |
|
112 |
120,140,150,160,120,140,160,108, |
|
113 |
128,138,115,135,145,115,135,145, |
|
114 |
110,140,150,105,130,140,107,130, |
|
115 |
140,114,133,143,118,137,147,121, |
|
116 |
140,150,112,135,145,145,170,180, |
|
117 |
112,134,144,112,135,145,121,140, |
|
118 |
150,111,141,151,118,148,158,117, |
|
119 |
147,157,117,147,157,117,147,157, |
|
120 |
117,147,157,117,147,157,117,147, |
|
121 |
157,117,147,157,117,147,157,117, |
|
122 |
147,157,117,147,157,117,147,157, |
|
123 |
}; |
|
124 |
||
125 |
static const byte _road_engine_sounds[88] = { |
|
126 |
23, 26, 25, 25, 60, 62, 60, 23, |
|
127 |
23, 23, 23, 23, 23, 62, 60, 62, |
|
128 |
23, 23, 23, 23, 23, 23, 23, 23, |
|
129 |
23, 23, 23, 23, 23, 23, 23, 23, |
|
130 |
23, 23, 23, 23, 23, 23, 23, 23, |
|
131 |
23, 23, 23, 23, 23, 23, 23, 23, |
|
132 |
23, 23, 23, 23, 23, 23, 23, 23, |
|
133 |
23, 23, 63, 64, 63, 64, 63, 64, |
|
134 |
63, 64, 63, 64, 63, 64, 63, 64, |
|
135 |
63, 64, 63, 64, 63, 64, 63, 64, |
|
136 |
63, 64, 63, 64, 63, 64, 63, 64, |
|
137 |
}; |
|
138 |
||
139 |
static const uint16 _road_veh_fp_ax_or[4] = { |
|
140 |
0x100,0x200,1,2, |
|
141 |
}; |
|
142 |
||
143 |
static const uint16 _road_veh_fp_ax_and[4] = { |
|
144 |
0x1009, 0x16, 0x520, 0x2A00 |
|
145 |
}; |
|
146 |
||
147 |
static const byte _road_reverse_table[4] = { |
|
148 |
6, 7, 14, 15 |
|
149 |
}; |
|
150 |
||
151 |
static const uint16 _road_pf_table_3[4] = { |
|
152 |
0x910, 0x1600, 0x2005, 0x2A |
|
153 |
}; |
|
154 |
||
155 |
int GetRoadVehImage(Vehicle *v, byte direction) |
|
156 |
{ |
|
157 |
int img = v->spritenum; |
|
158 |
int image; |
|
159 |
||
160 |
#ifdef ROADVEH_CUSTOM_SPRITES // TODO --pasky |
|
161 |
if (is_custom_sprite(img)) { |
|
162 |
image = GetCustomVehicleSprite(v, direction); |
|
163 |
if (image) return image; |
|
164 |
img = _engine_original_sprites[v->engine_type]; |
|
165 |
} |
|
166 |
#endif |
|
167 |
||
168 |
image = direction + _roadveh_images[img]; |
|
169 |
if (v->cargo_count >= (v->cargo_cap >> 1)) |
|
170 |
image += _roadveh_full_adder[img]; |
|
171 |
return image; |
|
172 |
} |
|
173 |
||
174 |
void DrawRoadVehEngine(int x, int y, int engine, uint32 image_ormod) |
|
175 |
{ |
|
176 |
DrawSprite((6 + _roadveh_images[_roadveh_spritenum[engine - ROAD_ENGINES_INDEX]]) | image_ormod, x, y); |
|
177 |
} |
|
178 |
||
179 |
void DrawRoadVehEngineInfo(int engine, int x, int y, int maxw) |
|
180 |
{ |
|
181 |
engine -= ROAD_ENGINES_INDEX; |
|
182 |
||
183 |
SET_DPARAM32(0, ((_price.roadveh_base >> 3) * _roadveh_price[engine]) >> 5); |
|
184 |
SET_DPARAM16(1, _roadveh_speed[engine] * 10 >> 5); |
|
185 |
SET_DPARAM32(2, _roadveh_runningcost[engine] * _price.roadveh_running >> 8); |
|
186 |
||
187 |
SET_DPARAM16(4, _roadveh_capacity[engine]); |
|
188 |
SET_DPARAM16(3, _cargoc.names_long_p[_roadveh_cargo_type[engine]]); |
|
189 |
||
190 |
DrawStringMultiCenter(x, y, STR_902A_COST_SPEED_RUNNING_COST, maxw); |
|
191 |
} |
|
192 |
||
193 |
static int32 EstimateRoadVehCost(byte engine_type) |
|
194 |
{ |
|
195 |
return ((_price.roadveh_base >> 3) * _roadveh_price[engine_type - ROAD_ENGINES_INDEX]) >> 5; |
|
196 |
} |
|
197 |
||
198 |
int32 CmdBuildRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
|
199 |
{ |
|
200 |
int32 cost; |
|
201 |
Vehicle *v; |
|
202 |
byte unit_num; |
|
203 |
uint tile = TILE_FROM_XY(x,y); |
|
204 |
Engine *e; |
|
205 |
||
206 |
SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
|
207 |
||
208 |
cost = EstimateRoadVehCost(p1); |
|
209 |
if (flags & DC_QUERY_COST) |
|
210 |
return cost; |
|
211 |
||
212 |
v = AllocateVehicle(); |
|
213 |
if (v == NULL || _ptr_to_next_order >= endof(_order_array)) |
|
214 |
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
|
215 |
||
216 |
/* find the first free roadveh id */ |
|
217 |
unit_num = GetFreeUnitNumber(VEH_Road); |
|
218 |
if (unit_num > _patches.max_roadveh) |
|
219 |
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
|
220 |
||
221 |
if (flags & DC_EXEC) { |
|
222 |
v->unitnumber = unit_num; |
|
223 |
v->direction = 0; |
|
224 |
v->owner = _current_player; |
|
225 |
||
226 |
v->tile = tile; |
|
227 |
x = GET_TILE_X(tile)*16 + 8; |
|
228 |
y = GET_TILE_Y(tile)*16 + 8; |
|
229 |
v->x_pos = x; |
|
230 |
v->y_pos = y; |
|
231 |
v->z_pos = GetSlopeZ(x,y); |
|
232 |
v->z_height = 6; |
|
233 |
||
234 |
v->u.road.state = 254; |
|
235 |
v->vehstatus = VS_HIDDEN|VS_STOPPED|VS_DEFPAL; |
|
236 |
||
237 |
v->spritenum = _roadveh_spritenum[p1 - ROAD_ENGINES_INDEX]; |
|
238 |
v->cargo_type = _roadveh_cargo_type[p1 - ROAD_ENGINES_INDEX]; |
|
239 |
v->cargo_cap = _roadveh_capacity[p1 - ROAD_ENGINES_INDEX]; |
|
240 |
// v->cargo_count = 0; |
|
241 |
v->value = cost; |
|
242 |
// v->day_counter = 0; |
|
243 |
// v->next_order_param = v->next_order = 0; |
|
244 |
// v->load_unload_time_rem = 0; |
|
245 |
// v->progress = 0; |
|
246 |
||
247 |
// v->u.road.unk2 = 0; |
|
248 |
// v->u.road.overtaking = 0; |
|
249 |
||
250 |
v->last_station_visited = 0xFF; |
|
251 |
v->max_speed = _roadveh_speed[p1 - ROAD_ENGINES_INDEX]; |
|
252 |
v->engine_type = (byte)p1; |
|
253 |
||
254 |
e = &_engines[p1]; |
|
255 |
v->reliability = e->reliability; |
|
256 |
v->reliability_spd_dec = e->reliability_spd_dec; |
|
257 |
v->max_age = e->lifelength * 366; |
|
258 |
_new_roadveh_id = v->index; |
|
259 |
||
260 |
v->string_id = STR_SV_ROADVEH_NAME; |
|
261 |
*(v->schedule_ptr = _ptr_to_next_order++) = 0; |
|
262 |
||
263 |
v->service_interval = _patches.servint_roadveh; |
|
264 |
||
265 |
v->date_of_last_service = _date; |
|
266 |
v->build_year = _cur_year; |
|
267 |
||
268 |
v->type = VEH_Road; |
|
269 |
v->cur_image = 0xC15; |
|
270 |
||
271 |
VehiclePositionChanged(v); |
|
272 |
||
273 |
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
|
164
0cbdf3c9bde1
(svn r165) -Feature: Option to sort vehicles in vehicle-list window by different criteria. Total independent sort for all types and players. Periodic resort of list every 10 TTD days. Thank you for your graphical inspiration follow and buxo (since none of you provided any code).
darkvater
parents:
159
diff
changeset
|
274 |
_vehicle_sort_dirty[VEHROAD] = true; // build a new bus/truck |
0 | 275 |
InvalidateWindow(WC_ROADVEH_LIST, v->owner); |
276 |
InvalidateWindow(WC_COMPANY, v->owner); |
|
277 |
} |
|
278 |
||
279 |
return cost; |
|
280 |
} |
|
281 |
||
282 |
// p1 = vehicle |
|
283 |
int32 CmdStartStopRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
|
284 |
{ |
|
285 |
Vehicle *v; |
|
286 |
||
287 |
v = &_vehicles[p1]; |
|
288 |
||
289 |
if (v->type != VEH_Road || !CheckOwnership(v->owner)) |
|
290 |
return CMD_ERROR; |
|
291 |
||
292 |
if (flags & DC_EXEC) { |
|
293 |
v->vehstatus ^= VS_STOPPED; |
|
294 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
295 |
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
|
296 |
} |
|
297 |
||
298 |
return 0; |
|
299 |
} |
|
300 |
||
301 |
int32 CmdSellRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
|
302 |
{ |
|
303 |
Vehicle *v; |
|
304 |
||
305 |
SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
|
306 |
||
307 |
v = &_vehicles[p1]; |
|
308 |
||
309 |
if (v->type != VEH_Road || !CheckOwnership(v->owner)) |
|
310 |
return CMD_ERROR; |
|
311 |
||
312 |
if (!IsRoadDepotTile(v->tile) || v->u.road.state != 254 || !(v->vehstatus&VS_STOPPED)) |
|
313 |
return_cmd_error(STR_9013_MUST_BE_STOPPED_INSIDE); |
|
314 |
||
315 |
if (flags & DC_EXEC) { |
|
316 |
// Invalidate depot |
|
317 |
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
|
164
0cbdf3c9bde1
(svn r165) -Feature: Option to sort vehicles in vehicle-list window by different criteria. Total independent sort for all types and players. Periodic resort of list every 10 TTD days. Thank you for your graphical inspiration follow and buxo (since none of you provided any code).
darkvater
parents:
159
diff
changeset
|
318 |
_vehicle_sort_dirty[VEHROAD] = true; // sell a bus/truck |
0 | 319 |
InvalidateWindow(WC_ROADVEH_LIST, v->owner); |
320 |
InvalidateWindow(WC_COMPANY, v->owner); |
|
321 |
DeleteWindowById(WC_VEHICLE_VIEW, v->index); |
|
322 |
DeleteVehicle(v); |
|
323 |
} |
|
324 |
||
325 |
return -(int32)v->value; |
|
326 |
} |
|
327 |
||
328 |
typedef struct RoadFindDepotData { |
|
329 |
uint best_length; |
|
330 |
uint tile; |
|
331 |
byte owner; |
|
332 |
} RoadFindDepotData; |
|
333 |
||
334 |
||
335 |
static const TileIndexDiff _road_find_sig_dir_mod[4] = { |
|
336 |
TILE_XY(-1,0), |
|
337 |
TILE_XY(0,1), |
|
338 |
TILE_XY(1,0), |
|
339 |
TILE_XY(0,-1), |
|
340 |
}; |
|
341 |
||
342 |
static const byte _road_pf_directions[16] = { |
|
343 |
0, 1, 0, 1, 2, 1, 255, 255, |
|
344 |
2, 3, 3, 2, 3, 0, 255, 255, |
|
345 |
}; |
|
346 |
||
347 |
static bool EnumRoadSignalFindDepot(uint tile, RoadFindDepotData *rfdd, int track, uint length, byte *state) |
|
348 |
{ |
|
349 |
tile += _road_find_sig_dir_mod[_road_pf_directions[track]]; |
|
350 |
||
351 |
if (IS_TILETYPE(tile, MP_STREET) && |
|
352 |
(_map5[tile] & 0xF0) == 0x20 && |
|
353 |
_map_owner[tile] == rfdd->owner) { |
|
354 |
||
355 |
if (length < rfdd->best_length) { |
|
356 |
rfdd->best_length = length; |
|
357 |
rfdd->tile = tile; |
|
358 |
} |
|
359 |
} |
|
360 |
return false; |
|
361 |
} |
|
362 |
||
363 |
static int FindClosestRoadDepot(Vehicle *v) |
|
364 |
{ |
|
365 |
uint tile = v->tile; |
|
366 |
int i; |
|
367 |
RoadFindDepotData rfdd; |
|
368 |
||
369 |
if (v->u.road.state == 255) { tile = GetVehicleOutOfTunnelTile(v); } |
|
370 |
||
371 |
rfdd.owner = v->owner; |
|
372 |
rfdd.best_length = (uint)-1; |
|
373 |
||
374 |
/* search in all directions */ |
|
375 |
for(i=0; i!=4; i++) |
|
159
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
376 |
FollowTrack(tile, 0x2000 | TRANSPORT_ROAD, i, (TPFEnumProc*)EnumRoadSignalFindDepot, NULL, &rfdd); |
0 | 377 |
|
378 |
if (rfdd.best_length == (uint)-1) |
|
379 |
return -1; |
|
380 |
||
381 |
return GetDepotByTile(rfdd.tile); |
|
382 |
} |
|
383 |
||
384 |
int32 CmdSendRoadVehToDepot(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
|
385 |
{ |
|
386 |
Vehicle *v = &_vehicles[p1]; |
|
387 |
int depot; |
|
388 |
||
389 |
if (v->type != VEH_Road || !CheckOwnership(v->owner)) |
|
390 |
return CMD_ERROR; |
|
391 |
||
392 |
if ((v->next_order & OT_MASK) == OT_GOTO_DEPOT) { |
|
393 |
if (flags & DC_EXEC) { |
|
394 |
if (v->next_order & OF_UNLOAD) |
|
395 |
v->cur_order_index++; |
|
396 |
v->next_order = OT_DUMMY; |
|
397 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
398 |
} |
|
399 |
return 0; |
|
400 |
} |
|
401 |
||
402 |
depot = FindClosestRoadDepot(v); |
|
403 |
if (depot < 0) |
|
404 |
return_cmd_error(STR_9019_UNABLE_TO_FIND_LOCAL_DEPOT); |
|
405 |
||
406 |
if (flags & DC_EXEC) { |
|
407 |
v->next_order = OF_NON_STOP | OF_FULL_LOAD | OT_GOTO_DEPOT; |
|
408 |
v->next_order_param = (byte)depot; |
|
409 |
v->dest_tile = _depots[depot].xy; |
|
410 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
411 |
} |
|
412 |
||
413 |
return 0; |
|
414 |
} |
|
415 |
||
416 |
int32 CmdTurnRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
|
417 |
{ |
|
418 |
Vehicle *v; |
|
419 |
||
420 |
v = &_vehicles[p1]; |
|
421 |
||
422 |
if (v->type != VEH_Road || !CheckOwnership(v->owner)) |
|
423 |
return CMD_ERROR; |
|
424 |
||
425 |
if (v->vehstatus & (VS_HIDDEN|VS_STOPPED) || |
|
426 |
v->u.road.crashed_ctr != 0 || |
|
427 |
v->breakdown_ctr != 0 || |
|
428 |
v->u.road.overtaking != 0 || |
|
429 |
v->cur_speed < 5) { |
|
430 |
_error_message = STR_EMPTY; |
|
431 |
return CMD_ERROR; |
|
432 |
} |
|
433 |
||
434 |
if (flags & DC_EXEC) { |
|
435 |
v->u.road.reverse_ctr = 180; |
|
436 |
} |
|
437 |
||
438 |
return 0; |
|
439 |
} |
|
440 |
||
441 |
int32 CmdChangeRoadVehServiceInt(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
|
442 |
{ |
|
443 |
Vehicle *v; |
|
444 |
||
445 |
v = &_vehicles[p1]; |
|
446 |
||
447 |
if (v->type != VEH_Road || !CheckOwnership(v->owner)) |
|
448 |
return CMD_ERROR; |
|
449 |
||
450 |
if (flags & DC_EXEC) { |
|
451 |
v->service_interval = (uint16)p2; |
|
452 |
InvalidateWindowWidget(WC_VEHICLE_DETAILS, v->index, 7); |
|
453 |
} |
|
454 |
||
455 |
return 0; |
|
456 |
} |
|
457 |
||
458 |
||
459 |
static void MarkRoadVehDirty(Vehicle *v) |
|
460 |
{ |
|
461 |
v->cur_image = GetRoadVehImage(v, v->direction); |
|
462 |
MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1); |
|
463 |
} |
|
464 |
||
465 |
static void UpdateRoadVehDeltaXY(Vehicle *v) |
|
466 |
{ |
|
467 |
#define MKIT(a,b,c,d) ((a&0xFF)<<24) | ((b&0xFF)<<16) | ((c&0xFF)<<8) | ((d&0xFF)<<0) |
|
468 |
static const uint32 _delta_xy_table[8] = { |
|
469 |
MKIT(3, 3, -1, -1), |
|
470 |
MKIT(3, 7, -1, -3), |
|
471 |
MKIT(3, 3, -1, -1), |
|
472 |
MKIT(7, 3, -3, -1), |
|
473 |
MKIT(3, 3, -1, -1), |
|
474 |
MKIT(3, 7, -1, -3), |
|
475 |
MKIT(3, 3, -1, -1), |
|
476 |
MKIT(7, 3, -3, -1), |
|
477 |
}; |
|
478 |
#undef MKIT |
|
479 |
uint32 x = _delta_xy_table[v->direction]; |
|
480 |
v->x_offs = (byte)x; |
|
481 |
v->y_offs = (byte)(x>>=8); |
|
482 |
v->sprite_width = (byte)(x>>=8); |
|
483 |
v->sprite_height = (byte)(x>>=8); |
|
484 |
} |
|
485 |
||
486 |
static void ClearCrashedStation(Vehicle *v) |
|
487 |
{ |
|
488 |
uint tile = v->tile; |
|
489 |
Station *st = DEREF_STATION(_map2[tile]); |
|
490 |
byte *b, bb; |
|
491 |
||
492 |
b = (_map5[tile] >= 0x47) ? &st->bus_stop_status : &st->truck_stop_status; |
|
493 |
||
494 |
bb = *b; |
|
495 |
||
496 |
// mark station as not busy |
|
497 |
bb &= ~0x80; |
|
498 |
||
499 |
// free parking bay |
|
500 |
bb |= (v->u.road.state&0x02)?2:1; |
|
501 |
||
502 |
*b = bb; |
|
503 |
} |
|
504 |
||
505 |
static void RoadVehDelete(Vehicle *v) |
|
506 |
{ |
|
507 |
DeleteWindowById(WC_VEHICLE_VIEW, v->index); |
|
508 |
InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
|
509 |
||
164
0cbdf3c9bde1
(svn r165) -Feature: Option to sort vehicles in vehicle-list window by different criteria. Total independent sort for all types and players. Periodic resort of list every 10 TTD days. Thank you for your graphical inspiration follow and buxo (since none of you provided any code).
darkvater
parents:
159
diff
changeset
|
510 |
_vehicle_sort_dirty[VEHROAD] = true; // delete bus/truck (eg. crash for example) |
0 | 511 |
InvalidateWindow(WC_ROADVEH_LIST, v->owner); |
512 |
InvalidateWindow(WC_COMPANY, v->owner); |
|
513 |
||
514 |
if(IS_TILETYPE(v->tile, MP_STATION)) |
|
515 |
ClearCrashedStation(v); |
|
516 |
||
517 |
BeginVehicleMove(v); |
|
518 |
EndVehicleMove(v); |
|
519 |
||
520 |
DeleteVehicle(v); |
|
521 |
} |
|
522 |
||
523 |
static byte SetRoadVehPosition(Vehicle *v, int x, int y) |
|
524 |
{ |
|
525 |
byte new_z, old_z; |
|
526 |
||
527 |
// need this hint so it returns the right z coordinate on bridges. |
|
528 |
_get_z_hint = v->z_pos; |
|
529 |
new_z = GetSlopeZ(v->x_pos=x, v->y_pos=y); |
|
530 |
_get_z_hint = 0; |
|
531 |
||
532 |
old_z = v->z_pos; |
|
533 |
v->z_pos = new_z; |
|
534 |
||
535 |
VehiclePositionChanged(v); |
|
536 |
EndVehicleMove(v); |
|
537 |
return old_z; |
|
538 |
} |
|
539 |
||
540 |
static void RoadVehSetRandomDirection(Vehicle *v) |
|
541 |
{ |
|
542 |
static const int8 _turn_prob[4] = { -1, 0, 0, 1 }; |
|
543 |
uint32 r = Random(); |
|
544 |
v->direction = (v->direction+_turn_prob[r&3])&7; |
|
545 |
BeginVehicleMove(v); |
|
546 |
UpdateRoadVehDeltaXY(v); |
|
547 |
v->cur_image = GetRoadVehImage(v, v->direction); |
|
548 |
SetRoadVehPosition(v, v->x_pos, v->y_pos); |
|
549 |
} |
|
550 |
||
551 |
static void RoadVehIsCrashed(Vehicle *v) |
|
552 |
{ |
|
553 |
v->u.road.crashed_ctr++; |
|
554 |
if (v->u.road.crashed_ctr == 2) { |
|
555 |
CreateEffectVehicleRel(v,4,4,8,EV_CRASHED_SMOKE); |
|
556 |
} else if (v->u.road.crashed_ctr <= 45) { |
|
557 |
if ((v->tick_counter&7)==0) |
|
558 |
RoadVehSetRandomDirection(v); |
|
559 |
} else if (v->u.road.crashed_ctr >= 2220) { |
|
560 |
RoadVehDelete(v); |
|
561 |
} |
|
562 |
} |
|
563 |
||
564 |
static void *EnumCheckRoadVehCrashTrain(Vehicle *v, Vehicle *u) |
|
565 |
{ |
|
566 |
if (v->type != VEH_Train || |
|
567 |
myabs(v->z_pos - u->z_pos) > 6 || |
|
568 |
myabs(v->x_pos - u->x_pos) > 4 || |
|
569 |
myabs(v->y_pos - u->y_pos) > 4) |
|
570 |
return NULL; |
|
571 |
return v; |
|
572 |
} |
|
573 |
||
574 |
static void RoadVehCrash(Vehicle *v) |
|
575 |
{ |
|
576 |
uint16 pass; |
|
577 |
||
578 |
v->u.road.crashed_ctr++; |
|
579 |
v->vehstatus |= VS_CRASHED; |
|
580 |
||
581 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
582 |
||
583 |
pass = 1; |
|
584 |
if (v->cargo_type == 0) |
|
585 |
pass += v->cargo_count; |
|
586 |
v->cargo_count = 0; |
|
587 |
SET_DPARAM16(0, pass); |
|
588 |
||
589 |
AddNewsItem(STR_9031_ROAD_VEHICLE_CRASH_DRIVER+(pass!=1), |
|
590 |
NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0), |
|
591 |
v->index, |
|
592 |
0); |
|
593 |
||
594 |
ModifyStationRatingAround(v->tile, v->owner, -160, 22); |
|
595 |
SndPlayVehicleFx(16, v); |
|
596 |
} |
|
597 |
||
598 |
static void RoadVehCheckTrainCrash(Vehicle *v) |
|
599 |
{ |
|
600 |
uint tile; |
|
601 |
||
602 |
if (v->u.road.state == 255) |
|
603 |
return; |
|
604 |
||
605 |
tile = v->tile; |
|
606 |
||
607 |
// Make sure it's a road/rail crossing |
|
608 |
if (!IS_TILETYPE(tile, MP_STREET) || |
|
609 |
(_map5[tile] & 0xF0) != 0x10) |
|
610 |
return; |
|
611 |
||
612 |
if (VehicleFromPos(tile, v, (VehicleFromPosProc*)EnumCheckRoadVehCrashTrain) != NULL) |
|
613 |
RoadVehCrash(v); |
|
614 |
} |
|
615 |
||
616 |
static void HandleBrokenRoadVeh(Vehicle *v) |
|
617 |
{ |
|
618 |
if (v->breakdown_ctr != 1) { |
|
619 |
v->breakdown_ctr = 1; |
|
620 |
v->cur_speed = 0; |
|
621 |
||
622 |
if (v->breakdowns_since_last_service != 255) |
|
623 |
v->breakdowns_since_last_service++; |
|
624 |
||
625 |
InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
|
626 |
InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
|
627 |
||
628 |
SndPlayVehicleFx((_opt.landscape != LT_CANDY) ? 0xD : 0x34, v); |
|
629 |
||
630 |
if (!(v->vehstatus & VS_HIDDEN)) { |
|
631 |
Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE); |
|
632 |
if (u) |
|
633 |
u->u.special.unk0 = v->breakdown_delay * 2; |
|
634 |
} |
|
635 |
} |
|
636 |
||
637 |
if (!(v->tick_counter & 1)) { |
|
638 |
if (!--v->breakdown_delay) { |
|
639 |
v->breakdown_ctr = 0; |
|
640 |
InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
|
641 |
} |
|
642 |
} |
|
643 |
} |
|
644 |
||
645 |
static void ProcessRoadVehOrder(Vehicle *v) |
|
646 |
{ |
|
647 |
uint order; |
|
648 |
Station *st; |
|
649 |
||
650 |
if ((v->next_order & OT_MASK) >= OT_GOTO_DEPOT && (v->next_order & OT_MASK) <= OT_LEAVESTATION) { |
|
651 |
// Let a depot order in the schedule interrupt. |
|
652 |
if ((v->next_order & (OT_MASK|OF_UNLOAD)) != (OT_GOTO_DEPOT|OF_UNLOAD)) |
|
653 |
return; |
|
654 |
} |
|
655 |
||
656 |
if ((v->next_order & (OT_MASK|OF_UNLOAD|OF_FULL_LOAD)) == (OT_GOTO_DEPOT|OF_UNLOAD|OF_FULL_LOAD) && |
|
156
8fef5e5752d6
(svn r157) -Feature: [1009708] Percent-based service intervals. Send a vehicle to depot after it has lost X% of its reliability (mivlad)
darkvater
parents:
76
diff
changeset
|
657 |
SERVICE_INTERVAL ) { |
0 | 658 |
v->cur_order_index++; |
659 |
} |
|
660 |
||
661 |
if (v->cur_order_index >= v->num_orders) |
|
662 |
v->cur_order_index = 0; |
|
663 |
||
664 |
order = v->schedule_ptr[v->cur_order_index]; |
|
665 |
||
666 |
if (order == 0) { |
|
667 |
v->next_order = OT_NOTHING; |
|
668 |
v->dest_tile = 0; |
|
669 |
return; |
|
670 |
} |
|
671 |
||
672 |
if (order == (uint)((v->next_order | (v->next_order_param<<8)))) |
|
673 |
return; |
|
674 |
||
675 |
v->next_order = (byte)order; |
|
676 |
v->next_order_param = (byte)(order >> 8); |
|
677 |
||
678 |
v->dest_tile = 0; |
|
679 |
||
680 |
if ((order & OT_MASK) == OT_GOTO_STATION) { |
|
681 |
if ( (byte)(order >> 8) == v->last_station_visited) |
|
682 |
v->last_station_visited = 0xFF; |
|
683 |
st = DEREF_STATION(order >> 8); |
|
684 |
v->dest_tile = v->cargo_type==CT_PASSENGERS ? st->bus_tile : st->lorry_tile; |
|
685 |
} else if ((order & OT_MASK) == OT_GOTO_DEPOT) { |
|
686 |
v->dest_tile = _depots[order >> 8].xy; |
|
687 |
} |
|
688 |
||
689 |
InvalidateVehicleOrderWidget(v); |
|
690 |
} |
|
691 |
||
692 |
static void HandleRoadVehLoading(Vehicle *v) |
|
693 |
{ |
|
694 |
if (v->next_order == OT_NOTHING) |
|
695 |
return; |
|
696 |
||
697 |
if (v->next_order != OT_DUMMY) { |
|
698 |
if ((v->next_order&OT_MASK) != OT_LOADING) |
|
699 |
return; |
|
700 |
||
701 |
if (--v->load_unload_time_rem) |
|
702 |
return; |
|
703 |
||
704 |
if (v->next_order&OF_FULL_LOAD && CanFillVehicle(v)) { |
|
705 |
SET_EXPENSES_TYPE(EXPENSES_ROADVEH_INC); |
|
706 |
if (LoadUnloadVehicle(v)) { |
|
707 |
InvalidateWindow(WC_ROADVEH_LIST, v->owner); |
|
708 |
MarkRoadVehDirty(v); |
|
709 |
} |
|
710 |
return; |
|
711 |
} |
|
712 |
||
713 |
{ |
|
714 |
byte b = v->next_order; |
|
715 |
v->next_order = OT_LEAVESTATION; |
|
716 |
if (!(b & OF_NON_STOP)) |
|
717 |
return; |
|
718 |
} |
|
719 |
} |
|
720 |
||
721 |
v->cur_order_index++; |
|
722 |
InvalidateVehicleOrderWidget(v); |
|
723 |
} |
|
724 |
||
725 |
static void StartRoadVehSound(Vehicle *v) |
|
726 |
{ |
|
727 |
int s = _road_engine_sounds[v->engine_type - ROAD_ENGINES_INDEX]; |
|
728 |
if (s == 23 && (v->tick_counter&3) == 0) s++; |
|
729 |
SndPlayVehicleFx(s, v); |
|
730 |
} |
|
731 |
||
732 |
typedef struct RoadVehFindData { |
|
733 |
int x,y; |
|
734 |
Vehicle *veh; |
|
735 |
byte dir; |
|
736 |
} RoadVehFindData; |
|
737 |
||
738 |
void *EnumCheckRoadVehClose(Vehicle *v, RoadVehFindData *rvf) |
|
739 |
{ |
|
63
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
740 |
static const short _dists[] = { |
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
741 |
-4, -8, -4, -1, 4, 8, 4, 1, |
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
742 |
-4, -1, 4, 8, 4, 1, -4, -8, |
0 | 743 |
}; |
63
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
744 |
|
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
745 |
short x_diff = v->x_pos - rvf->x; |
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
746 |
short y_diff = v->y_pos - rvf->y; |
0 | 747 |
|
748 |
if (rvf->veh == v || |
|
749 |
v->type != VEH_Road || |
|
750 |
v->u.road.state == 254 || |
|
751 |
myabs(v->z_pos - rvf->veh->z_pos) > 6 || |
|
752 |
v->direction != rvf->dir || |
|
63
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
753 |
(_dists[v->direction] < 0 && (x_diff <= _dists[v->direction] || x_diff > 0)) || |
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
754 |
(_dists[v->direction] > 0 && (x_diff >= _dists[v->direction] || x_diff < 0)) || |
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
755 |
(_dists[v->direction+8] < 0 && (y_diff <= _dists[v->direction+8] || y_diff > 0)) || |
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
756 |
(_dists[v->direction+8] > 0 && (y_diff >= _dists[v->direction+8] || y_diff < 0))) |
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
757 |
return NULL; |
0 | 758 |
|
759 |
return v; |
|
760 |
} |
|
761 |
||
762 |
static Vehicle *RoadVehFindCloseTo(Vehicle *v, int x, int y, byte dir) |
|
763 |
{ |
|
764 |
RoadVehFindData rvf; |
|
765 |
Vehicle *u; |
|
766 |
||
767 |
if (v->u.road.reverse_ctr != 0) |
|
768 |
return NULL; |
|
769 |
||
770 |
rvf.x = x; |
|
771 |
rvf.y = y; |
|
772 |
rvf.dir = dir; |
|
773 |
rvf.veh = v; |
|
774 |
u = VehicleFromPos(TILE_FROM_XY(x,y), &rvf, (VehicleFromPosProc*)EnumCheckRoadVehClose); |
|
775 |
||
63
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
776 |
// This code protects a roadvehicle from being blocked for ever |
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
777 |
// If more then 1480 / 74 days a road vehicle is blocked, it will |
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
778 |
// drive just through it. The ultimate backup-code of TTD. |
53cc59601b3c
(svn r64) Fix: Road vehicles don't get stuck any more (Truelight + Celestar
dominik
parents:
19
diff
changeset
|
779 |
// It can be disabled. |
0 | 780 |
if (u == NULL) { |
781 |
v->u.road.unk2 = 0; |
|
782 |
return NULL; |
|
783 |
} |
|
784 |
||
785 |
if (++v->u.road.unk2 > 1480) |
|
786 |
return NULL; |
|
787 |
||
788 |
return u; |
|
789 |
} |
|
790 |
||
791 |
static void RoadVehArrivesAt(Vehicle *v, Station *st) |
|
792 |
{ |
|
793 |
if (v->engine_type < 123) { |
|
794 |
/* Check if station was ever visited before */ |
|
795 |
if (!(st->had_vehicle_of_type & HVOT_BUS)) { |
|
796 |
uint32 flags; |
|
797 |
||
798 |
st->had_vehicle_of_type |= HVOT_BUS; |
|
799 |
SET_DPARAM16(0, st->index); |
|
800 |
flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0); |
|
801 |
AddNewsItem( |
|
802 |
STR_902F_CITIZENS_CELEBRATE_FIRST, |
|
803 |
flags, |
|
804 |
v->index, |
|
805 |
0); |
|
806 |
} |
|
807 |
} else { |
|
808 |
/* Check if station was ever visited before */ |
|
809 |
if (!(st->had_vehicle_of_type & HVOT_TRUCK)) { |
|
810 |
uint32 flags; |
|
811 |
||
812 |
st->had_vehicle_of_type |= HVOT_TRUCK; |
|
813 |
SET_DPARAM16(0, st->index); |
|
814 |
flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0); |
|
815 |
AddNewsItem( |
|
816 |
STR_9030_CITIZENS_CELEBRATE_FIRST, |
|
817 |
flags, |
|
818 |
v->index, |
|
819 |
0); |
|
820 |
} |
|
821 |
} |
|
822 |
} |
|
823 |
||
824 |
static bool RoadVehAccelerate(Vehicle *v) |
|
825 |
{ |
|
826 |
uint spd = v->cur_speed + 1 + ((v->u.road.overtaking != 0)?1:0); |
|
827 |
byte t; |
|
828 |
||
829 |
// Clamp |
|
830 |
spd = min(spd, v->max_speed); |
|
831 |
||
832 |
//updates statusbar only if speed have changed to save CPU time |
|
833 |
if (spd != v->cur_speed) { |
|
834 |
v->cur_speed = spd; |
|
835 |
if (_patches.vehicle_speed) |
|
836 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
837 |
} |
|
838 |
||
839 |
// Decrease somewhat when turning |
|
840 |
if (!(v->direction&1)) |
|
841 |
spd = spd * 3 >> 2; |
|
842 |
||
843 |
if (spd == 0) |
|
844 |
return false; |
|
845 |
||
846 |
if ((byte)++spd == 0) |
|
847 |
return true; |
|
848 |
||
849 |
v->progress = (t = v->progress) - (byte)spd; |
|
850 |
||
851 |
return (t < v->progress); |
|
852 |
} |
|
853 |
||
854 |
static byte RoadVehGetNewDirection(Vehicle *v, int x, int y) |
|
855 |
{ |
|
856 |
static const byte _roadveh_new_dir[11] = { |
|
857 |
0, 7, 6, 0, |
|
858 |
1, 0, 5, 0, |
|
859 |
2, 3, 4 |
|
860 |
}; |
|
861 |
||
862 |
x = x - v->x_pos + 1; |
|
863 |
y = y - v->y_pos + 1; |
|
864 |
||
865 |
if ((uint)x > 2 || (uint)y > 2) |
|
866 |
return v->direction; |
|
867 |
return _roadveh_new_dir[y*4+x]; |
|
868 |
} |
|
869 |
||
870 |
static byte RoadVehGetSlidingDirection(Vehicle *v, int x, int y) |
|
871 |
{ |
|
872 |
byte b = RoadVehGetNewDirection(v,x,y); |
|
873 |
byte d = v->direction; |
|
874 |
if (b == d) return d; |
|
875 |
d = (d+1)&7; |
|
876 |
if (b==d) return d; |
|
877 |
d = (d-2)&7; |
|
878 |
if (b==d) return d; |
|
879 |
if (b==((d-1)&7)) return d; |
|
880 |
if (b==((d-2)&7)) return d; |
|
881 |
return (d+2)&7; |
|
882 |
} |
|
883 |
||
884 |
typedef struct OvertakeData { |
|
885 |
Vehicle *u, *v; |
|
886 |
uint tile; |
|
887 |
byte tilebits; |
|
888 |
} OvertakeData; |
|
889 |
||
890 |
void *EnumFindVehToOvertake(Vehicle *v, OvertakeData *od) |
|
891 |
{ |
|
892 |
if (v->tile != (TileIndex)od->tile || |
|
893 |
v->type != VEH_Road || |
|
894 |
v == od->u || |
|
895 |
v == od->v) |
|
896 |
return NULL; |
|
897 |
return v; |
|
898 |
} |
|
899 |
||
900 |
static bool FindRoadVehToOvertake(OvertakeData *od) |
|
901 |
{ |
|
902 |
uint32 bits; |
|
903 |
||
159
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
904 |
bits = GetTileTrackStatus(od->tile, TRANSPORT_ROAD)&0x3F; |
0 | 905 |
|
906 |
if (!(od->tilebits & bits) || (bits&0x3C) || (bits & 0x3F3F0000)) |
|
907 |
return true; |
|
908 |
return VehicleFromPos(od->tile, od, (VehicleFromPosProc*)EnumFindVehToOvertake) != NULL; |
|
909 |
} |
|
910 |
||
911 |
static void RoadVehCheckOvertake(Vehicle *v, Vehicle *u) |
|
912 |
{ |
|
913 |
OvertakeData od; |
|
914 |
byte tt; |
|
915 |
||
916 |
od.v = v; |
|
917 |
od.u = u; |
|
918 |
||
919 |
if (u->max_speed >= v->max_speed && |
|
920 |
!(u->vehstatus&VS_STOPPED) && |
|
921 |
u->cur_speed != 0) |
|
922 |
return; |
|
923 |
||
924 |
if (v->direction != u->direction || !(v->direction&1)) |
|
925 |
return; |
|
926 |
||
927 |
if (v->u.road.state >= 32 || (v->u.road.state&7) > 1 ) |
|
928 |
return; |
|
929 |
||
159
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
930 |
tt = (byte)(GetTileTrackStatus(v->tile, TRANSPORT_ROAD) & 0x3F); |
0 | 931 |
if ((tt & 3) == 0) |
932 |
return; |
|
933 |
if ((tt & 0x3C) != 0) |
|
934 |
return; |
|
935 |
||
936 |
if (tt == 3) { |
|
937 |
tt = (v->direction&2)?2:1; |
|
938 |
} |
|
939 |
od.tilebits = tt; |
|
940 |
||
941 |
od.tile = v->tile; |
|
942 |
if (FindRoadVehToOvertake(&od)) |
|
943 |
return; |
|
944 |
||
945 |
od.tile = v->tile + _tileoffs_by_dir[v->direction>>1]; |
|
946 |
if (FindRoadVehToOvertake(&od)) |
|
947 |
return; |
|
948 |
||
949 |
if (od.u->cur_speed == 0 || od.u->vehstatus&VS_STOPPED) { |
|
950 |
v->u.road.overtaking_ctr = 0x11; |
|
951 |
v->u.road.overtaking = 0x10; |
|
952 |
} else { |
|
953 |
// if (FindRoadVehToOvertake(&od)) |
|
954 |
// return; |
|
955 |
v->u.road.overtaking_ctr = 0; |
|
956 |
v->u.road.overtaking = 0x10; |
|
957 |
} |
|
958 |
} |
|
959 |
||
960 |
static void RoadZPosAffectSpeed(Vehicle *v, byte old_z) |
|
961 |
{ |
|
962 |
if (old_z == v->z_pos) |
|
963 |
return; |
|
964 |
||
965 |
if (old_z < v->z_pos) { |
|
966 |
v->cur_speed = v->cur_speed * 232 >> 8; |
|
967 |
} else { |
|
968 |
uint16 spd = v->cur_speed + 2; |
|
969 |
if (spd <= v->max_speed) |
|
970 |
v->cur_speed = spd; |
|
971 |
} |
|
972 |
} |
|
973 |
||
974 |
static int PickRandomBit(uint bits) |
|
975 |
{ |
|
976 |
uint num = 0; |
|
977 |
uint b = bits; |
|
978 |
uint i; |
|
979 |
||
980 |
do { |
|
981 |
if (b & 1) |
|
982 |
num++; |
|
983 |
} while (b >>= 1); |
|
984 |
||
985 |
num = ((uint16)Random() * num >> 16); |
|
986 |
||
987 |
for(i=0; !((bits & 1) && ((int)--num) < 0); bits>>=1,i++); |
|
988 |
return i; |
|
989 |
} |
|
990 |
||
991 |
typedef struct { |
|
992 |
TileIndex dest; |
|
993 |
uint maxtracklen; |
|
994 |
uint mindist; |
|
995 |
} FindRoadToChooseData; |
|
996 |
||
997 |
static bool EnumRoadTrackFindDist(uint tile, FindRoadToChooseData *frd, int track, uint length, byte *state) |
|
998 |
{ |
|
999 |
uint dist = GetTileDist(tile, frd->dest); |
|
1000 |
if (dist <= frd->mindist) { |
|
1001 |
if (dist != frd->mindist || length < frd->maxtracklen) { |
|
1002 |
frd->maxtracklen = length; |
|
1003 |
} |
|
1004 |
frd->mindist = dist; |
|
1005 |
} |
|
1006 |
return false; |
|
1007 |
} |
|
1008 |
||
1009 |
// Returns direction to choose |
|
1010 |
// or -1 if the direction is currently blocked |
|
1011 |
static int RoadFindPathToDest(Vehicle *v, uint tile, int direction) |
|
1012 |
{ |
|
1013 |
#define return_track(x) {best_track = x; goto found_best_track; } |
|
1014 |
||
1015 |
uint16 signal; |
|
1016 |
uint bitmask; |
|
1017 |
uint desttile; |
|
1018 |
FindRoadToChooseData frd; |
|
1019 |
int best_track; |
|
1020 |
uint best_dist, best_maxlen; |
|
1021 |
uint i; |
|
1022 |
byte m5; |
|
1023 |
||
1024 |
{ |
|
1025 |
uint32 r; |
|
159
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
1026 |
r = GetTileTrackStatus(tile, TRANSPORT_ROAD); |
0 | 1027 |
signal = (uint16)(r >> 16); |
1028 |
bitmask = (uint16)r; |
|
1029 |
} |
|
1030 |
||
1031 |
||
159
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
1032 |
/* Most of the checks that used to be here, are now integrated into |
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
1033 |
* GetTileTrackStatus now. The only thing still remaining is the |
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
1034 |
* owner check for stations and depots, since GetTileTrackStatus |
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
1035 |
* doesn't know about owner */ |
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
1036 |
if (IS_TILETYPE(tile, MP_STREET) && (_map5[tile]&0xF0) == 0x20 && v->owner != _map_owner[tile]) |
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
1037 |
/* Depot not owned by us */ |
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
1038 |
bitmask = 0; |
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
1039 |
if (IS_TILETYPE(tile, MP_STATION) && _map_owner[tile] != OWNER_NONE && _map_owner[tile] != v->owner) |
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
1040 |
/* Station not owned by us */ |
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
1041 |
bitmask = 0; |
0 | 1042 |
|
159
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
1043 |
/* remove unreachable tracks */ |
0 | 1044 |
bitmask &= _road_veh_fp_ax_and[direction]; |
1045 |
if (bitmask == 0) { |
|
1046 |
// reverse |
|
1047 |
return_track(_road_reverse_table[direction]); |
|
1048 |
} |
|
1049 |
||
1050 |
if (v->u.road.reverse_ctr != 0) { |
|
1051 |
v->u.road.reverse_ctr = 0; |
|
1052 |
if (v->tile != (TileIndex)tile) { |
|
1053 |
return_track(_road_reverse_table[direction]); |
|
1054 |
} |
|
1055 |
} |
|
1056 |
||
1057 |
desttile = v->dest_tile; |
|
1058 |
if (desttile == 0) { |
|
1059 |
// Pick a random direction |
|
1060 |
return_track(PickRandomBit(bitmask)); |
|
1061 |
} |
|
1062 |
||
1063 |
// Only one direction to choose between? |
|
1064 |
if (!(bitmask & (bitmask - 1))) { |
|
1065 |
return_track(FindFirstBit2x64(bitmask)); |
|
1066 |
} |
|
1067 |
||
1068 |
if (IS_TILETYPE(desttile, MP_STREET)) { |
|
1069 |
m5 = _map5[desttile]; |
|
1070 |
if ((m5&0xF0) == 0x20) |
|
1071 |
goto do_it; |
|
1072 |
} else if (IS_TILETYPE(desttile, MP_STATION)) { |
|
1073 |
m5 = _map5[desttile]; |
|
1074 |
if (IS_BYTE_INSIDE(m5, 0x43, 0x4B)) { |
|
1075 |
m5 -= 0x43; |
|
1076 |
do_it:; |
|
1077 |
desttile += _tileoffs_by_dir[m5&3]; |
|
1078 |
if (desttile == tile && bitmask&_road_pf_table_3[m5&3]) { |
|
1079 |
return_track(FindFirstBit2x64(bitmask&_road_pf_table_3[m5&3])); |
|
1080 |
} |
|
1081 |
} |
|
1082 |
} |
|
1083 |
// do pathfind |
|
1084 |
frd.dest = desttile; |
|
1085 |
||
1086 |
best_track = -1; |
|
1087 |
best_dist = (uint)-1; |
|
1088 |
best_maxlen = (uint)-1; |
|
1089 |
i = 0; |
|
1090 |
do { |
|
1091 |
if (bitmask & 1) { |
|
1092 |
if (best_track == -1) best_track = i; // in case we don't find the path, just pick a direction |
|
1093 |
frd.maxtracklen = (uint)-1; |
|
1094 |
frd.mindist = (uint)-1; |
|
159
139cf78bfb28
(svn r160) -Codechange: made GetTileTrackStatus more readable (blathijs)
truelight
parents:
156
diff
changeset
|
1095 |
FollowTrack(tile, 0x3000 | TRANSPORT_ROAD, _road_pf_directions[i], (TPFEnumProc*)EnumRoadTrackFindDist, NULL, &frd); |
0 | 1096 |
|
1097 |
if (frd.mindist < best_dist || (frd.mindist==best_dist && frd.maxtracklen < best_maxlen)) { |
|
1098 |
best_dist = frd.mindist; |
|
1099 |
best_maxlen = frd.maxtracklen; |
|
1100 |
best_track = i; |
|
1101 |
} |
|
1102 |
} |
|
1103 |
} while (++i,(bitmask>>=1) != 0); |
|
1104 |
||
1105 |
found_best_track:; |
|
1106 |
||
1107 |
if (HASBIT(signal, best_track)) |
|
1108 |
return -1; |
|
1109 |
||
1110 |
return best_track; |
|
1111 |
} |
|
1112 |
||
1113 |
typedef struct RoadDriveEntry { |
|
1114 |
byte x,y; |
|
1115 |
} RoadDriveEntry; |
|
1116 |
||
1117 |
#include "table/roadveh.h" |
|
1118 |
||
1119 |
static const byte _road_veh_data_1[] = { |
|
1120 |
20, 20, 16, 16, 0, 0, 0, 0, |
|
1121 |
19, 19, 15, 15, 0, 0, 0, 0, |
|
1122 |
16, 16, 12, 12, 0, 0, 0, 0, |
|
1123 |
15, 15, 11, 11 |
|
1124 |
}; |
|
1125 |
||
1126 |
static const byte _roadveh_data_2[4] = { 0,1,8,9 }; |
|
1127 |
||
1128 |
static void RoadVehEventHandler(Vehicle *v) |
|
1129 |
{ |
|
1130 |
GetNewVehiclePosResult gp; |
|
1131 |
byte new_dir,old_dir,old_order; |
|
1132 |
RoadDriveEntry rd; |
|
1133 |
int x,y; |
|
1134 |
Station *st; |
|
1135 |
uint32 r; |
|
1136 |
Vehicle *u; |
|
1137 |
||
1138 |
// decrease counters |
|
1139 |
v->tick_counter++; |
|
1140 |
if (v->u.road.reverse_ctr != 0) |
|
1141 |
v->u.road.reverse_ctr--; |
|
1142 |
||
1143 |
// handle crashed |
|
1144 |
if (v->u.road.crashed_ctr != 0) { |
|
1145 |
RoadVehIsCrashed(v); |
|
1146 |
return; |
|
1147 |
} |
|
1148 |
||
1149 |
RoadVehCheckTrainCrash(v); |
|
1150 |
||
1151 |
// road vehicle has broken down? |
|
1152 |
if (v->breakdown_ctr != 0) { |
|
1153 |
if (v->breakdown_ctr <= 2) { |
|
1154 |
HandleBrokenRoadVeh(v); |
|
1155 |
return; |
|
1156 |
} |
|
1157 |
v->breakdown_ctr--; |
|
1158 |
} |
|
1159 |
||
1160 |
// exit if vehicle is stopped |
|
1161 |
if (v->vehstatus & VS_STOPPED) |
|
1162 |
return; |
|
1163 |
||
1164 |
ProcessRoadVehOrder(v); |
|
1165 |
HandleRoadVehLoading(v); |
|
1166 |
||
1167 |
if ((v->next_order & OT_MASK) == OT_LOADING) |
|
1168 |
return; |
|
1169 |
||
1170 |
if (v->u.road.state == 254) { |
|
1171 |
int dir; |
|
1172 |
const RoadDriveEntry*rdp; |
|
1173 |
byte rd2; |
|
1174 |
||
1175 |
v->cur_speed = 0; |
|
1176 |
||
1177 |
dir = _map5[v->tile]&3; |
|
1178 |
v->direction = dir*2+1; |
|
1179 |
||
1180 |
rd2 = _roadveh_data_2[dir]; |
|
1181 |
rdp = _road_drive_data[(_opt.road_side<<4) + rd2]; |
|
1182 |
||
1183 |
x = GET_TILE_X(v->tile)*16 + (rdp[6].x&0xF); |
|
1184 |
y = GET_TILE_Y(v->tile)*16 + (rdp[6].y&0xF); |
|
1185 |
||
1186 |
if (RoadVehFindCloseTo(v,x,y,v->direction)) |
|
1187 |
return; |
|
1188 |
||
1189 |
StartRoadVehSound(v); |
|
1190 |
||
1191 |
BeginVehicleMove(v); |
|
1192 |
||
1193 |
v->vehstatus &= ~VS_HIDDEN; |
|
1194 |
v->u.road.state = rd2; |
|
1195 |
v->u.road.frame = 6; |
|
1196 |
||
1197 |
v->cur_image = GetRoadVehImage(v, v->direction); |
|
1198 |
UpdateRoadVehDeltaXY(v); |
|
1199 |
SetRoadVehPosition(v,x,y); |
|
1200 |
||
1201 |
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
|
1202 |
return; |
|
1203 |
} |
|
1204 |
||
1205 |
if (!RoadVehAccelerate(v)) |
|
1206 |
return; |
|
1207 |
||
1208 |
if (v->u.road.overtaking != 0) { |
|
1209 |
if (++v->u.road.overtaking_ctr >= 35) |
|
1210 |
v->u.road.overtaking = 0; |
|
1211 |
} |
|
1212 |
||
1213 |
BeginVehicleMove(v); |
|
1214 |
||
1215 |
if (v->u.road.state == 255) { |
|
1216 |
GetNewVehiclePos(v, &gp); |
|
1217 |
||
1218 |
if (RoadVehFindCloseTo(v, gp.x, gp.y, v->direction)) { |
|
1219 |
v->cur_speed = 0; |
|
1220 |
return; |
|
1221 |
} |
|
1222 |
||
1223 |
if (IS_TILETYPE(gp.new_tile, MP_TUNNELBRIDGE) && |
|
1224 |
(_map5[gp.new_tile]&0xF0) == 0 && |
|
1225 |
(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y)&4)) { |
|
1226 |
||
1227 |
//new_dir = RoadGetNewDirection(v, gp.x, gp.y) |
|
1228 |
v->cur_image = GetRoadVehImage(v, v->direction); |
|
1229 |
UpdateRoadVehDeltaXY(v); |
|
1230 |
SetRoadVehPosition(v,gp.x,gp.y); |
|
1231 |
return; |
|
1232 |
} |
|
1233 |
||
1234 |
v->x_pos = gp.x; |
|
1235 |
v->y_pos = gp.y; |
|
1236 |
VehiclePositionChanged(v); |
|
1237 |
return; |
|
1238 |
} |
|
1239 |
||
1240 |
rd = _road_drive_data[(v->u.road.state + (_opt.road_side<<4)) ^ v->u.road.overtaking][v->u.road.frame+1]; |
|
1241 |
||
1242 |
// switch to another tile |
|
1243 |
if (rd.x & 0x80) { |
|
1244 |
uint tile = v->tile + _tileoffs_by_dir[rd.x&3]; |
|
1245 |
int dir = RoadFindPathToDest(v, tile, rd.x&3); |
|
1246 |
int tmp; |
|
1247 |
uint32 r; |
|
1248 |
byte newdir; |
|
1249 |
const RoadDriveEntry *rdp; |
|
1250 |
||
1251 |
if (dir == -1) { |
|
1252 |
v->cur_speed = 0; |
|
1253 |
return; |
|
1254 |
} |
|
1255 |
||
1256 |
again: |
|
1257 |
if ((dir & 7) >= 6) { |
|
1258 |
tile = v->tile; |
|
1259 |
} |
|
1260 |
||
1261 |
tmp = (dir+(_opt.road_side<<4))^v->u.road.overtaking; |
|
1262 |
rdp = _road_drive_data[tmp]; |
|
1263 |
||
1264 |
tmp &= ~0x10; |
|
1265 |
||
1266 |
x = GET_TILE_X(tile)*16 + rdp[0].x; |
|
1267 |
y = GET_TILE_Y(tile)*16 + rdp[0].y; |
|
1268 |
||
1269 |
if (RoadVehFindCloseTo(v, x, y, newdir=RoadVehGetSlidingDirection(v, x, y))) |
|
1270 |
return; |
|
1271 |
||
1272 |
r = VehicleEnterTile(v, tile, x, y); |
|
1273 |
if (r & 8) { |
|
1274 |
if (!IS_TILETYPE(tile, MP_TUNNELBRIDGE)) { |
|
1275 |
v->cur_speed = 0; |
|
1276 |
return; |
|
1277 |
} |
|
1278 |
dir = _road_reverse_table[rd.x&3]; |
|
1279 |
goto again; |
|
1280 |
} |
|
1281 |
||
1282 |
if (IS_BYTE_INSIDE(v->u.road.state, 0x20, 0x30) && IS_TILETYPE(v->tile, MP_STATION)) { |
|
1283 |
if ((tmp&7) >= 6) { v->cur_speed = 0; return; } |
|
1284 |
if (IS_BYTE_INSIDE(_map5[v->tile], 0x43, 0x4B)) { |
|
1285 |
Station *st = DEREF_STATION(_map2[v->tile]); |
|
1286 |
byte *b; |
|
1287 |
||
1288 |
if (_map5[v->tile] >= 0x47) { |
|
1289 |
b = &st->bus_stop_status; |
|
1290 |
} else { |
|
1291 |
b = &st->truck_stop_status; |
|
1292 |
} |
|
1293 |
*b = (*b | ((v->u.road.state&2)?2:1)) & 0x7F; |
|
1294 |
} |
|
1295 |
} |
|
1296 |
||
1297 |
if (!(r & 4)) { |
|
1298 |
v->tile = tile; |
|
1299 |
v->u.road.state = (byte)tmp; |
|
1300 |
v->u.road.frame = 0; |
|
1301 |
} |
|
1302 |
if (newdir != v->direction) { |
|
1303 |
v->direction = newdir; |
|
1304 |
v->cur_speed -= v->cur_speed >> 2; |
|
1305 |
} |
|
1306 |
||
1307 |
v->cur_image = GetRoadVehImage(v, newdir); |
|
1308 |
UpdateRoadVehDeltaXY(v); |
|
1309 |
RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y)); |
|
1310 |
return; |
|
1311 |
} |
|
1312 |
||
1313 |
if (rd.x & 0x40) { |
|
1314 |
int dir = RoadFindPathToDest(v, v->tile, rd.x&3); |
|
1315 |
uint32 r; |
|
1316 |
int tmp; |
|
1317 |
byte newdir; |
|
1318 |
const RoadDriveEntry *rdp; |
|
1319 |
||
1320 |
if (dir == -1) { |
|
1321 |
v->cur_speed = 0; |
|
1322 |
return; |
|
1323 |
} |
|
1324 |
||
1325 |
tmp = (_opt.road_side<<4) + dir; |
|
1326 |
rdp = _road_drive_data[tmp]; |
|
1327 |
||
1328 |
x = GET_TILE_X(v->tile)*16 + rdp[1].x; |
|
1329 |
y = GET_TILE_Y(v->tile)*16 + rdp[1].y; |
|
1330 |
||
1331 |
if (RoadVehFindCloseTo(v, x, y, newdir=RoadVehGetSlidingDirection(v, x, y))) |
|
1332 |
return; |
|
1333 |
||
1334 |
r = VehicleEnterTile(v, v->tile, x, y); |
|
1335 |
if (r & 8) { |
|
1336 |
v->cur_speed = 0; |
|
1337 |
return; |
|
1338 |
} |
|
1339 |
||
1340 |
v->u.road.state = tmp & ~16; |
|
1341 |
v->u.road.frame = 1; |
|
1342 |
||
1343 |
if (newdir != v->direction) { |
|
1344 |
v->direction = newdir; |
|
1345 |
v->cur_speed -= v->cur_speed >> 2; |
|
1346 |
} |
|
1347 |
||
1348 |
v->cur_image = GetRoadVehImage(v, newdir); |
|
1349 |
UpdateRoadVehDeltaXY(v); |
|
1350 |
RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y)); |
|
1351 |
return; |
|
1352 |
} |
|
1353 |
||
1354 |
x = (v->x_pos&~15)+(rd.x&15); |
|
1355 |
y = (v->y_pos&~15)+(rd.y&15); |
|
1356 |
||
1357 |
new_dir = RoadVehGetSlidingDirection(v, x, y); |
|
1358 |
||
1359 |
if (!IS_BYTE_INSIDE(v->u.road.state, 0x20, 0x30) && (u=RoadVehFindCloseTo(v, x, y, new_dir)) != NULL) { |
|
1360 |
if (v->u.road.overtaking == 0) |
|
1361 |
RoadVehCheckOvertake(v, u); |
|
1362 |
return; |
|
1363 |
} |
|
1364 |
||
1365 |
old_dir = v->direction; |
|
1366 |
if (new_dir != old_dir) { |
|
1367 |
v->direction = new_dir; |
|
1368 |
v->cur_speed -= (v->cur_speed >> 2); |
|
1369 |
if (old_dir != v->u.road.state) { |
|
1370 |
v->cur_image = GetRoadVehImage(v, new_dir); |
|
1371 |
UpdateRoadVehDeltaXY(v); |
|
1372 |
SetRoadVehPosition(v, v->x_pos, v->y_pos); |
|
1373 |
return; |
|
1374 |
} |
|
1375 |
} |
|
1376 |
||
1377 |
if (v->u.road.state >= 0x20 && |
|
1378 |
_road_veh_data_1[v->u.road.state - 0x20 + (_opt.road_side<<4)] == v->u.road.frame) { |
|
1379 |
byte *b; |
|
1380 |
||
1381 |
st = DEREF_STATION(_map2[v->tile]); |
|
1382 |
b = IS_BYTE_INSIDE(_map5[v->tile], 0x43, 0x47) ? &st->truck_stop_status : &st->bus_stop_status; |
|
1383 |
||
1384 |
if ( (v->next_order&OT_MASK) != OT_LEAVESTATION && |
|
1385 |
(v->next_order&OT_MASK) != OT_GOTO_DEPOT) { |
|
1386 |
||
1387 |
*b &= ~0x80; |
|
1388 |
||
1389 |
v->last_station_visited = _map2[v->tile]; |
|
1390 |
||
1391 |
RoadVehArrivesAt(v, st); |
|
1392 |
||
1393 |
old_order = v->next_order; |
|
1394 |
v->next_order = OT_LOADING; |
|
1395 |
||
1396 |
if ((old_order & OT_MASK) == OT_GOTO_STATION && |
|
1397 |
v->next_order_param == v->last_station_visited) { |
|
1398 |
v->next_order = OT_LOADING | OF_NON_STOP | (old_order & (OF_FULL_LOAD|OF_UNLOAD)); |
|
1399 |
} |
|
1400 |
||
1401 |
SET_EXPENSES_TYPE(EXPENSES_ROADVEH_INC); |
|
1402 |
if (LoadUnloadVehicle(v)) { |
|
1403 |
InvalidateWindow(WC_ROADVEH_LIST, v->owner); |
|
1404 |
MarkRoadVehDirty(v); |
|
1405 |
} |
|
1406 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
1407 |
return; |
|
1408 |
} |
|
1409 |
||
1410 |
if ((v->next_order & OT_MASK) != OT_GOTO_DEPOT) { |
|
1411 |
if (*b&0x80) { |
|
1412 |
v->cur_speed = 0; |
|
1413 |
return; |
|
1414 |
} |
|
1415 |
v->next_order = 0; |
|
1416 |
} |
|
1417 |
*b |= 0x80; |
|
1418 |
||
1419 |
StartRoadVehSound(v); |
|
1420 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
1421 |
} |
|
1422 |
||
1423 |
r = VehicleEnterTile(v, v->tile, x, y); |
|
1424 |
if (r & 8) { |
|
1425 |
v->cur_speed = 0; |
|
1426 |
return; |
|
1427 |
} |
|
1428 |
||
1429 |
if ((r & 4) == 0) { |
|
1430 |
v->u.road.frame++; |
|
1431 |
} |
|
1432 |
||
1433 |
v->cur_image = GetRoadVehImage(v, v->direction); |
|
1434 |
UpdateRoadVehDeltaXY(v); |
|
1435 |
RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y)); |
|
1436 |
} |
|
1437 |
||
1438 |
void RoadVehEnterDepot(Vehicle *v) |
|
1439 |
{ |
|
1440 |
byte t; |
|
1441 |
||
1442 |
v->u.road.state = 254; |
|
1443 |
v->vehstatus |= VS_HIDDEN; |
|
1444 |
||
1445 |
v->date_of_last_service = _date; |
|
1446 |
v->breakdowns_since_last_service = 0; |
|
1447 |
v->reliability = _engines[v->engine_type].reliability; |
|
1448 |
InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
|
1449 |
||
1450 |
MaybeRenewVehicle(v, EstimateRoadVehCost(v->engine_type)); |
|
1451 |
||
1452 |
||
1453 |
if ((v->next_order&OT_MASK) == OT_GOTO_DEPOT) { |
|
1454 |
InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
|
1455 |
||
1456 |
t = v->next_order; |
|
1457 |
v->next_order = OT_DUMMY; |
|
1458 |
||
1459 |
// Part of the schedule? |
|
1460 |
if (t & OF_UNLOAD) { v->cur_order_index++; } |
|
1461 |
||
1462 |
else if (t & OF_FULL_LOAD) { |
|
1463 |
v->vehstatus |= VS_STOPPED; |
|
1464 |
if (v->owner == _local_player) { |
|
1465 |
SET_DPARAM16(0, v->unitnumber); |
|
1466 |
AddNewsItem( |
|
1467 |
STR_9016_ROAD_VEHICLE_IS_WAITING, |
|
1468 |
NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), |
|
1469 |
v->index, |
|
1470 |
0); |
|
1471 |
} |
|
1472 |
} |
|
1473 |
} |
|
1474 |
||
1475 |
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
|
1476 |
} |
|
1477 |
||
1478 |
static void AgeRoadVehCargo(Vehicle *v) |
|
1479 |
{ |
|
1480 |
if (_age_cargo_skip_counter != 0) |
|
1481 |
return; |
|
1482 |
if (v->cargo_days != 255) |
|
1483 |
v->cargo_days++; |
|
1484 |
} |
|
1485 |
||
1486 |
void RoadVeh_Tick(Vehicle *v) |
|
1487 |
{ |
|
1488 |
AgeRoadVehCargo(v); |
|
1489 |
RoadVehEventHandler(v); |
|
1490 |
} |
|
1491 |
||
1492 |
static void CheckIfRoadVehNeedsService(Vehicle *v) |
|
1493 |
{ |
|
1494 |
int i; |
|
1495 |
||
76
30511cbc5188
(svn r77) -Fix: [1010788] AI service interval bug (tnx truesatan)
truelight
parents:
63
diff
changeset
|
1496 |
if (_patches.servint_roadveh == 0) |
11
836bc4b37b5b
(svn r12) Change: removed patch no_train_service. Instead you can set the default service interval for any vehicle type to 'disabled'.
dominik
parents:
0
diff
changeset
|
1497 |
return; |
836bc4b37b5b
(svn r12) Change: removed patch no_train_service. Instead you can set the default service interval for any vehicle type to 'disabled'.
dominik
parents:
0
diff
changeset
|
1498 |
|
156
8fef5e5752d6
(svn r157) -Feature: [1009708] Percent-based service intervals. Send a vehicle to depot after it has lost X% of its reliability (mivlad)
darkvater
parents:
76
diff
changeset
|
1499 |
if (SERVICE_INTERVAL) |
0 | 1500 |
return; |
1501 |
||
1502 |
if (v->vehstatus & VS_STOPPED) |
|
1503 |
return; |
|
1504 |
||
76
30511cbc5188
(svn r77) -Fix: [1010788] AI service interval bug (tnx truesatan)
truelight
parents:
63
diff
changeset
|
1505 |
if (_patches.gotodepot && ScheduleHasDepotOrders(v->schedule_ptr)) |
0 | 1506 |
return; |
1507 |
||
1508 |
// Don't interfere with a depot visit scheduled by the user, or a |
|
1509 |
// depot visit by the order list. |
|
1510 |
if ((v->next_order & OT_MASK) == OT_GOTO_DEPOT && |
|
1511 |
(v->next_order & (OF_FULL_LOAD|OF_UNLOAD)) != 0) |
|
1512 |
return; |
|
1513 |
||
1514 |
i = FindClosestRoadDepot(v); |
|
1515 |
||
1516 |
if (i < 0 || GetTileDist(v->tile, (&_depots[i])->xy) > 12) { |
|
1517 |
if ((v->next_order & OT_MASK) == OT_GOTO_DEPOT) { |
|
1518 |
v->next_order = OT_DUMMY; |
|
1519 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
1520 |
} |
|
1521 |
return; |
|
1522 |
} |
|
1523 |
||
1524 |
if (v->next_order == (OT_GOTO_DEPOT | OF_NON_STOP) && !CHANCE16(1,20)) |
|
1525 |
return; |
|
1526 |
||
1527 |
v->next_order = OT_GOTO_DEPOT | OF_NON_STOP; |
|
1528 |
v->next_order_param = (byte)i; |
|
1529 |
v->dest_tile = (&_depots[i])->xy; |
|
1530 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
1531 |
} |
|
1532 |
||
1533 |
void OnNewDay_RoadVeh(Vehicle *v) |
|
1534 |
{ |
|
1535 |
int32 cost; |
|
1536 |
Station *st; |
|
1537 |
uint tile; |
|
1538 |
||
1539 |
if ((++v->day_counter & 7) == 0) |
|
1540 |
DecreaseVehicleValue(v); |
|
1541 |
||
1542 |
if (v->u.road.unk2 == 0) |
|
1543 |
CheckVehicleBreakdown(v); |
|
1544 |
||
1545 |
AgeVehicle(v); |
|
1546 |
CheckIfRoadVehNeedsService(v); |
|
1547 |
||
19
6080d2b6a959
(svn r20) Feature: warning when a vehicle has invalid orders (celestar)
dominik
parents:
11
diff
changeset
|
1548 |
CheckOrders(v); |
6080d2b6a959
(svn r20) Feature: warning when a vehicle has invalid orders (celestar)
dominik
parents:
11
diff
changeset
|
1549 |
|
0 | 1550 |
/* update destination */ |
1551 |
if ((v->next_order & OT_MASK) == OT_GOTO_STATION) { |
|
1552 |
st = DEREF_STATION(v->next_order_param); |
|
1553 |
if ((tile=(v->cargo_type==CT_PASSENGERS ? st->bus_tile : st->lorry_tile)) != 0) |
|
1554 |
v->dest_tile = tile; |
|
1555 |
} |
|
1556 |
||
1557 |
if (v->vehstatus & VS_STOPPED) |
|
1558 |
return; |
|
1559 |
||
1560 |
cost = _roadveh_runningcost[v->engine_type - ROAD_ENGINES_INDEX] * _price.roadveh_running / 364; |
|
1561 |
||
1562 |
v->profit_this_year -= cost >> 8; |
|
1563 |
||
1564 |
SET_EXPENSES_TYPE(EXPENSES_ROADVEH_RUN); |
|
1565 |
SubtractMoneyFromPlayerFract(v->owner, cost); |
|
1566 |
||
1567 |
InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
|
1568 |
InvalidateWindow(WC_ROADVEH_LIST, v->owner); |
|
1569 |
} |
|
1570 |
||
1571 |
void HandleClickOnRoadVeh(Vehicle *v) |
|
1572 |
{ |
|
1573 |
ShowRoadVehViewWindow(v); |
|
1574 |
} |
|
1575 |
||
1576 |
void RoadVehiclesYearlyLoop() |
|
1577 |
{ |
|
1578 |
Vehicle *v; |
|
1579 |
||
1580 |
FOR_ALL_VEHICLES(v) { |
|
1581 |
if (v->type == VEH_Road) { |
|
1582 |
v->profit_last_year = v->profit_this_year; |
|
1583 |
v->profit_this_year = 0; |
|
1584 |
InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
|
1585 |
} |
|
1586 |
} |
|
1587 |
} |
|
1588 |