author | tron |
Sat, 04 Dec 2004 09:26:39 +0000 | |
changeset 541 | 625227bb2a3d |
parent 538 | 24fdb517fbe5 |
child 555 | 02df8a1b7f33 |
permissions | -rw-r--r-- |
0 | 1 |
#include "stdafx.h" |
2 |
#include "ttd.h" |
|
507
04b5403aaf6b
(svn r815) Include strings.h only in the files which need it.
tron
parents:
458
diff
changeset
|
3 |
#include "table/strings.h" |
0 | 4 |
#include "vehicle.h" |
5 |
#include "engine.h" |
|
6 |
#include "command.h" |
|
7 |
#include "station.h" |
|
8 |
#include "news.h" |
|
9 |
#include "gfx.h" |
|
337
cbe0c766c947
(svn r513) Merge revisions 402, 416, 417, 478, 479, 511, 512 from map to trunk
tron
parents:
193
diff
changeset
|
10 |
#include "sound.h" |
0 | 11 |
#include "player.h" |
12 |
#include "airport.h" |
|
13 |
||
14 |
static bool AirportMove(Vehicle *v, const AirportFTAClass *Airport); |
|
15 |
static bool AirportSetBlocks(Vehicle *v, AirportFTA *current_pos, const AirportFTAClass *Airport); |
|
16 |
static bool AirportHasBlock(Vehicle *v, AirportFTA *current_pos, const AirportFTAClass *Airport); |
|
17 |
static bool AirportFindFreeTerminal(Vehicle *v, const AirportFTAClass *Airport); |
|
18 |
static bool AirportFindFreeHelipad(Vehicle *v, const AirportFTAClass *Airport); |
|
19 |
static void AirportGoToNextPosition(Vehicle *v, const AirportFTAClass *Airport); |
|
20 |
||
21 |
static void AircraftNextAirportPos_and_Order(Vehicle *v); |
|
22 |
static byte GetAircraftFlyingAltitude(const Vehicle *v); |
|
23 |
||
24 |
static const SpriteID _aircraft_sprite[] = { |
|
25 |
0x0EB5, 0x0EBD, 0x0EC5, 0x0ECD, |
|
26 |
0x0ED5, 0x0EDD, 0x0E9D, 0x0EA5, |
|
27 |
0x0EAD, 0x0EE5, 0x0F05, 0x0F0D, |
|
28 |
0x0F15, 0x0F1D, 0x0F25, 0x0F2D, |
|
29 |
0x0EED, 0x0EF5, 0x0EFD, 0x0F35, |
|
30 |
0x0E9D, 0x0EA5, 0x0EAD, 0x0EB5, |
|
31 |
0x0EBD, 0x0EC5 |
|
32 |
}; |
|
33 |
||
34 |
int GetAircraftImage(Vehicle *v, byte direction) |
|
35 |
{ |
|
36 |
int spritenum = v->spritenum; |
|
37 |
||
38 |
if (is_custom_sprite(spritenum)) { |
|
39 |
int sprite = GetCustomVehicleSprite(v, direction); |
|
40 |
||
41 |
if (sprite) return sprite; |
|
42 |
spritenum = _engine_original_sprites[v->engine_type]; |
|
43 |
} |
|
44 |
return direction + _aircraft_sprite[spritenum]; |
|
45 |
} |
|
46 |
||
47 |
void DrawAircraftEngine(int x, int y, int engine, uint32 image_ormod) |
|
48 |
{ |
|
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
49 |
int spritenum = AircraftVehInfo(engine)->image_index; |
0 | 50 |
|
381
527e47c8feec
(svn r570) -newgrf: Support for custom aircrafts via GRF files. Planeset seems to work :). Also use aircraft_vehinfo() instead of the old tables (pasky).
darkvater
parents:
337
diff
changeset
|
51 |
if (is_custom_sprite(spritenum)) { |
527e47c8feec
(svn r570) -newgrf: Support for custom aircrafts via GRF files. Planeset seems to work :). Also use aircraft_vehinfo() instead of the old tables (pasky).
darkvater
parents:
337
diff
changeset
|
52 |
int sprite = GetCustomVehicleIcon(engine, 6); |
527e47c8feec
(svn r570) -newgrf: Support for custom aircrafts via GRF files. Planeset seems to work :). Also use aircraft_vehinfo() instead of the old tables (pasky).
darkvater
parents:
337
diff
changeset
|
53 |
|
527e47c8feec
(svn r570) -newgrf: Support for custom aircrafts via GRF files. Planeset seems to work :). Also use aircraft_vehinfo() instead of the old tables (pasky).
darkvater
parents:
337
diff
changeset
|
54 |
if (sprite) { |
527e47c8feec
(svn r570) -newgrf: Support for custom aircrafts via GRF files. Planeset seems to work :). Also use aircraft_vehinfo() instead of the old tables (pasky).
darkvater
parents:
337
diff
changeset
|
55 |
DrawSprite(sprite | image_ormod, x, y); |
527e47c8feec
(svn r570) -newgrf: Support for custom aircrafts via GRF files. Planeset seems to work :). Also use aircraft_vehinfo() instead of the old tables (pasky).
darkvater
parents:
337
diff
changeset
|
56 |
return; |
527e47c8feec
(svn r570) -newgrf: Support for custom aircrafts via GRF files. Planeset seems to work :). Also use aircraft_vehinfo() instead of the old tables (pasky).
darkvater
parents:
337
diff
changeset
|
57 |
} |
527e47c8feec
(svn r570) -newgrf: Support for custom aircrafts via GRF files. Planeset seems to work :). Also use aircraft_vehinfo() instead of the old tables (pasky).
darkvater
parents:
337
diff
changeset
|
58 |
spritenum = _engine_original_sprites[engine]; |
527e47c8feec
(svn r570) -newgrf: Support for custom aircrafts via GRF files. Planeset seems to work :). Also use aircraft_vehinfo() instead of the old tables (pasky).
darkvater
parents:
337
diff
changeset
|
59 |
} |
527e47c8feec
(svn r570) -newgrf: Support for custom aircrafts via GRF files. Planeset seems to work :). Also use aircraft_vehinfo() instead of the old tables (pasky).
darkvater
parents:
337
diff
changeset
|
60 |
|
527e47c8feec
(svn r570) -newgrf: Support for custom aircrafts via GRF files. Planeset seems to work :). Also use aircraft_vehinfo() instead of the old tables (pasky).
darkvater
parents:
337
diff
changeset
|
61 |
DrawSprite((6 + _aircraft_sprite[spritenum]) | image_ormod, x, y); |
527e47c8feec
(svn r570) -newgrf: Support for custom aircrafts via GRF files. Planeset seems to work :). Also use aircraft_vehinfo() instead of the old tables (pasky).
darkvater
parents:
337
diff
changeset
|
62 |
|
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
63 |
if ((AircraftVehInfo(engine)->subtype & 1) == 0) |
0 | 64 |
DrawSprite(0xF3D, x, y-5); |
65 |
} |
|
66 |
||
67 |
void DrawAircraftEngineInfo(int engine, int x, int y, int maxw) |
|
68 |
{ |
|
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
69 |
const AircraftVehicleInfo *avi = AircraftVehInfo(engine); |
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
70 |
SetDParam(0, ((_price.aircraft_base >> 3) * avi->base_cost) >> 5); |
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
71 |
SetDParam(1, avi->max_speed << 3); |
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
72 |
SetDParam(2, avi->passanger_capacity); |
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
73 |
SetDParam(3, avi->mail_capacity); |
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
74 |
SetDParam(4, avi->running_cost * _price.aircraft_running >> 8); |
0 | 75 |
|
76 |
DrawStringMultiCenter(x, y, STR_A02E_COST_MAX_SPEED_CAPACITY, maxw); |
|
77 |
} |
|
78 |
||
79 |
/* Allocate many vehicles */ |
|
410 | 80 |
static bool AllocateVehicles(Vehicle **vl, int num) |
0 | 81 |
{ |
82 |
int i; |
|
83 |
Vehicle *v; |
|
84 |
bool success = true; |
|
85 |
||
86 |
for(i=0; i!=num; i++) { |
|
87 |
vl[i] = v = AllocateVehicle(); |
|
88 |
if (v == NULL) { |
|
89 |
success = false; |
|
90 |
break; |
|
91 |
} |
|
92 |
v->type = 1; |
|
93 |
} |
|
94 |
||
95 |
while (--i >= 0) { |
|
96 |
vl[i]->type = 0; |
|
97 |
} |
|
98 |
||
99 |
return success; |
|
100 |
} |
|
101 |
||
102 |
static int32 EstimateAircraftCost(uint16 engine_type) |
|
103 |
{ |
|
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
104 |
return AircraftVehInfo(engine_type)->base_cost * (_price.aircraft_base>>3)>>5; |
0 | 105 |
} |
106 |
||
107 |
||
108 |
/* p1 = engine */ |
|
109 |
int32 CmdBuildAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
|
110 |
{ |
|
111 |
int32 value; |
|
112 |
Vehicle *vl[3], *v, *u, *w; |
|
113 |
byte unit_num; |
|
114 |
uint tile = TILE_FROM_XY(x,y); |
|
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
115 |
const AircraftVehicleInfo *avi = AircraftVehInfo(p1); |
0 | 116 |
Engine *e; |
117 |
||
118 |
SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
|
119 |
||
120 |
value = EstimateAircraftCost(p1); |
|
121 |
||
122 |
if (flags & DC_QUERY_COST) |
|
123 |
return value; |
|
124 |
||
125 |
// allocate 2 or 3 vehicle structs, depending on type |
|
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
126 |
if (!AllocateVehicles(vl, (avi->subtype & 1) == 0 ? 3 : 2) || |
0 | 127 |
_ptr_to_next_order >= endof(_order_array)) |
128 |
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
|
129 |
||
130 |
unit_num = GetFreeUnitNumber(VEH_Aircraft); |
|
131 |
if (unit_num > _patches.max_aircraft) |
|
132 |
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
|
133 |
||
134 |
if (flags & DC_EXEC) { |
|
135 |
v = vl[0]; |
|
136 |
u = vl[1]; |
|
137 |
||
138 |
v->unitnumber = unit_num; |
|
139 |
v->type = u->type = VEH_Aircraft; |
|
140 |
v->direction = 3; |
|
141 |
||
142 |
v->owner = u->owner = _current_player; |
|
143 |
||
144 |
v->tile = tile; |
|
145 |
// u->tile = 0; |
|
146 |
||
147 |
x = GET_TILE_X(tile)*16 + 5; |
|
148 |
y = GET_TILE_Y(tile)*16 + 3; |
|
149 |
||
150 |
v->x_pos = u->x_pos = x; |
|
151 |
v->y_pos = u->y_pos = y; |
|
152 |
||
153 |
u->z_pos = GetSlopeZ(x, y); |
|
154 |
v->z_pos = u->z_pos + 1; |
|
155 |
||
156 |
v->x_offs = v->y_offs = -1; |
|
157 |
// u->delta_x = u->delta_y = 0; |
|
158 |
||
159 |
v->sprite_width = v->sprite_height = 2; |
|
160 |
v->z_height = 5; |
|
161 |
||
162 |
u->sprite_width = u->sprite_height = 2; |
|
163 |
u->z_height = 1; |
|
164 |
||
165 |
v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL; |
|
166 |
u->vehstatus = VS_HIDDEN | VS_UNCLICKABLE | VS_DISASTER; |
|
167 |
||
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
168 |
v->spritenum = avi->image_index; |
0 | 169 |
// v->cargo_count = u->number_of_pieces = 0; |
170 |
||
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
171 |
v->cargo_cap = avi->passanger_capacity; |
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
172 |
u->cargo_cap = avi->mail_capacity; |
0 | 173 |
|
174 |
v->cargo_type = CT_PASSENGERS; |
|
175 |
u->cargo_type = CT_MAIL; |
|
176 |
||
177 |
v->string_id = STR_SV_AIRCRAFT_NAME; |
|
178 |
// v->next_order_param = v->next_order = 0; |
|
179 |
||
180 |
// v->load_unload_time_rem = 0; |
|
181 |
// v->progress = 0; |
|
182 |
v->last_station_visited = 0xFF; |
|
183 |
// v->destination_coords = 0; |
|
184 |
||
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
185 |
v->max_speed = avi->max_speed; |
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
186 |
v->acceleration = avi->acceleration; |
0 | 187 |
v->engine_type = (byte)p1; |
188 |
||
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
189 |
v->subtype = (avi->subtype & 1) == 0 ? 0 : 2; |
0 | 190 |
v->value = value; |
191 |
||
192 |
u->subtype = 4; |
|
193 |
||
194 |
e = &_engines[p1]; |
|
195 |
v->reliability = e->reliability; |
|
196 |
v->reliability_spd_dec = e->reliability_spd_dec; |
|
197 |
v->max_age = e->lifelength * 366; |
|
198 |
||
199 |
_new_aircraft_id = v->index; |
|
200 |
||
201 |
*(v->schedule_ptr = _ptr_to_next_order++) = 0; |
|
202 |
// the AI doesn't click on a tile to build airplanes, so the below code will |
|
203 |
// never work. Therefore just assume the AI's planes always come from Hangar0 |
|
84
1e0721c29bad
(svn r85) -Add: initial commit of new AI (enable in Patch menu)
truelight
parents:
76
diff
changeset
|
204 |
// On hold for NewAI |
1e0721c29bad
(svn r85) -Add: initial commit of new AI (enable in Patch menu)
truelight
parents:
76
diff
changeset
|
205 |
v->u.air.pos = (!_patches.ainew_active && _is_ai_player) ? 0:MAX_ELEMENTS; |
0 | 206 |
|
193
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
207 |
/* When we click on hangar we know the tile (it is in var 'tile')it is on. By that we know |
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
208 |
its position in the array of depots the airport has.....we can search |
0 | 209 |
->layout for #th position of depot. Since layout must start with depots, it is simple |
210 |
*/ |
|
211 |
{ |
|
212 |
Station *st; |
|
213 |
const AirportFTAClass *Airport; |
|
214 |
const uint16 *cur_depot; |
|
215 |
byte i = 0; |
|
216 |
st = DEREF_STATION(_map2[tile]); |
|
217 |
Airport = GetAirport(st->airport_type); |
|
218 |
// first element of depot array contains #of depots on the airport |
|
219 |
for (cur_depot=&Airport->airport_depots[1]; i != Airport->airport_depots[0]; cur_depot++) { |
|
220 |
if ((uint)(st->airport_tile + *cur_depot) == tile) { |
|
221 |
assert(Airport->layout[i].heading == HANGAR); |
|
222 |
v->u.air.pos = Airport->layout[i].position; |
|
223 |
break; |
|
224 |
} |
|
225 |
i++; |
|
226 |
} |
|
227 |
// to ensure v->u.air.pos has been given a value |
|
228 |
assert(v->u.air.pos != MAX_ELEMENTS); |
|
229 |
} |
|
230 |
||
231 |
v->u.air.state = HANGAR; |
|
232 |
v->u.air.previous_pos = v->u.air.pos; |
|
233 |
v->u.air.targetairport = _map2[tile]; |
|
234 |
v->next = u; |
|
235 |
||
236 |
v->service_interval = _patches.servint_aircraft; |
|
237 |
||
238 |
v->date_of_last_service = _date; |
|
239 |
v->build_year = _cur_year; |
|
240 |
||
241 |
v->cur_image = u->cur_image = 0xEA0; |
|
242 |
||
243 |
VehiclePositionChanged(v); |
|
244 |
VehiclePositionChanged(u); |
|
245 |
||
246 |
// Aircraft with 3 vehicles? |
|
247 |
if (v->subtype == 0) { |
|
248 |
w = vl[2]; |
|
249 |
||
250 |
u->next = w; |
|
251 |
||
252 |
w->type = VEH_Aircraft; |
|
253 |
w->direction = 0; |
|
254 |
w->owner = _current_player; |
|
255 |
w->x_pos = v->x_pos; |
|
256 |
w->y_pos = v->y_pos; |
|
257 |
w->z_pos = v->z_pos + 5; |
|
258 |
w->x_offs = w->y_offs = -1; |
|
259 |
w->sprite_width = w->sprite_height = 2; |
|
260 |
w->z_height = 1; |
|
261 |
w->vehstatus = VS_HIDDEN | VS_UNCLICKABLE; |
|
262 |
w->subtype = 6; |
|
263 |
w->cur_image = 0xF3D; |
|
264 |
VehiclePositionChanged(w); |
|
265 |
} |
|
266 |
||
267 |
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:
156
diff
changeset
|
268 |
_vehicle_sort_dirty[VEHAIRCRAFT] = true; // build aircraft |
0 | 269 |
InvalidateWindow(WC_AIRCRAFT_LIST, v->owner); |
270 |
InvalidateWindow(WC_COMPANY, v->owner); |
|
271 |
} |
|
272 |
||
273 |
return value; |
|
274 |
} |
|
275 |
||
276 |
bool IsAircraftHangarTile(TileIndex tile) |
|
277 |
{ |
|
278 |
// 0x56 - hangar facing other way international airport (86) |
|
279 |
// 0x20 - hangar large airport (32) |
|
280 |
// 0x41 - hangar small airport (65) |
|
281 |
return IS_TILETYPE(tile, MP_STATION) && |
|
282 |
(_map5[tile] == 32 || _map5[tile] == 65 || _map5[tile] == 86); |
|
283 |
} |
|
284 |
||
285 |
static bool CheckStoppedInHangar(Vehicle *v) |
|
286 |
{ |
|
287 |
if (!(v->vehstatus&VS_STOPPED) || |
|
288 |
!IsAircraftHangarTile(v->tile)) { |
|
289 |
_error_message = STR_A01B_AIRCRAFT_MUST_BE_STOPPED; |
|
290 |
return false; |
|
291 |
} |
|
292 |
||
293 |
return true; |
|
294 |
} |
|
295 |
||
296 |
||
410 | 297 |
static void DoDeleteAircraft(Vehicle *v) |
0 | 298 |
{ |
299 |
DeleteWindowById(WC_VEHICLE_VIEW, v->index); |
|
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:
156
diff
changeset
|
300 |
_vehicle_sort_dirty[VEHAIRCRAFT] = true; // delete aircraft |
0 | 301 |
InvalidateWindow(WC_AIRCRAFT_LIST, v->owner); |
302 |
InvalidateWindow(WC_COMPANY, v->owner); |
|
303 |
DeleteVehicleChain(v); |
|
304 |
} |
|
305 |
||
306 |
// p1 = vehicle |
|
307 |
int32 CmdSellAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
|
308 |
{ |
|
309 |
Vehicle *v; |
|
310 |
||
311 |
SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
|
312 |
||
313 |
v = &_vehicles[p1]; |
|
314 |
||
315 |
if (!CheckOwnership(v->owner) || !CheckStoppedInHangar(v)) |
|
316 |
return CMD_ERROR; |
|
317 |
||
318 |
if (flags & DC_EXEC) { |
|
319 |
// Invalidate depot |
|
320 |
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
|
321 |
||
322 |
DoDeleteAircraft(v); |
|
323 |
||
324 |
} |
|
325 |
||
326 |
return -(int32)v->value; |
|
327 |
} |
|
328 |
||
329 |
// p1 = vehicle |
|
330 |
int32 CmdStartStopAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
|
331 |
{ |
|
332 |
Vehicle *v; |
|
333 |
||
334 |
v = &_vehicles[p1]; |
|
335 |
||
336 |
if (!CheckOwnership(v->owner)) |
|
337 |
return CMD_ERROR; |
|
338 |
||
339 |
// cannot stop airplane when in flight, or when taking off / landing |
|
340 |
if (v->u.air.state >= STARTTAKEOFF) { |
|
341 |
return_cmd_error(STR_A017_AIRCRAFT_IS_IN_FLIGHT); |
|
342 |
} |
|
343 |
||
344 |
if (flags & DC_EXEC) { |
|
345 |
v->vehstatus ^= VS_STOPPED; |
|
346 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
347 |
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
|
348 |
} |
|
349 |
||
350 |
return 0; |
|
351 |
} |
|
352 |
||
353 |
// p1 = vehicle |
|
354 |
int32 CmdSendAircraftToHangar(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
|
355 |
{ |
|
356 |
Vehicle *v; |
|
357 |
Station *st; |
|
358 |
||
359 |
v = &_vehicles[p1]; |
|
360 |
||
361 |
if (!CheckOwnership(v->owner)) |
|
362 |
return CMD_ERROR; |
|
363 |
||
364 |
if ((v->next_order&OT_MASK) == OT_GOTO_DEPOT) { |
|
365 |
if (flags & DC_EXEC) { |
|
366 |
if (v->next_order&OF_UNLOAD) |
|
367 |
{ v->cur_order_index++; } |
|
368 |
v->next_order = OT_DUMMY; |
|
369 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
370 |
} |
|
371 |
} else { |
|
372 |
st = DEREF_STATION(v->u.air.targetairport); |
|
373 |
// If an airport doesn't have terminals (so no landing space for airports), |
|
374 |
// it surely doesn't have any hangars |
|
375 |
if (st->xy == 0 || st->airport_tile == 0 || GetAirport(st->airport_type)->nofterminals == 0) |
|
376 |
return CMD_ERROR; |
|
377 |
||
378 |
if (flags & DC_EXEC) { |
|
379 |
v->next_order = OF_NON_STOP | OF_FULL_LOAD | OT_GOTO_DEPOT; |
|
380 |
v->next_order_param = v->u.air.targetairport; |
|
381 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
382 |
} |
|
383 |
} |
|
384 |
||
385 |
return 0; |
|
386 |
} |
|
387 |
||
388 |
// p1 = vehicle |
|
389 |
// p2 = new service int |
|
390 |
int32 CmdChangeAircraftServiceInt(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
|
391 |
{ |
|
392 |
Vehicle *v; |
|
393 |
||
394 |
v = &_vehicles[p1]; |
|
395 |
||
396 |
if (!CheckOwnership(v->owner)) |
|
397 |
return CMD_ERROR; |
|
398 |
||
399 |
if (flags & DC_EXEC) { |
|
400 |
v->service_interval = (uint16)p2; |
|
401 |
InvalidateWindowWidget(WC_VEHICLE_DETAILS, v->index, 7); |
|
402 |
} |
|
403 |
||
404 |
return 0; |
|
405 |
} |
|
406 |
||
407 |
// p1 = vehicle |
|
408 |
// p2 = new cargo type |
|
409 |
int32 CmdRefitAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
|
410 |
{ |
|
411 |
Vehicle *v,*u; |
|
412 |
int pass, mail; |
|
413 |
int32 cost; |
|
414 |
||
415 |
SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_RUN); |
|
416 |
||
417 |
v = &_vehicles[p1]; |
|
418 |
if (!CheckOwnership(v->owner) || !CheckStoppedInHangar(v)) |
|
419 |
return CMD_ERROR; |
|
420 |
||
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
421 |
pass = AircraftVehInfo(v->engine_type)->passanger_capacity; |
0 | 422 |
if (p2 != 0) { |
423 |
pass >>= 1; |
|
424 |
if (p2 != 5) |
|
425 |
pass >>= 1; |
|
426 |
} |
|
427 |
_aircraft_refit_capacity = pass; |
|
428 |
||
429 |
cost = 0; |
|
430 |
if (IS_HUMAN_PLAYER(v->owner) && (byte)p2 != v->cargo_type) { |
|
431 |
cost = _price.aircraft_base >> 7; |
|
432 |
} |
|
433 |
||
434 |
if (flags & DC_EXEC) { |
|
435 |
v->cargo_cap = pass; |
|
436 |
||
437 |
u = v->next; |
|
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
438 |
mail = AircraftVehInfo(v->engine_type)->mail_capacity; |
0 | 439 |
if (p2 != 0) { |
440 |
mail = 0; |
|
441 |
} |
|
442 |
u->cargo_cap = mail; |
|
443 |
v->cargo_count = u->cargo_count = 0; |
|
444 |
v->cargo_type = (byte)p2; |
|
445 |
InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
|
446 |
} |
|
447 |
||
448 |
return cost; |
|
449 |
} |
|
450 |
||
451 |
void HandleClickOnAircraft(Vehicle *v) |
|
452 |
{ |
|
453 |
ShowAircraftViewWindow(v); |
|
454 |
} |
|
455 |
||
456 |
static void CheckIfAircraftNeedsService(Vehicle *v) |
|
457 |
{ |
|
458 |
Station *st; |
|
459 |
||
76
30511cbc5188
(svn r77) -Fix: [1010788] AI service interval bug (tnx truesatan)
truelight
parents:
70
diff
changeset
|
460 |
if (_patches.servint_aircraft == 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
|
461 |
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
|
462 |
|
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:
99
diff
changeset
|
463 |
if (SERVICE_INTERVAL) |
0 | 464 |
return; |
465 |
||
466 |
if (v->vehstatus & VS_STOPPED) |
|
467 |
return; |
|
468 |
||
469 |
if ((v->next_order & (OT_MASK | OF_FULL_LOAD)) == (OT_GOTO_DEPOT | OF_FULL_LOAD)) |
|
470 |
return; |
|
471 |
||
76
30511cbc5188
(svn r77) -Fix: [1010788] AI service interval bug (tnx truesatan)
truelight
parents:
70
diff
changeset
|
472 |
if (_patches.gotodepot && ScheduleHasDepotOrders(v->schedule_ptr)) |
0 | 473 |
return; |
193
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
474 |
|
0 | 475 |
st = DEREF_STATION(v->next_order_param); |
476 |
// only goto depot if the target airport has terminals (eg. it is airport) |
|
477 |
if (st->xy != 0 && st->airport_tile != 0 && GetAirport(st->airport_type)->nofterminals != 0) { |
|
478 |
// printf("targetairport = %d, st->index = %d\n", v->u.air.targetairport, st->index); |
|
479 |
// v->u.air.targetairport = st->index; |
|
480 |
v->next_order = OF_NON_STOP | OT_GOTO_DEPOT; |
|
481 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
482 |
} else if ((v->next_order & OT_MASK) == OT_GOTO_DEPOT) { |
|
483 |
v->next_order = OT_DUMMY; |
|
484 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
485 |
} |
|
486 |
} |
|
487 |
||
488 |
void OnNewDay_Aircraft(Vehicle *v) |
|
489 |
{ |
|
490 |
int32 cost; |
|
491 |
||
492 |
if (v->subtype > 2) |
|
493 |
return; |
|
494 |
||
495 |
if ((++v->day_counter & 7) == 0) |
|
496 |
DecreaseVehicleValue(v); |
|
497 |
||
19
6080d2b6a959
(svn r20) Feature: warning when a vehicle has invalid orders (celestar)
dominik
parents:
11
diff
changeset
|
498 |
CheckOrders(v); |
6080d2b6a959
(svn r20) Feature: warning when a vehicle has invalid orders (celestar)
dominik
parents:
11
diff
changeset
|
499 |
|
0 | 500 |
CheckVehicleBreakdown(v); |
501 |
AgeVehicle(v); |
|
502 |
CheckIfAircraftNeedsService(v); |
|
503 |
||
504 |
if (v->vehstatus & VS_STOPPED) |
|
505 |
return; |
|
506 |
||
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
507 |
cost = AircraftVehInfo(v->engine_type)->running_cost * _price.aircraft_running / 364; |
0 | 508 |
|
509 |
v->profit_this_year -= cost >> 8; |
|
510 |
||
511 |
SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_RUN); |
|
512 |
SubtractMoneyFromPlayerFract(v->owner, cost); |
|
513 |
||
514 |
InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
|
515 |
InvalidateWindow(WC_AIRCRAFT_LIST, v->owner); |
|
516 |
} |
|
517 |
||
518 |
void AircraftYearlyLoop() |
|
519 |
{ |
|
520 |
Vehicle *v; |
|
521 |
||
522 |
FOR_ALL_VEHICLES(v) { |
|
523 |
if (v->type == VEH_Aircraft && v->subtype <= 2) { |
|
524 |
v->profit_last_year = v->profit_this_year; |
|
525 |
v->profit_this_year = 0; |
|
526 |
InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
|
527 |
} |
|
528 |
} |
|
529 |
} |
|
530 |
||
531 |
static void AgeAircraftCargo(Vehicle *v) |
|
532 |
{ |
|
533 |
if (_age_cargo_skip_counter != 0) |
|
534 |
return; |
|
535 |
||
536 |
do { |
|
537 |
if (v->cargo_days != 0xFF) |
|
538 |
v->cargo_days++; |
|
539 |
} while ( (v=v->next) != NULL ); |
|
540 |
} |
|
541 |
||
542 |
static void HelicopterTickHandler(Vehicle *v) |
|
543 |
{ |
|
544 |
Vehicle *u; |
|
545 |
int tick,spd; |
|
546 |
uint16 img; |
|
547 |
||
548 |
u = v->next->next; |
|
549 |
||
550 |
if (u->vehstatus & VS_HIDDEN) |
|
551 |
return; |
|
552 |
||
193
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
553 |
// if true, helicopter rotors do not rotate. This should only be the case if a helicopter is |
0 | 554 |
// loading/unloading at a terminal or stopped |
555 |
if ((v->next_order&OT_MASK) == OT_LOADING || (v->vehstatus&VS_STOPPED)) { |
|
556 |
if (u->cur_speed != 0) { |
|
557 |
u->cur_speed++; |
|
558 |
if (u->cur_speed >= 0x80 && u->cur_image == 0xF40) { |
|
559 |
u->cur_speed = 0; |
|
560 |
} |
|
561 |
} |
|
562 |
} else { |
|
563 |
if (u->cur_speed == 0) |
|
564 |
u->cur_speed = 0x70; |
|
565 |
||
566 |
if (u->cur_speed >= 0x50) |
|
567 |
u->cur_speed--; |
|
568 |
} |
|
569 |
||
570 |
tick = ++u->tick_counter; |
|
571 |
spd = u->cur_speed >> 4; |
|
572 |
||
573 |
if (spd == 0) { |
|
574 |
img = 0xF3D; |
|
575 |
if (u->cur_image == img) |
|
576 |
return; |
|
577 |
} else if (tick >= spd) { |
|
578 |
u->tick_counter = 0; |
|
579 |
img = u->cur_image + 1; |
|
580 |
if (img > 0xF40) |
|
581 |
img = 0xF3E; |
|
582 |
} else |
|
583 |
return; |
|
584 |
||
585 |
u->cur_image=img; |
|
586 |
||
587 |
BeginVehicleMove(u); |
|
588 |
VehiclePositionChanged(u); |
|
589 |
EndVehicleMove(u); |
|
590 |
} |
|
591 |
||
592 |
static void SetAircraftPosition(Vehicle *v, int x, int y, int z) |
|
593 |
{ |
|
594 |
Vehicle *u; |
|
595 |
int yt; |
|
596 |
||
597 |
v->x_pos = x; |
|
598 |
v->y_pos = y; |
|
599 |
v->z_pos = z; |
|
600 |
||
601 |
v->cur_image = GetAircraftImage(v, v->direction); |
|
602 |
||
603 |
BeginVehicleMove(v); |
|
604 |
VehiclePositionChanged(v); |
|
605 |
EndVehicleMove(v); |
|
606 |
||
607 |
u = v->next; |
|
608 |
||
609 |
yt = y - ((v->z_pos-GetSlopeZ(x, y-1)) >> 3); |
|
610 |
u->x_pos = x; |
|
611 |
u->y_pos = yt; |
|
612 |
u->z_pos = GetSlopeZ(x,yt); |
|
613 |
u->cur_image = v->cur_image; |
|
614 |
||
615 |
BeginVehicleMove(u); |
|
616 |
VehiclePositionChanged(u); |
|
617 |
EndVehicleMove(u); |
|
618 |
||
619 |
if ((u=u->next) != NULL) { |
|
620 |
u->x_pos = x; |
|
621 |
u->y_pos = y; |
|
622 |
u->z_pos = z + 5; |
|
623 |
||
624 |
BeginVehicleMove(u); |
|
625 |
VehiclePositionChanged(u); |
|
626 |
EndVehicleMove(u); |
|
627 |
} |
|
628 |
} |
|
629 |
||
630 |
static void ServiceAircraft(Vehicle *v) |
|
631 |
{ |
|
632 |
Vehicle *u; |
|
633 |
||
634 |
v->cur_speed = 0; |
|
635 |
v->subspeed = 0; |
|
636 |
v->progress = 0; |
|
637 |
v->vehstatus |= VS_HIDDEN; |
|
638 |
||
639 |
u = v->next; |
|
640 |
u->vehstatus |= VS_HIDDEN; |
|
641 |
if ((u=u->next) != NULL) { |
|
642 |
u->vehstatus |= VS_HIDDEN; |
|
643 |
u->cur_speed = 0; |
|
644 |
} |
|
645 |
||
646 |
SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); |
|
647 |
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
|
648 |
||
649 |
v->date_of_last_service = _date; |
|
650 |
v->breakdowns_since_last_service = 0; |
|
651 |
v->reliability = _engines[v->engine_type].reliability; |
|
652 |
InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
|
653 |
} |
|
654 |
||
655 |
static void PlayAircraftSound(Vehicle *v) |
|
656 |
{ |
|
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
657 |
SndPlayVehicleFx(AircraftVehInfo(v->engine_type)->sfx, v); |
0 | 658 |
} |
659 |
||
660 |
static bool UpdateAircraftSpeed(Vehicle *v) |
|
661 |
{ |
|
662 |
uint spd = v->acceleration * 2; |
|
663 |
byte t; |
|
664 |
||
665 |
v->subspeed = (t=v->subspeed) + (byte)spd; |
|
666 |
spd = min( v->cur_speed + (spd >> 8) + (v->subspeed < t), v->max_speed); |
|
193
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
667 |
|
0 | 668 |
// adjust speed for broken vehicles |
669 |
if(v->vehstatus&VS_AIRCRAFT_BROKEN) spd = min(spd, 27); |
|
670 |
||
671 |
//updates statusbar only if speed have changed to save CPU time |
|
672 |
if (spd != v->cur_speed) { |
|
673 |
v->cur_speed = spd; |
|
674 |
if (_patches.vehicle_speed) |
|
675 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
676 |
} |
|
677 |
||
678 |
if (!(v->direction & 1)) { |
|
679 |
spd = spd * 3 >> 2; |
|
680 |
} |
|
681 |
||
682 |
if (spd == 0) |
|
683 |
return false; |
|
684 |
||
685 |
if ((byte)++spd == 0) |
|
686 |
return true; |
|
687 |
||
688 |
v->progress = (t = v->progress) - (byte)spd; |
|
689 |
||
690 |
return (t < v->progress); |
|
691 |
} |
|
692 |
||
693 |
// get Aircraft running altitude |
|
694 |
static byte GetAircraftFlyingAltitude(const Vehicle *v) |
|
695 |
{ |
|
696 |
byte maxz = 162; |
|
697 |
if (v->max_speed != 37) { |
|
698 |
maxz = 171; |
|
699 |
if (v->max_speed != 74) {maxz = 180;} |
|
700 |
} |
|
701 |
return maxz; |
|
702 |
} |
|
703 |
||
704 |
static bool Aircraft_5(Vehicle *v) |
|
705 |
{ |
|
706 |
Station *st; |
|
707 |
const AirportMovingData *amd; |
|
708 |
Vehicle *u; |
|
709 |
byte z,dirdiff,newdir,maxz,curz; |
|
710 |
GetNewVehiclePosResult gp; |
|
711 |
uint dist; |
|
712 |
int x,y; |
|
713 |
||
714 |
st = DEREF_STATION(v->u.air.targetairport); |
|
715 |
||
716 |
// prevent going to 0,0 if airport is deleted. |
|
717 |
{ |
|
718 |
uint tile = st->airport_tile; |
|
719 |
if (tile == 0) tile = st->xy; |
|
720 |
// xy of destination |
|
721 |
x = GET_TILE_X(tile)*16; |
|
722 |
y = GET_TILE_Y(tile)*16; |
|
723 |
} |
|
724 |
||
725 |
// get airport moving data |
|
726 |
assert(v->u.air.pos < GetAirport(st->airport_type)->nofelements); |
|
727 |
amd = &_airport_moving_datas[st->airport_type][v->u.air.pos]; |
|
728 |
||
729 |
// Helicopter raise |
|
730 |
if (amd->flag & AMED_HELI_RAISE) { |
|
731 |
u = v->next->next; |
|
732 |
||
733 |
// Make sure the rotors don't rotate too fast |
|
734 |
if (u->cur_speed > 32) { |
|
735 |
v->cur_speed = 0; |
|
736 |
if (--u->cur_speed == 32) { |
|
541 | 737 |
SndPlayVehicleFx(SND_18_HELICOPTER, v); |
0 | 738 |
} |
739 |
} else { |
|
740 |
u->cur_speed = 32; |
|
741 |
if (UpdateAircraftSpeed(v)) { |
|
742 |
v->tile = 0; |
|
743 |
||
744 |
// Reached altitude? |
|
745 |
if (v->z_pos >= 184) { |
|
746 |
v->cur_speed = 0; |
|
747 |
return true; |
|
748 |
} |
|
749 |
SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos+1); |
|
750 |
} |
|
751 |
} |
|
752 |
return false; |
|
753 |
} |
|
754 |
||
755 |
// Helicopter landing. |
|
756 |
if (amd->flag & AMED_HELI_LOWER) { |
|
757 |
if (UpdateAircraftSpeed(v)) { |
|
758 |
if (st->airport_tile == 0) { |
|
759 |
// FIXME - Aircraft_5 -> if station no longer exists, do not land |
|
760 |
// helicopter will circle until sign disappears, then go to next order |
|
761 |
// * what to do when it is the only order left, right now it just stays in 1 place |
|
762 |
v->u.air.state = FLYING; |
|
763 |
AircraftNextAirportPos_and_Order(v); |
|
764 |
return false; |
|
765 |
} |
|
766 |
||
767 |
// Vehicle is now at the airport. |
|
768 |
v->tile = st->airport_tile; |
|
769 |
||
770 |
// Find altitude of landing position. |
|
771 |
z = GetSlopeZ(x, y) + 1; |
|
772 |
if (st->airport_type == AT_OILRIG) z += 54; |
|
773 |
if (st->airport_type == AT_HELIPORT) z += 60; |
|
774 |
||
775 |
if (z == v->z_pos) { |
|
776 |
u = v->next->next; |
|
777 |
||
778 |
// Increase speed of rotors. When speed is 80, we've landed. |
|
779 |
if (u->cur_speed >= 80) |
|
780 |
return true; |
|
781 |
u->cur_speed+=4; |
|
782 |
} else if (v->z_pos > z) { |
|
783 |
SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos-1); |
|
784 |
} else { |
|
785 |
SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos+1); |
|
786 |
} |
|
787 |
} |
|
788 |
return false; |
|
789 |
} |
|
790 |
||
791 |
// Get distance from destination pos to current pos. |
|
792 |
dist = myabs(x + amd->x - v->x_pos) + myabs(y + amd->y - v->y_pos); |
|
793 |
||
794 |
// Need exact position? |
|
795 |
if (!(amd->flag & AMED_EXACTPOS) && dist <= (uint)((amd->flag&AMED_SLOWTURN)?8:4)) |
|
796 |
return true; |
|
797 |
||
798 |
// At final pos? |
|
799 |
if (dist == 0) { |
|
800 |
||
801 |
// Clamp speed to 12. |
|
802 |
if (v->cur_speed > 12) |
|
803 |
v->cur_speed = 12; |
|
804 |
||
805 |
// Change direction smoothly to final direction. |
|
806 |
dirdiff = amd->direction - v->direction; |
|
193
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
807 |
// if distance is 0, and plane points in right direction, no point in calling |
0 | 808 |
// UpdateAircraftSpeed(). So do it only afterwards |
809 |
if (dirdiff == 0) { |
|
810 |
v->cur_speed = 0; |
|
811 |
return true; |
|
812 |
} |
|
813 |
||
814 |
if (!UpdateAircraftSpeed(v)) |
|
815 |
return false; |
|
816 |
||
817 |
v->direction = (v->direction+((dirdiff&7)<5?1:-1)) & 7; |
|
818 |
v->cur_speed >>= 1; |
|
819 |
||
820 |
SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); |
|
821 |
return false; |
|
822 |
} |
|
823 |
||
824 |
// Clamp speed? |
|
825 |
if (!(amd->flag & AMED_NOSPDCLAMP) && v->cur_speed > 12) |
|
826 |
v->cur_speed = 12; |
|
827 |
||
828 |
if (!UpdateAircraftSpeed(v)) |
|
829 |
return false; |
|
830 |
||
831 |
// Decrease animation counter. |
|
832 |
if (v->load_unload_time_rem != 0) |
|
833 |
v->load_unload_time_rem--; |
|
834 |
||
835 |
// Turn. Do it slowly if in the air. |
|
836 |
newdir = GetDirectionTowards(v, x + amd->x, y + amd->y); |
|
837 |
if (newdir != v->direction) { |
|
838 |
if (amd->flag & AMED_SLOWTURN) { |
|
839 |
if (v->load_unload_time_rem == 0) { |
|
840 |
v->load_unload_time_rem = 8; |
|
841 |
} |
|
99 | 842 |
v->direction = newdir; |
0 | 843 |
} else { |
844 |
v->cur_speed >>= 1; |
|
845 |
v->direction = newdir; |
|
846 |
} |
|
847 |
} |
|
848 |
||
849 |
// Move vehicle. |
|
850 |
GetNewVehiclePos(v, &gp); |
|
851 |
v->tile = gp.new_tile; |
|
852 |
||
853 |
// If vehicle is in the air, use tile coordinate 0. |
|
854 |
if (amd->flag & (AMED_TAKEOFF | AMED_SLOWTURN | AMED_LAND)) { |
|
855 |
v->tile = 0; |
|
856 |
} |
|
857 |
||
858 |
// Adjust Z for land or takeoff? |
|
859 |
z = v->z_pos; |
|
860 |
||
861 |
if (amd->flag & AMED_TAKEOFF) { |
|
862 |
z+=2; |
|
863 |
// Determine running altitude |
|
864 |
maxz = GetAircraftFlyingAltitude(v); |
|
865 |
if (z > maxz) |
|
866 |
z = maxz; |
|
867 |
} |
|
868 |
||
869 |
if (amd->flag & AMED_LAND) { |
|
870 |
if (st->airport_tile == 0) { |
|
871 |
//FIXME -- FIXED - Aircraft_5 -> if station no longer exists, do not land |
|
872 |
// * what to do when it is the only order left, right now it just stays in 1 place? |
|
873 |
v->u.air.state = FLYING; |
|
874 |
AircraftNextAirportPos_and_Order(v); |
|
875 |
// get aircraft back on running altitude |
|
876 |
SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v)); |
|
877 |
return false; |
|
878 |
} |
|
879 |
||
880 |
curz = GetSlopeZ(x, y) + 1; |
|
881 |
||
882 |
if (curz > z) { |
|
883 |
z++; |
|
884 |
} else { |
|
885 |
int t = max(1, dist-4); |
|
886 |
||
887 |
z -= ((z - curz) + t - 1) / t; |
|
888 |
if (z < curz) z = curz; |
|
889 |
} |
|
890 |
} |
|
891 |
||
892 |
// We've landed. Decrase speed when we're reaching end of runway. |
|
893 |
if (amd->flag & AMED_BRAKE) { |
|
894 |
curz = GetSlopeZ(x, y) + 1; |
|
895 |
||
896 |
if (z > curz) z--; |
|
897 |
else if (z < curz) z++; |
|
898 |
||
899 |
if (dist < 64 && v->cur_speed > 12) |
|
900 |
v->cur_speed -= 4; |
|
901 |
} |
|
902 |
||
903 |
SetAircraftPosition(v, gp.x, gp.y, z); |
|
904 |
return false; |
|
905 |
} |
|
906 |
||
907 |
static const int8 _crashed_aircraft_moddir[4] = { |
|
908 |
-1,0,0,1 |
|
909 |
}; |
|
910 |
||
911 |
static void HandleCrashedAircraft(Vehicle *v) |
|
912 |
{ |
|
913 |
uint32 r; |
|
914 |
Station *st; |
|
915 |
||
916 |
v->u.air.crashed_counter++; |
|
917 |
||
918 |
if (v->u.air.crashed_counter < 650) { |
|
919 |
if (CHANCE16R(1,32,r)) { |
|
920 |
v->direction = (v->direction+_crashed_aircraft_moddir[(r >> 16)&3]) & 7; |
|
921 |
SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); |
|
922 |
r = Random(); |
|
923 |
CreateEffectVehicleRel(v, |
|
924 |
4 + (r&0xF), |
|
925 |
4 + ((r>>4)&0xF), |
|
926 |
((r>>8)&0xF), |
|
927 |
EV_DEMOLISH); |
|
928 |
} |
|
929 |
} else if (v->u.air.crashed_counter >= 10000) { |
|
930 |
st = DEREF_STATION(v->u.air.targetairport); |
|
931 |
// remove rubble of crashed airplane |
|
932 |
||
933 |
// clear runway-in on all airports, set by crashing plane |
|
934 |
// small airports use AIRPORT_BUSY, city airports use RUNWAY_IN_OUT_block, etc. |
|
935 |
// but they all share the same number |
|
936 |
CLRBITS(st->airport_flags, RUNWAY_IN_block); |
|
937 |
||
938 |
BeginVehicleMove(v); |
|
939 |
EndVehicleMove(v); |
|
940 |
||
941 |
DoDeleteAircraft(v); |
|
942 |
} |
|
943 |
} |
|
944 |
||
945 |
static void HandleBrokenAircraft(Vehicle *v) |
|
946 |
{ |
|
947 |
if (v->breakdown_ctr != 1) { |
|
948 |
v->breakdown_ctr = 1; |
|
949 |
v->vehstatus |= VS_AIRCRAFT_BROKEN; |
|
950 |
||
951 |
if (v->breakdowns_since_last_service != 255) |
|
952 |
v->breakdowns_since_last_service++; |
|
953 |
InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
|
954 |
InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
|
955 |
} |
|
956 |
} |
|
957 |
||
958 |
static const int8 _aircraft_smoke_xy[16] = { |
|
959 |
5,6,5,0,-5,-6,-5,0, /* x coordinates */ |
|
960 |
5,0,-5,-6,-5,0,5,6, /* y coordinate */ |
|
961 |
}; |
|
962 |
||
963 |
static void HandleAircraftSmoke(Vehicle *v) |
|
964 |
{ |
|
965 |
if (!(v->vehstatus&VS_AIRCRAFT_BROKEN)) |
|
966 |
return; |
|
967 |
||
968 |
if (v->cur_speed < 10) { |
|
969 |
v->vehstatus &= ~VS_AIRCRAFT_BROKEN; |
|
970 |
v->breakdown_ctr = 0; |
|
971 |
return; |
|
972 |
} |
|
973 |
||
974 |
if ((v->tick_counter & 0x1F) == 0) { |
|
975 |
CreateEffectVehicleRel(v, |
|
976 |
_aircraft_smoke_xy[v->direction], |
|
977 |
_aircraft_smoke_xy[v->direction + 8], |
|
978 |
2, |
|
979 |
EV_SMOKE_3 |
|
980 |
); |
|
981 |
} |
|
982 |
} |
|
983 |
||
984 |
static void ProcessAircraftOrder(Vehicle *v) |
|
985 |
{ |
|
986 |
uint order; |
|
987 |
||
988 |
// OT_GOTO_DEPOT, OT_LOADING |
|
989 |
if ((v->next_order & OT_MASK) >= OT_GOTO_DEPOT && (v->next_order & OT_MASK) <= OT_LOADING) { |
|
990 |
if ((v->next_order & (OT_MASK|OF_UNLOAD)) != (OT_GOTO_DEPOT|OF_UNLOAD)) |
|
991 |
return; |
|
992 |
} |
|
193
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
993 |
|
0 | 994 |
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:
99
diff
changeset
|
995 |
SERVICE_INTERVAL) { |
0 | 996 |
v->cur_order_index++; |
997 |
} |
|
998 |
||
999 |
if (v->cur_order_index >= v->num_orders) |
|
1000 |
v->cur_order_index = 0; |
|
1001 |
||
1002 |
order = v->schedule_ptr[v->cur_order_index]; |
|
1003 |
||
1004 |
if (order == 0) { |
|
1005 |
v->next_order = OT_NOTHING; |
|
1006 |
return; |
|
1007 |
} |
|
1008 |
||
1009 |
if (order == (uint)((v->next_order | (v->next_order_param<<8)))) |
|
1010 |
return; |
|
1011 |
||
1012 |
v->next_order = (byte)order; |
|
1013 |
v->next_order_param = (byte)(order >> 8); |
|
1014 |
||
1015 |
// orders are changed in flight, ensure going to the right station |
|
1016 |
if ((order & OT_MASK) == OT_GOTO_STATION && v->u.air.state == FLYING) { |
|
1017 |
AircraftNextAirportPos_and_Order(v); |
|
1018 |
v->u.air.targetairport = order >> 8; |
|
1019 |
} |
|
1020 |
||
1021 |
InvalidateVehicleOrderWidget(v); |
|
1022 |
} |
|
1023 |
||
1024 |
static void HandleAircraftLoading(Vehicle *v, int mode) |
|
1025 |
{ |
|
1026 |
if (v->next_order == OT_NOTHING) |
|
1027 |
return; |
|
1028 |
||
1029 |
if (v->next_order != OT_DUMMY) { |
|
1030 |
if ((v->next_order&OT_MASK) != OT_LOADING) |
|
1031 |
return; |
|
1032 |
||
1033 |
if (mode != 0) |
|
1034 |
return; |
|
1035 |
||
1036 |
if (--v->load_unload_time_rem) |
|
1037 |
return; |
|
1038 |
||
1039 |
if (v->next_order&OF_FULL_LOAD && CanFillVehicle(v)) { |
|
1040 |
SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_INC); |
|
1041 |
LoadUnloadVehicle(v); |
|
1042 |
return; |
|
1043 |
} |
|
1044 |
||
1045 |
{ |
|
1046 |
byte b = v->next_order; |
|
1047 |
v->next_order = OT_NOTHING; |
|
1048 |
if (!(b & OF_NON_STOP)) |
|
1049 |
return; |
|
1050 |
} |
|
1051 |
} |
|
1052 |
v->cur_order_index++; |
|
1053 |
InvalidateVehicleOrderWidget(v); |
|
1054 |
} |
|
1055 |
||
1056 |
static void MaybeCrashAirplane(Vehicle *v) |
|
1057 |
{ |
|
1058 |
Station *st; |
|
1059 |
uint16 prob; |
|
1060 |
int i; |
|
1061 |
uint16 amt; |
|
1062 |
||
1063 |
st = DEREF_STATION(v->u.air.targetairport); |
|
1064 |
||
1065 |
//FIXME -- MaybeCrashAirplane -> increase crashing chances of very modern airplanes on smaller than AT_METROPOLITAN airports |
|
1066 |
prob = 0x10000 / 1500; |
|
538
24fdb517fbe5
(svn r920) Replace vehicle info macros with inline functions and add asserts to check limits
tron
parents:
534
diff
changeset
|
1067 |
if (st->airport_type == AT_SMALL && (AircraftVehInfo(v->engine_type)->subtype & 2) && !_cheats.no_jetcrash.value) { |
0 | 1068 |
prob = 0x10000 / 20; |
1069 |
} |
|
1070 |
||
1071 |
if ((uint16)Random() > prob) |
|
1072 |
return; |
|
1073 |
||
1074 |
// Crash the airplane. Remove all goods stored at the station. |
|
1075 |
for(i=0; i!=NUM_CARGO; i++) { |
|
1076 |
st->goods[i].rating = 1; |
|
1077 |
st->goods[i].waiting_acceptance &= ~0xFFF; |
|
1078 |
} |
|
1079 |
||
1080 |
v->vehstatus |= VS_CRASHED; |
|
1081 |
v->u.air.crashed_counter = 0; |
|
1082 |
||
1083 |
CreateEffectVehicleRel(v, 4, 4, 8, EV_CRASHED_SMOKE); |
|
1084 |
||
1085 |
InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
|
1086 |
||
1087 |
amt = 2; |
|
1088 |
if (v->cargo_type == CT_PASSENGERS) amt += v->cargo_count; |
|
534
306bc86eb23e
(svn r901) Small step in the process to clean up the DPARAM mess:
tron
parents:
507
diff
changeset
|
1089 |
SetDParam(0, amt); |
0 | 1090 |
|
1091 |
v->cargo_count = 0; |
|
1092 |
v->next->cargo_count = 0, |
|
1093 |
||
534
306bc86eb23e
(svn r901) Small step in the process to clean up the DPARAM mess:
tron
parents:
507
diff
changeset
|
1094 |
SetDParam(1, st->index); |
0 | 1095 |
AddNewsItem(STR_A034_PLANE_CRASH_DIE_IN_FIREBALL, |
1096 |
NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0), |
|
1097 |
v->index, |
|
1098 |
0); |
|
1099 |
||
1100 |
ModifyStationRatingAround(TILE_FROM_XY(v->x_pos, v->y_pos), v->owner, -160, 30); |
|
541 | 1101 |
SndPlayVehicleFx(SND_12_EXPLOSION, v); |
0 | 1102 |
} |
1103 |
||
1104 |
// we've landed and just arrived at a terminal |
|
1105 |
static void AircraftEntersTerminal(Vehicle *v) |
|
1106 |
{ |
|
1107 |
Station *st; |
|
1108 |
byte old_order; |
|
1109 |
||
1110 |
if ((v->next_order & OT_MASK) == OT_GOTO_DEPOT) |
|
1111 |
return; |
|
1112 |
||
1113 |
st = DEREF_STATION(v->u.air.targetairport); |
|
1114 |
v->last_station_visited = v->u.air.targetairport; |
|
1115 |
||
1116 |
/* Check if station was ever visited before */ |
|
1117 |
if (!(st->had_vehicle_of_type & HVOT_AIRCRAFT)) { |
|
1118 |
uint32 flags; |
|
1119 |
||
1120 |
st->had_vehicle_of_type |= HVOT_AIRCRAFT; |
|
534
306bc86eb23e
(svn r901) Small step in the process to clean up the DPARAM mess:
tron
parents:
507
diff
changeset
|
1121 |
SetDParam(0, st->index); |
0 | 1122 |
// show newsitem of celebrating citizens |
1123 |
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); |
|
1124 |
AddNewsItem( |
|
1125 |
STR_A033_CITIZENS_CELEBRATE_FIRST, |
|
1126 |
flags, |
|
1127 |
v->index, |
|
1128 |
0); |
|
1129 |
} |
|
1130 |
||
1131 |
old_order = v->next_order; |
|
1132 |
v->next_order = OT_LOADING; |
|
1133 |
||
1134 |
if ((old_order & OT_MASK) == OT_GOTO_STATION && |
|
1135 |
v->next_order_param == v->last_station_visited) { |
|
1136 |
v->next_order = OT_LOADING | (old_order & (OF_UNLOAD|OF_FULL_LOAD)) | OF_NON_STOP; |
|
1137 |
} |
|
1138 |
||
1139 |
SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_INC); |
|
1140 |
LoadUnloadVehicle(v); |
|
1141 |
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
|
1142 |
} |
|
1143 |
||
1144 |
static void AircraftEnterHangar(Vehicle *v) |
|
1145 |
{ |
|
1146 |
byte old_order; |
|
1147 |
||
1148 |
ServiceAircraft(v); |
|
193
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
1149 |
|
0 | 1150 |
MaybeRenewVehicle(v, EstimateAircraftCost(v->engine_type)); |
1151 |
||
445
beafc0fb8f12
(svn r654) Hopefully complete support for randomized variational spritegroups (i.e. the cars transporter in DBSetXL gets different cars each time) (pasky)
tron
parents:
410
diff
changeset
|
1152 |
TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT); |
beafc0fb8f12
(svn r654) Hopefully complete support for randomized variational spritegroups (i.e. the cars transporter in DBSetXL gets different cars each time) (pasky)
tron
parents:
410
diff
changeset
|
1153 |
|
0 | 1154 |
if ((v->next_order & OT_MASK) == OT_GOTO_DEPOT) { |
1155 |
InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
|
1156 |
||
1157 |
old_order = v->next_order; |
|
1158 |
v->next_order = OT_NOTHING; |
|
1159 |
||
1160 |
if (old_order & OF_UNLOAD) { v->cur_order_index++; } |
|
193
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
1161 |
|
0 | 1162 |
else if (old_order & OF_FULL_LOAD) { // force depot visit |
1163 |
v->vehstatus |= VS_STOPPED; |
|
1164 |
||
1165 |
if (v->owner == _local_player) { |
|
534
306bc86eb23e
(svn r901) Small step in the process to clean up the DPARAM mess:
tron
parents:
507
diff
changeset
|
1166 |
SetDParam(0, v->unitnumber); |
0 | 1167 |
AddNewsItem( |
1168 |
STR_A014_AIRCRAFT_IS_WAITING_IN, |
|
1169 |
NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), |
|
1170 |
v->index, |
|
1171 |
0); |
|
1172 |
} |
|
1173 |
} |
|
1174 |
} |
|
1175 |
} |
|
1176 |
||
1177 |
static void AircraftLand(Vehicle *v) |
|
1178 |
{ |
|
1179 |
v->sprite_width = v->sprite_height = 2; |
|
1180 |
} |
|
1181 |
||
1182 |
static void AircraftLandAirplane(Vehicle *v) |
|
1183 |
{ |
|
1184 |
AircraftLand(v); |
|
541 | 1185 |
SndPlayVehicleFx(SND_17_SKID_PLANE, v); |
0 | 1186 |
MaybeCrashAirplane(v); |
1187 |
} |
|
1188 |
||
1189 |
// set the right pos when heading to other airports after takeoff |
|
1190 |
static void AircraftNextAirportPos_and_Order(Vehicle *v) |
|
1191 |
{ |
|
1192 |
Station *st; |
|
1193 |
const AirportFTAClass *Airport; |
|
1194 |
||
1195 |
if ((v->next_order&OT_MASK) == OT_GOTO_STATION || |
|
1196 |
(v->next_order&OT_MASK) == OT_GOTO_DEPOT) |
|
1197 |
v->u.air.targetairport = v->next_order_param; |
|
1198 |
||
1199 |
st = DEREF_STATION(v->u.air.targetairport); |
|
1200 |
Airport = GetAirport(st->airport_type); |
|
1201 |
v->u.air.pos = v->u.air.previous_pos = Airport->entry_point; |
|
1202 |
} |
|
1203 |
||
1204 |
static void AircraftLeaveHangar(Vehicle *v) |
|
1205 |
{ |
|
1206 |
v->cur_speed = 0; |
|
1207 |
v->subspeed = 0; |
|
1208 |
v->progress = 0; |
|
1209 |
v->direction = 3; |
|
1210 |
v->vehstatus &= ~VS_HIDDEN; |
|
1211 |
{ |
|
1212 |
Vehicle *u = v->next; |
|
1213 |
u->vehstatus &= ~VS_HIDDEN; |
|
1214 |
||
1215 |
// Rotor blades |
|
1216 |
if ((u=u->next) != NULL) { |
|
1217 |
u->vehstatus &= ~VS_HIDDEN; |
|
1218 |
u->cur_speed = 80; |
|
1219 |
} |
|
1220 |
} |
|
1221 |
||
1222 |
SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); |
|
1223 |
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
|
1224 |
} |
|
1225 |
||
1226 |
||
1227 |
//////////////////////////////////////////////////////////////////////////////// |
|
1228 |
/////////////////// AIRCRAFT MOVEMENT SCHEME //////////////////////////////// |
|
1229 |
//////////////////////////////////////////////////////////////////////////////// |
|
1230 |
static void AircraftEventHandler_EnterTerminal(Vehicle *v, const AirportFTAClass *Airport) |
|
1231 |
{ |
|
1232 |
AircraftEntersTerminal(v); |
|
1233 |
v->u.air.state = Airport->layout[v->u.air.pos].heading; |
|
1234 |
} |
|
1235 |
||
1236 |
static void AircraftEventHandler_EnterHangar(Vehicle *v, const AirportFTAClass *Airport) |
|
1237 |
{ |
|
1238 |
AircraftEnterHangar(v); |
|
1239 |
v->u.air.state = Airport->layout[v->u.air.pos].heading; |
|
1240 |
} |
|
1241 |
||
1242 |
// In an Airport Hangar |
|
1243 |
static void AircraftEventHandler_InHangar(Vehicle *v, const AirportFTAClass *Airport) |
|
1244 |
{ |
|
1245 |
// if we just arrived, execute EnterHangar first |
|
1246 |
if (v->u.air.previous_pos != v->u.air.pos) { |
|
1247 |
AircraftEventHandler_EnterHangar(v, Airport); |
|
1248 |
return; |
|
1249 |
} |
|
1250 |
||
1251 |
if ((v->next_order&OT_MASK) == OT_GOTO_DEPOT && (v->vehstatus&VS_STOPPED)) { // if we were sent to the depot, stay there |
|
1252 |
v->next_order = OT_NOTHING; |
|
1253 |
return; |
|
1254 |
} |
|
1255 |
||
1256 |
if ((v->next_order&OT_MASK) != OT_GOTO_STATION && (v->next_order&OT_MASK) != OT_GOTO_DEPOT) |
|
1257 |
return; |
|
1258 |
||
1259 |
// if the block of the next position is busy, stay put |
|
1260 |
if (AirportHasBlock(v, &Airport->layout[v->u.air.pos], Airport)) {return;} |
|
1261 |
||
1262 |
// We are already at the target airport, we need to find a terminal |
|
1263 |
if (v->next_order_param == v->u.air.targetairport) { |
|
1264 |
// FindFreeTerminal: |
|
1265 |
// 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal |
|
1266 |
if (v->subtype != 0) {if(!AirportFindFreeTerminal(v, Airport)) {return;}} // airplane |
|
1267 |
else {if(!AirportFindFreeHelipad(v, Airport)) {return;}} // helicopter |
|
1268 |
} |
|
1269 |
else { // Else prepare for launch. |
|
1270 |
// airplane goto state takeoff, helicopter to helitakeoff |
|
1271 |
v->u.air.state = (v->subtype != 0) ? TAKEOFF : HELITAKEOFF; |
|
1272 |
} |
|
1273 |
AircraftLeaveHangar(v); |
|
1274 |
AirportMove(v, Airport); |
|
1275 |
} |
|
1276 |
||
1277 |
// At one of the Airport's Terminals |
|
1278 |
static void AircraftEventHandler_AtTerminal(Vehicle *v, const AirportFTAClass *Airport) |
|
1279 |
{ |
|
1280 |
// if we just arrived, execute EnterTerminal first |
|
1281 |
if (v->u.air.previous_pos != v->u.air.pos) { |
|
1282 |
AircraftEventHandler_EnterTerminal(v, Airport); |
|
1283 |
// on an airport with helipads, a helicopter will always land there |
|
1284 |
// and get serviced at the same time - patch setting |
|
1285 |
if (_patches.serviceathelipad) { |
|
1286 |
if (v->subtype == 0 && Airport->nofhelipads > 0) { |
|
1287 |
// an exerpt of ServiceAircraft, without the invisibility stuff |
|
1288 |
v->date_of_last_service = _date; |
|
1289 |
v->breakdowns_since_last_service = 0; |
|
1290 |
v->reliability = _engines[v->engine_type].reliability; |
|
1291 |
InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
|
1292 |
} |
|
1293 |
} |
|
1294 |
return; |
|
1295 |
} |
|
1296 |
||
1297 |
// removed &0x1F |
|
1298 |
if (v->next_order == OT_NOTHING) {return;} |
|
1299 |
||
1300 |
// if the block of the next position is busy, stay put |
|
1301 |
if (AirportHasBlock(v, &Airport->layout[v->u.air.pos], Airport)) { |
|
1302 |
return; |
|
1303 |
} |
|
1304 |
||
1305 |
// airport-road is free. We either have to go to another airport, or to the hangar |
|
1306 |
// ---> start moving |
|
1307 |
||
1308 |
switch (v->next_order&OT_MASK) { |
|
1309 |
case OT_GOTO_STATION: // ready to fly to another airport |
|
1310 |
// airplane goto state takeoff, helicopter to helitakeoff |
|
1311 |
v->u.air.state = (v->subtype != 0) ? TAKEOFF : HELITAKEOFF; |
|
1312 |
break; |
|
1313 |
case OT_GOTO_DEPOT: // visit hangar for serivicing, sale, etc. |
|
1314 |
if (v->next_order_param == v->u.air.targetairport) |
|
1315 |
v->u.air.state = HANGAR; |
|
1316 |
else |
|
1317 |
v->u.air.state = (v->subtype != 0) ? TAKEOFF : HELITAKEOFF; |
|
1318 |
break; |
|
1319 |
default: // orders have been deleted (no orders), goto depot and don't bother us |
|
1320 |
v->next_order = OT_NOTHING; |
|
1321 |
v->u.air.state = HANGAR; |
|
1322 |
} |
|
1323 |
AirportMove(v, Airport); |
|
1324 |
} |
|
1325 |
||
1326 |
static void AircraftEventHandler_General(Vehicle *v, const AirportFTAClass *Airport) |
|
1327 |
{ |
|
70
60216d94f7c1
(svn r71) -Cheat: [976127] no extra frequent jet crash on small airports (truesatan)
darkvater
parents:
19
diff
changeset
|
1328 |
DEBUG(misc, 0) ("OK, you shouldn't be here, check your Airport Scheme!"); |
60216d94f7c1
(svn r71) -Cheat: [976127] no extra frequent jet crash on small airports (truesatan)
darkvater
parents:
19
diff
changeset
|
1329 |
assert(0); |
0 | 1330 |
} |
1331 |
||
1332 |
static void AircraftEventHandler_TakeOff(Vehicle *v, const AirportFTAClass *Airport) { |
|
1333 |
PlayAircraftSound(v); // play takeoffsound for airplanes |
|
1334 |
v->u.air.state = STARTTAKEOFF; |
|
1335 |
} |
|
1336 |
||
1337 |
static void AircraftEventHandler_StartTakeOff(Vehicle *v, const AirportFTAClass *Airport) |
|
1338 |
{ |
|
1339 |
v->sprite_width = v->sprite_height = 24; // ??? no idea what this is |
|
1340 |
v->u.air.state = ENDTAKEOFF; |
|
1341 |
} |
|
1342 |
||
1343 |
static void AircraftEventHandler_EndTakeOff(Vehicle *v, const AirportFTAClass *Airport) |
|
1344 |
{ |
|
1345 |
v->u.air.state = FLYING; |
|
1346 |
// get the next position to go to, differs per airport |
|
1347 |
AircraftNextAirportPos_and_Order(v); |
|
1348 |
} |
|
1349 |
||
1350 |
static void AircraftEventHandler_HeliTakeOff(Vehicle *v, const AirportFTAClass *Airport) |
|
1351 |
{ |
|
1352 |
v->sprite_width = v->sprite_height = 24; // ??? no idea what this is |
|
1353 |
v->u.air.state = FLYING; |
|
1354 |
// get the next position to go to, differs per airport |
|
1355 |
AircraftNextAirportPos_and_Order(v); |
|
1356 |
} |
|
1357 |
||
1358 |
static void AircraftEventHandler_Flying(Vehicle *v, const AirportFTAClass *Airport) |
|
1359 |
{ |
|
1360 |
Station *st; |
|
1361 |
byte landingtype; |
|
1362 |
AirportFTA *current; |
|
1363 |
uint16 tcur_speed, tsubspeed; |
|
1364 |
||
1365 |
st = DEREF_STATION(v->u.air.targetairport); |
|
1366 |
// flying device is accepted at this station |
|
1367 |
// small airport --> no helicopters (AIRCRAFT_ONLY) |
|
1368 |
// all other airports --> all types of flying devices (ALL) |
|
1369 |
// heliport/oilrig, etc --> no airplanes (HELICOPTERS_ONLY) |
|
1370 |
// runway busy or not allowed to use this airstation, circle |
|
1371 |
if (! (v->subtype == Airport->acc_planes || |
|
1372 |
st->airport_tile == 0 || (st->owner != OWNER_NONE && st->owner != v->owner) )) { |
|
1373 |
||
1374 |
// {32,FLYING,NOTHING_block,37}, {32,LANDING,N,33}, {32,HELILANDING,N,41}, |
|
1375 |
// if it is an airplane, look for LANDING, for helicopter HELILANDING |
|
1376 |
// it is possible to choose from multiple landing runways, so loop until a free one is found |
|
1377 |
landingtype = (v->subtype != 0) ? LANDING : HELILANDING; |
|
1378 |
current = Airport->layout[v->u.air.pos].next_in_chain; |
|
1379 |
while (current != NULL) { |
|
1380 |
if (current->heading == landingtype) { |
|
1381 |
// save speed before, since if AirportHasBlock is false, it resets them to 0 |
|
1382 |
// we don't want that for plane in air |
|
1383 |
// hack for speed thingie |
|
1384 |
tcur_speed = v->cur_speed; |
|
1385 |
tsubspeed = v->subspeed; |
|
1386 |
if (!AirportHasBlock(v, current, Airport)) { |
|
1387 |
v->u.air.state = landingtype; // LANDING / HELILANDING |
|
1388 |
// it's a bit dirty, but I need to set position to next position, otherwise |
|
1389 |
// if there are multiple runways, plane won't know which one it took (because |
|
1390 |
// they all have heading LANDING). And also occupy that block! |
|
1391 |
v->u.air.pos = current->next_position; |
|
1392 |
SETBITS(st->airport_flags, Airport->layout[v->u.air.pos].block); |
|
1393 |
return; |
|
1394 |
} |
|
1395 |
v->cur_speed = tcur_speed; |
|
1396 |
v->subspeed = tsubspeed; |
|
1397 |
} |
|
1398 |
current = current->next_in_chain; |
|
1399 |
} |
|
1400 |
} |
|
1401 |
v->u.air.state = FLYING; |
|
1402 |
v->u.air.pos = Airport->layout[v->u.air.pos].next_position; |
|
1403 |
} |
|
1404 |
||
1405 |
static void AircraftEventHandler_Landing(Vehicle *v, const AirportFTAClass *Airport) |
|
1406 |
{ |
|
1407 |
AircraftLandAirplane(v); // maybe crash airplane |
|
1408 |
v->u.air.state = ENDLANDING; |
|
1409 |
} |
|
1410 |
||
1411 |
static void AircraftEventHandler_HeliLanding(Vehicle *v, const AirportFTAClass *Airport) |
|
1412 |
{ |
|
1413 |
AircraftLand(v); // helicopters don't crash |
|
1414 |
v->u.air.state = HELIENDLANDING; |
|
1415 |
} |
|
1416 |
||
1417 |
static void AircraftEventHandler_EndLanding(Vehicle *v, const AirportFTAClass *Airport) |
|
1418 |
{ |
|
1419 |
// next block busy, don't do a thing, just wait |
|
1420 |
if(AirportHasBlock(v, &Airport->layout[v->u.air.pos], Airport)) {return;} |
|
1421 |
||
1422 |
// if going to terminal (OT_GOTO_STATION) choose one |
|
1423 |
// 1. in case all terminals are busy AirportFindFreeTerminal() returns false or |
|
1424 |
// 2. not going for terminal (but depot, no order), |
|
1425 |
// --> get out of the way to the hangar. |
|
1426 |
if ((v->next_order&OT_MASK) == OT_GOTO_STATION) { |
|
1427 |
if (AirportFindFreeTerminal(v, Airport)) {return;} |
|
1428 |
} |
|
1429 |
v->u.air.state = HANGAR; |
|
1430 |
||
1431 |
} |
|
1432 |
||
1433 |
static void AircraftEventHandler_HeliEndLanding(Vehicle *v, const AirportFTAClass *Airport) |
|
1434 |
{ |
|
1435 |
// next block busy, don't do a thing, just wait |
|
1436 |
if(AirportHasBlock(v, &Airport->layout[v->u.air.pos], Airport)) {return;} |
|
1437 |
||
1438 |
// if going to helipad (OT_GOTO_STATION) choose one. If airport doesn't have helipads, choose terminal |
|
1439 |
// 1. in case all terminals/helipads are busy (AirportFindFreeHelipad() returns false) or |
|
1440 |
// 2. not going for terminal (but depot, no order), |
|
1441 |
// --> get out of the way to the hangar IF there are terminals on the airport. |
|
1442 |
// --> else TAKEOFF |
|
1443 |
// the reason behind this is that if an airport has a terminal, it also has a hangar. Airplanes |
|
1444 |
// must go to a hangar. |
|
1445 |
if ((v->next_order&OT_MASK) == OT_GOTO_STATION) { |
|
1446 |
if (AirportFindFreeHelipad(v, Airport)) {return;} |
|
1447 |
} |
|
1448 |
v->u.air.state = (Airport->nofterminals != 0) ? HANGAR : HELITAKEOFF; |
|
1449 |
} |
|
1450 |
||
1451 |
typedef void AircraftStateHandler(Vehicle *v, const AirportFTAClass *Airport); |
|
1452 |
static AircraftStateHandler * const _aircraft_state_handlers[] = { |
|
1453 |
AircraftEventHandler_General, // TO_ALL = 0 |
|
1454 |
AircraftEventHandler_InHangar, // HANGAR = 1 |
|
1455 |
AircraftEventHandler_AtTerminal, // TERM1 = 2 |
|
1456 |
AircraftEventHandler_AtTerminal, // TERM2 = 3 |
|
1457 |
AircraftEventHandler_AtTerminal, // TERM3 = 4 |
|
1458 |
AircraftEventHandler_AtTerminal, // TERM4 = 5 |
|
1459 |
AircraftEventHandler_AtTerminal, // TERM5 = 6 |
|
1460 |
AircraftEventHandler_AtTerminal, // TERM6 = 7 |
|
1461 |
AircraftEventHandler_AtTerminal, // HELIPAD1 = 8 |
|
1462 |
AircraftEventHandler_AtTerminal, // HELIPAD2 = 9 |
|
1463 |
AircraftEventHandler_TakeOff, // TAKEOFF = 10 |
|
1464 |
AircraftEventHandler_StartTakeOff, // STARTTAKEOFF = 11 |
|
1465 |
AircraftEventHandler_EndTakeOff, // ENDTAKEOFF = 12 |
|
1466 |
AircraftEventHandler_HeliTakeOff, // HELITAKEOFF = 13 |
|
1467 |
AircraftEventHandler_Flying, // FLYING = 14 |
|
1468 |
AircraftEventHandler_Landing, // LANDING = 15 |
|
1469 |
AircraftEventHandler_EndLanding, // ENDLANDING = 16 |
|
1470 |
AircraftEventHandler_HeliLanding, // HELILANDING = 17 |
|
1471 |
AircraftEventHandler_HeliEndLanding,// HELIENDLANDING = 18 |
|
1472 |
}; |
|
1473 |
||
1474 |
static void AirportClearBlock(Vehicle *v, const AirportFTAClass *Airport) |
|
1475 |
{ |
|
1476 |
Station *st; |
|
1477 |
// we have left the previous block, and entered the new one. Free the previous block |
|
1478 |
if (Airport->layout[v->u.air.previous_pos].block != Airport->layout[v->u.air.pos].block) { |
|
1479 |
st = DEREF_STATION(v->u.air.targetairport); |
|
1480 |
CLRBITS(st->airport_flags, Airport->layout[v->u.air.previous_pos].block); |
|
1481 |
} |
|
1482 |
} |
|
1483 |
||
1484 |
static void AirportGoToNextPosition(Vehicle *v, const AirportFTAClass *Airport) |
|
1485 |
{ |
|
1486 |
// if aircraft is not in position, wait until it is |
|
1487 |
if (!Aircraft_5(v)) {return;} |
|
1488 |
||
1489 |
AirportClearBlock(v, Airport); |
|
1490 |
AirportMove(v, Airport); // move aircraft to next position |
|
1491 |
} |
|
1492 |
||
1493 |
// gets pos from vehicle and next orders |
|
1494 |
static bool AirportMove(Vehicle *v, const AirportFTAClass *Airport) |
|
1495 |
{ |
|
1496 |
AirportFTA *current; |
|
1497 |
byte prev_pos; |
|
1498 |
bool retval = false; |
|
1499 |
||
1500 |
// error handling |
|
1501 |
if (v->u.air.pos >= Airport->nofelements) { |
|
70
60216d94f7c1
(svn r71) -Cheat: [976127] no extra frequent jet crash on small airports (truesatan)
darkvater
parents:
19
diff
changeset
|
1502 |
DEBUG(misc, 0) ("position %d is not valid for current airport. Max position is %d", v->u.air.pos, Airport->nofelements-1); |
0 | 1503 |
assert(v->u.air.pos < Airport->nofelements); |
1504 |
} |
|
1505 |
||
1506 |
current = &Airport->layout[v->u.air.pos]; |
|
1507 |
// we have arrived in an important state (eg terminal, hangar, etc.) |
|
1508 |
if (current->heading == v->u.air.state) { |
|
1509 |
prev_pos = v->u.air.pos; // location could be changed in state, so save it before-hand |
|
1510 |
_aircraft_state_handlers[v->u.air.state](v, Airport); |
|
1511 |
if (v->u.air.state != FLYING) {v->u.air.previous_pos = prev_pos;} |
|
1512 |
return true; |
|
1513 |
} |
|
1514 |
||
1515 |
v->u.air.previous_pos = v->u.air.pos; // save previous location |
|
1516 |
||
1517 |
// there is only one choice to move to |
|
1518 |
if (current->next_in_chain == NULL) { |
|
1519 |
if (AirportSetBlocks(v, current, Airport)) { |
|
1520 |
v->u.air.pos = current->next_position; |
|
1521 |
} // move to next position |
|
1522 |
return retval; |
|
1523 |
} |
|
1524 |
||
1525 |
// there are more choices to choose from, choose the one that |
|
1526 |
// matches our heading |
|
1527 |
do { |
|
1528 |
if (v->u.air.state == current->heading || current->heading == TO_ALL) { |
|
1529 |
if (AirportSetBlocks(v, current, Airport)) { |
|
1530 |
v->u.air.pos = current->next_position; |
|
1531 |
} // move to next position |
|
1532 |
return retval; |
|
1533 |
} |
|
1534 |
current = current->next_in_chain; |
|
1535 |
} while (current != NULL); |
|
1536 |
||
70
60216d94f7c1
(svn r71) -Cheat: [976127] no extra frequent jet crash on small airports (truesatan)
darkvater
parents:
19
diff
changeset
|
1537 |
DEBUG(misc, 0) ("Cannot move further on Airport...! pos:%d state:%d", v->u.air.pos, v->u.air.state); |
60216d94f7c1
(svn r71) -Cheat: [976127] no extra frequent jet crash on small airports (truesatan)
darkvater
parents:
19
diff
changeset
|
1538 |
DEBUG(misc, 0) ("Airport entry point: %d, Vehicle: %d", Airport->entry_point, v->index); |
0 | 1539 |
assert(0); |
1540 |
return false; |
|
1541 |
} |
|
1542 |
||
1543 |
// returns true if the road ahead is busy, eg. you must wait before proceeding |
|
1544 |
static bool AirportHasBlock(Vehicle *v, AirportFTA *current_pos, const AirportFTAClass *Airport) |
|
1545 |
{ |
|
1546 |
Station *st; |
|
1547 |
uint32 airport_flags; |
|
1548 |
AirportFTA *next, *reference; |
|
1549 |
reference = &Airport->layout[v->u.air.pos]; |
|
1550 |
next = &Airport->layout[current_pos->next_position]; |
|
1551 |
||
1552 |
// same block, then of course we can move |
|
1553 |
if (Airport->layout[current_pos->position].block != next->block) { |
|
1554 |
airport_flags = next->block; |
|
1555 |
st = DEREF_STATION(v->u.air.targetairport); |
|
1556 |
// check additional possible extra blocks |
|
1557 |
if (current_pos != reference && current_pos->block != NOTHING_block) { |
|
1558 |
airport_flags |= current_pos->block; |
|
1559 |
} |
|
1560 |
||
1561 |
if (HASBITS(st->airport_flags, airport_flags)) { |
|
1562 |
v->cur_speed = 0; |
|
1563 |
v->subspeed = 0; |
|
1564 |
return true; |
|
1565 |
} |
|
1566 |
} |
|
1567 |
return false; |
|
1568 |
} |
|
1569 |
||
1570 |
// returns true on success. Eg, next block was free and we have occupied it |
|
1571 |
static bool AirportSetBlocks(Vehicle *v, AirportFTA *current_pos, const AirportFTAClass *Airport) |
|
1572 |
{ |
|
1573 |
Station *st; |
|
1574 |
uint32 airport_flags; |
|
1575 |
AirportFTA *current, *reference, *next; |
|
1576 |
next = &Airport->layout[current_pos->next_position]; |
|
1577 |
reference = &Airport->layout[v->u.air.pos]; |
|
1578 |
||
1579 |
// if the next position is in another block, check it and wait until it is free |
|
1580 |
if (Airport->layout[current_pos->position].block != next->block) { |
|
1581 |
airport_flags = next->block; |
|
1582 |
st = DEREF_STATION(v->u.air.targetairport); |
|
1583 |
//search for all all elements in the list with the same state, and blocks != N |
|
1584 |
// this means more blocks should be checked/set |
|
1585 |
current = current_pos; |
|
1586 |
if (current == reference) { current = current->next_in_chain;} |
|
1587 |
while (current != NULL) { |
|
1588 |
if (current->heading == current_pos->heading && current->block != 0) { |
|
1589 |
airport_flags |= current->block; |
|
1590 |
break; |
|
1591 |
} |
|
1592 |
current = current->next_in_chain; |
|
1593 |
}; |
|
1594 |
||
1595 |
// if the block to be checked is in the next position, then exclude that from |
|
1596 |
// checking, because it has been set by the airplane before |
|
1597 |
if (current_pos->block == next->block) {airport_flags ^= next->block;} |
|
1598 |
||
1599 |
if (HASBITS(st->airport_flags, airport_flags)) { |
|
1600 |
v->cur_speed = 0; |
|
1601 |
v->subspeed = 0; |
|
1602 |
return false; |
|
1603 |
} |
|
1604 |
||
1605 |
if (next->block != NOTHING_block) { |
|
1606 |
SETBITS(st->airport_flags, airport_flags); // occupy next block |
|
1607 |
} |
|
1608 |
} |
|
1609 |
return true; |
|
1610 |
} |
|
1611 |
||
1612 |
static bool FreeTerminal(Vehicle *v, byte i, byte last_terminal) |
|
1613 |
{ |
|
1614 |
Station *st = DEREF_STATION(v->u.air.targetairport); |
|
1615 |
for (; i < last_terminal; i++) { |
|
1616 |
if (!HASBIT(st->airport_flags, i)) { |
|
1617 |
// TERMINAL# HELIPAD# |
|
1618 |
v->u.air.state = i + TERM1; // start moving to that terminal/helipad |
|
1619 |
SETBIT(st->airport_flags, i); // occupy terminal/helipad |
|
1620 |
return true; |
|
1621 |
} |
|
1622 |
} |
|
1623 |
return false; |
|
1624 |
} |
|
1625 |
||
193
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
1626 |
static bool AirportFindFreeTerminal(Vehicle *v, const AirportFTAClass *Airport) |
0 | 1627 |
{ |
1628 |
byte nofterminalspergroup, i; |
|
1629 |
AirportFTA *temp; |
|
1630 |
Station *st; |
|
1631 |
||
1632 |
/* example of more terminalgroups |
|
1633 |
{0,HANGAR,NOTHING_block,1}, {0,255,TERM_GROUP1_block,0}, {0,255,TERM_GROUP2_ENTER_block,1}, {0,0,N,1}, |
|
1634 |
Heading 255 denotes a group. We see 2 groups here: |
|
1635 |
1. group 0 -- TERM_GROUP1_block (check block) |
|
1636 |
2. group 1 -- TERM_GROUP2_ENTER_block (check block) |
|
193
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
1637 |
First in line is checked first, group 0. If the block (TERM_GROUP1_block) is free, it |
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
1638 |
looks at the corresponding terminals of that group. If no free ones are found, other |
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
1639 |
possible groups are checked (in this case group 1, since that is after group 0). If that |
0 | 1640 |
fails, then attempt fails and plane waits |
1641 |
*/ |
|
1642 |
if (Airport->nofterminalgroups > 1) { |
|
1643 |
st = DEREF_STATION(v->u.air.targetairport); |
|
1644 |
nofterminalspergroup = Airport->nofterminals / Airport->nofterminalgroups; |
|
1645 |
temp = Airport->layout[v->u.air.pos].next_in_chain; |
|
1646 |
while (temp != NULL) { |
|
1647 |
if (temp->heading == 255) { |
|
1648 |
if (!HASBITS(st->airport_flags, temp->block)) { |
|
1649 |
i = temp->next_position * nofterminalspergroup; // next_position denotes the group to check |
|
1650 |
// only that group will be checked (eg 6 terms, 2 groups) |
|
1651 |
// with i = 0 terms 1 - 3 and |
|
1652 |
// with i = 1 terms 4 - 6 |
|
1653 |
if (FreeTerminal(v, i, i + nofterminalspergroup)) {return true;} |
|
1654 |
} |
|
1655 |
} |
|
1656 |
else {return false;} // once the heading isn't 255, we've exhausted the possible blocks. So we cannot move |
|
1657 |
temp = temp->next_in_chain; |
|
1658 |
} |
|
1659 |
} |
|
1660 |
||
1661 |
// if there is only 1 terminalgroup, all terminals are checked (starting from 0 to max) |
|
1662 |
return FreeTerminal(v, 0, Airport->nofterminals); |
|
1663 |
} |
|
1664 |
||
193
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
1665 |
static bool AirportFindFreeHelipad(Vehicle *v, const AirportFTAClass *Airport) |
0 | 1666 |
{ |
1667 |
Station *st; |
|
1668 |
byte nofhelipadspergroup, i; |
|
1669 |
AirportFTA *temp; |
|
1670 |
||
1671 |
// if an airport doesn't have helipads, use terminals |
|
1672 |
if (Airport->nofhelipads == 0) {return AirportFindFreeTerminal(v, Airport);} |
|
1673 |
||
1674 |
// if there are more helicoptergroups, pick one, just as in AirportFindFreeTerminal() |
|
1675 |
if (Airport->nofhelipadgroups > 1) { |
|
1676 |
st = DEREF_STATION(v->u.air.targetairport); |
|
1677 |
nofhelipadspergroup = Airport->nofhelipads / Airport->nofhelipadgroups; |
|
1678 |
temp = Airport->layout[v->u.air.pos].next_in_chain; |
|
1679 |
while (temp != NULL) { |
|
1680 |
if (temp->heading == 255) { |
|
1681 |
if (!HASBITS(st->airport_flags, temp->block)) { |
|
1682 |
i = temp->next_position * nofhelipadspergroup; // next position is the group to check |
|
1683 |
// heliports start from after TERMINALS, so MAX_TERMINALS needs to be added |
|
1684 |
if (FreeTerminal(v, i + MAX_TERMINALS, i + MAX_TERMINALS + nofhelipadspergroup)) {return true;} |
|
1685 |
} |
|
1686 |
} |
|
1687 |
else {return false;} // once the heading isn't 255, we've exhausted the possible blocks. So we cannot move |
|
1688 |
temp = temp->next_in_chain; |
|
1689 |
} |
|
1690 |
} |
|
1691 |
// only 1 helicoptergroup, check all helipads |
|
1692 |
// The blocks for helipads start after the last terminal (MAX_TERMINALS) |
|
1693 |
else {return FreeTerminal(v, MAX_TERMINALS, Airport->nofhelipads + MAX_TERMINALS);} |
|
1694 |
return false; // it shouldn't get here anytime, but just to be sure |
|
1695 |
} |
|
1696 |
||
1697 |
static void AircraftEventHandler(Vehicle *v, int loop) |
|
1698 |
{ |
|
1699 |
v->tick_counter++; |
|
1700 |
||
1701 |
if (v->vehstatus & VS_CRASHED) { |
|
1702 |
HandleCrashedAircraft(v); |
|
1703 |
return; |
|
1704 |
} |
|
1705 |
||
1706 |
/* exit if aircraft is stopped */ |
|
1707 |
if (v->vehstatus & VS_STOPPED) |
|
1708 |
return; |
|
1709 |
||
1710 |
/* aircraft is broken down? */ |
|
1711 |
if (v->breakdown_ctr != 0) { |
|
1712 |
if (v->breakdown_ctr <= 2) { |
|
1713 |
HandleBrokenAircraft(v); |
|
1714 |
} else { |
|
1715 |
v->breakdown_ctr--; |
|
1716 |
} |
|
1717 |
} |
|
1718 |
||
1719 |
HandleAircraftSmoke(v); |
|
1720 |
ProcessAircraftOrder(v); |
|
1721 |
HandleAircraftLoading(v, loop); |
|
1722 |
||
1723 |
if ((v->next_order&OT_MASK) >= OT_LOADING) |
|
1724 |
return; |
|
1725 |
||
1726 |
// pass the right airport structure to the functions |
|
1727 |
// DEREF_STATION gets target airport (Station *st), its type is passed to GetAirport |
|
1728 |
// that returns the correct layout depending on type |
|
1729 |
AirportGoToNextPosition(v, GetAirport(DEREF_STATION(v->u.air.targetairport)->airport_type)); |
|
1730 |
} |
|
1731 |
||
1732 |
void Aircraft_Tick(Vehicle *v) |
|
1733 |
{ |
|
1734 |
int i; |
|
1735 |
||
1736 |
if (v->subtype > 2) |
|
1737 |
return; |
|
1738 |
||
1739 |
if (v->subtype == 0) |
|
1740 |
HelicopterTickHandler(v); |
|
1741 |
||
1742 |
AgeAircraftCargo(v); |
|
1743 |
||
1744 |
for(i=0; i!=6; i++) { |
|
1745 |
AircraftEventHandler(v, i); |
|
1746 |
if (v->type != VEH_Aircraft) // In case it was deleted |
|
1747 |
break; |
|
1748 |
} |
|
1749 |
} |
|
1750 |
||
1751 |
// need to be called to load aircraft from old version |
|
1752 |
void UpdateOldAircraft() |
|
1753 |
{ |
|
1754 |
Station *st; |
|
1755 |
Vehicle *v_oldstyle; |
|
1756 |
GetNewVehiclePosResult gp; |
|
1757 |
||
1758 |
// set airport_flags to 0 for all airports just to be sure |
|
1759 |
FOR_ALL_STATIONS(st) { |
|
1760 |
st->airport_flags = 0; // reset airport |
|
1761 |
// type of oilrig has been moved, update it (3-5) |
|
1762 |
if (st->airport_type == 3) {st->airport_type = AT_OILRIG;} |
|
1763 |
} |
|
1764 |
||
1765 |
FOR_ALL_VEHICLES(v_oldstyle) { |
|
1766 |
// airplane has another vehicle with subtype 4 (shadow), helicopter also has 3 (rotor) |
|
1767 |
// skip those |
|
1768 |
if (v_oldstyle->type == VEH_Aircraft && v_oldstyle->subtype <= 2) { |
|
1769 |
// airplane in terminal stopped doesn't hurt anyone, so goto next |
|
1770 |
if ((v_oldstyle->vehstatus & VS_STOPPED) && (v_oldstyle->u.air.state == 0)) { |
|
1771 |
v_oldstyle->u.air.state = HANGAR; |
|
1772 |
continue; |
|
1773 |
} |
|
1774 |
||
1775 |
AircraftLeaveHangar(v_oldstyle); // make airplane visible if it was in a depot for example |
|
1776 |
v_oldstyle->vehstatus &= ~VS_STOPPED; // make airplane moving |
|
1777 |
v_oldstyle->u.air.state = FLYING; |
|
1778 |
AircraftNextAirportPos_and_Order(v_oldstyle); // move it to the entry point of the airport |
|
1779 |
GetNewVehiclePos(v_oldstyle, &gp); // get the position of the plane (to be used for setting) |
|
1780 |
v_oldstyle->tile = 0; // aircraft in air is tile=0 |
|
193
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
1781 |
|
0 | 1782 |
// correct speed of helicopter-rotors |
1783 |
if (v_oldstyle->subtype == 0) {v_oldstyle->next->next->cur_speed = 32;} |
|
1784 |
||
1785 |
// set new position x,y,z |
|
1786 |
SetAircraftPosition(v_oldstyle, gp.x, gp.y, GetAircraftFlyingAltitude(v_oldstyle)); |
|
1787 |
} |
|
1788 |
} |
|
1789 |
} |
|
1790 |
||
193
0a7025304867
(svn r194) -Codechange: stripping trailing-spaces. Please keep this that way!
truelight
parents:
164
diff
changeset
|
1791 |
void UpdateAirplanesOnNewStation(Station *st) |
0 | 1792 |
{ |
1793 |
GetNewVehiclePosResult gp; |
|
1794 |
Vehicle *v; |
|
1795 |
byte takeofftype; |
|
1796 |
uint16 cnt; |
|
1797 |
// only 1 station is updated per function call, so it is enough to get entry_point once |
|
1798 |
const AirportFTAClass *ap = GetAirport(st->airport_type); |
|
1799 |
FOR_ALL_VEHICLES(v) { |
|
1800 |
if (v->type == VEH_Aircraft && v->subtype <= 2) { |
|
1801 |
if (v->u.air.targetairport == st->index) { // if heading to this airport |
|
1802 |
/* update position of airplane. If plane is not flying, landing, or taking off |
|
1803 |
you cannot delete airport, so it doesn't matter |
|
1804 |
*/ |
|
1805 |
if (v->u.air.state >= FLYING) { // circle around |
|
1806 |
v->u.air.pos = v->u.air.previous_pos = ap->entry_point; |
|
1807 |
v->u.air.state = FLYING; |
|
1808 |
// landing plane needs to be reset to flying height (only if in pause mode upgrade, |
|
1809 |
// in normal mode, plane is reset in Aircraft_5. It doesn't hurt for FLYING |
|
1810 |
GetNewVehiclePos(v, &gp); |
|
1811 |
// set new position x,y,z |
|
1812 |
SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v)); |
|
1813 |
} |
|
1814 |
else { |
|
1815 |
assert(v->u.air.state == ENDTAKEOFF || v->u.air.state == HELITAKEOFF); |
|
1816 |
takeofftype = (v->subtype == 0) ? HELITAKEOFF : ENDTAKEOFF; |
|
1817 |
// search in airportdata for that heading |
|
1818 |
// easiest to do, since this doesn't happen a lot |
|
1819 |
for (cnt = 0; cnt < ap->nofelements; cnt++) { |
|
1820 |
if (ap->layout[cnt].heading == takeofftype) { |
|
1821 |
v->u.air.pos = ap->layout[cnt].position; |
|
1822 |
break; |
|
1823 |
} |
|
1824 |
} |
|
1825 |
} |
|
1826 |
} |
|
1827 |
} |
|
1828 |
} |
|
1829 |
} |