Rearrange conditionals in FreeTrainTrackReservation
[openttd/fttd.git] / src / effectvehicle.cpp
blob193df45f79c30babc1816bfb90658db6fe967df0
1 /* $Id$ */
3 /*
4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 */
10 /** @file effectvehicle.cpp Implementation of everything generic to vehicles. */
12 #include "stdafx.h"
13 #include "landscape.h"
14 #include "core/random_func.hpp"
15 #include "vehicle_func.h"
16 #include "sound_func.h"
17 #include "animated_tile_func.h"
18 #include "effectvehicle_func.h"
19 #include "effectvehicle_base.h"
20 #include "industrytype.h"
23 static void ChimneySmokeInit(EffectVehicle *v)
25 uint32 r = Random();
26 v->cur_image = SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3);
27 v->progress = GB(r, 16, 3);
30 static bool ChimneySmokeTick(EffectVehicle *v)
32 if (v->progress > 0) {
33 v->progress--;
34 } else {
35 TileIndex tile = TileVirtXY(v->x_pos, v->y_pos);
36 if (!IsIndustryTile(tile)) {
37 delete v;
38 return false;
41 if (v->cur_image != SPR_CHIMNEY_SMOKE_7) {
42 v->cur_image++;
43 } else {
44 v->cur_image = SPR_CHIMNEY_SMOKE_0;
46 v->progress = 7;
47 VehicleUpdatePositionAndViewport(v);
50 return true;
53 static void SteamSmokeInit(EffectVehicle *v)
55 v->cur_image = SPR_STEAM_SMOKE_0;
56 v->progress = 12;
59 static bool SteamSmokeTick(EffectVehicle *v)
61 bool moved = false;
63 v->progress++;
65 if ((v->progress & 7) == 0) {
66 v->z_pos++;
67 moved = true;
70 if ((v->progress & 0xF) == 4) {
71 if (v->cur_image != SPR_STEAM_SMOKE_4) {
72 v->cur_image++;
73 } else {
74 delete v;
75 return false;
77 moved = true;
80 if (moved) VehicleUpdatePositionAndViewport(v);
82 return true;
85 static void DieselSmokeInit(EffectVehicle *v)
87 v->cur_image = SPR_DIESEL_SMOKE_0;
88 v->progress = 0;
91 static bool DieselSmokeTick(EffectVehicle *v)
93 v->progress++;
95 if ((v->progress & 3) == 0) {
96 v->z_pos++;
97 VehicleUpdatePositionAndViewport(v);
98 } else if ((v->progress & 7) == 1) {
99 if (v->cur_image != SPR_DIESEL_SMOKE_5) {
100 v->cur_image++;
101 VehicleUpdatePositionAndViewport(v);
102 } else {
103 delete v;
104 return false;
108 return true;
111 static void ElectricSparkInit(EffectVehicle *v)
113 v->cur_image = SPR_ELECTRIC_SPARK_0;
114 v->progress = 1;
117 static bool ElectricSparkTick(EffectVehicle *v)
119 if (v->progress < 2) {
120 v->progress++;
121 } else {
122 v->progress = 0;
123 if (v->cur_image != SPR_ELECTRIC_SPARK_5) {
124 v->cur_image++;
125 VehicleUpdatePositionAndViewport(v);
126 } else {
127 delete v;
128 return false;
132 return true;
135 static void SmokeInit(EffectVehicle *v)
137 v->cur_image = SPR_SMOKE_0;
138 v->progress = 12;
141 static bool SmokeTick(EffectVehicle *v)
143 bool moved = false;
145 v->progress++;
147 if ((v->progress & 3) == 0) {
148 v->z_pos++;
149 moved = true;
152 if ((v->progress & 0xF) == 4) {
153 if (v->cur_image != SPR_SMOKE_4) {
154 v->cur_image++;
155 } else {
156 delete v;
157 return false;
159 moved = true;
162 if (moved) VehicleUpdatePositionAndViewport(v);
164 return true;
167 static void ExplosionLargeInit(EffectVehicle *v)
169 v->cur_image = SPR_EXPLOSION_LARGE_0;
170 v->progress = 0;
173 static bool ExplosionLargeTick(EffectVehicle *v)
175 v->progress++;
176 if ((v->progress & 3) == 0) {
177 if (v->cur_image != SPR_EXPLOSION_LARGE_F) {
178 v->cur_image++;
179 VehicleUpdatePositionAndViewport(v);
180 } else {
181 delete v;
182 return false;
186 return true;
189 static void BreakdownSmokeInit(EffectVehicle *v)
191 v->cur_image = SPR_BREAKDOWN_SMOKE_0;
192 v->progress = 0;
195 static bool BreakdownSmokeTick(EffectVehicle *v)
197 v->progress++;
198 if ((v->progress & 7) == 0) {
199 if (v->cur_image != SPR_BREAKDOWN_SMOKE_3) {
200 v->cur_image++;
201 } else {
202 v->cur_image = SPR_BREAKDOWN_SMOKE_0;
204 VehicleUpdatePositionAndViewport(v);
207 v->animation_state--;
208 if (v->animation_state == 0) {
209 delete v;
210 return false;
213 return true;
216 static void ExplosionSmallInit(EffectVehicle *v)
218 v->cur_image = SPR_EXPLOSION_SMALL_0;
219 v->progress = 0;
222 static bool ExplosionSmallTick(EffectVehicle *v)
224 v->progress++;
225 if ((v->progress & 3) == 0) {
226 if (v->cur_image != SPR_EXPLOSION_SMALL_B) {
227 v->cur_image++;
228 VehicleUpdatePositionAndViewport(v);
229 } else {
230 delete v;
231 return false;
235 return true;
238 static void BulldozerInit(EffectVehicle *v)
240 v->cur_image = SPR_BULLDOZER_NE;
241 v->progress = 0;
242 v->animation_state = 0;
243 v->animation_substate = 0;
246 struct BulldozerMovement {
247 byte direction:2;
248 byte image:2;
249 byte duration:3;
252 static const BulldozerMovement _bulldozer_movement[] = {
253 { 0, 0, 4 },
254 { 3, 3, 4 },
255 { 2, 2, 7 },
256 { 0, 2, 7 },
257 { 1, 1, 3 },
258 { 2, 2, 7 },
259 { 0, 2, 7 },
260 { 1, 1, 3 },
261 { 2, 2, 7 },
262 { 0, 2, 7 },
263 { 3, 3, 6 },
264 { 2, 2, 6 },
265 { 1, 1, 7 },
266 { 3, 1, 7 },
267 { 0, 0, 3 },
268 { 1, 1, 7 },
269 { 3, 1, 7 },
270 { 0, 0, 3 },
271 { 1, 1, 7 },
272 { 3, 1, 7 }
275 static const struct {
276 int8 x;
277 int8 y;
278 } _inc_by_dir[] = {
279 { -1, 0 },
280 { 0, 1 },
281 { 1, 0 },
282 { 0, -1 }
285 static bool BulldozerTick(EffectVehicle *v)
287 v->progress++;
288 if ((v->progress & 7) == 0) {
289 const BulldozerMovement *b = &_bulldozer_movement[v->animation_state];
291 v->cur_image = SPR_BULLDOZER_NE + b->image;
293 v->x_pos += _inc_by_dir[b->direction].x;
294 v->y_pos += _inc_by_dir[b->direction].y;
296 v->animation_substate++;
297 if (v->animation_substate >= b->duration) {
298 v->animation_substate = 0;
299 v->animation_state++;
300 if (v->animation_state == lengthof(_bulldozer_movement)) {
301 delete v;
302 return false;
305 VehicleUpdatePositionAndViewport(v);
308 return true;
311 static void BubbleInit(EffectVehicle *v)
313 v->cur_image = SPR_BUBBLE_GENERATE_0;
314 v->spritenum = 0;
315 v->progress = 0;
318 struct BubbleMovement {
319 int8 x:4;
320 int8 y:4;
321 int8 z:4;
322 byte image:4;
325 #define MK(x, y, z, i) { x, y, z, i }
326 #define ME(i) { i, 4, 0, 0 }
328 static const BubbleMovement _bubble_float_sw[] = {
329 MK(0, 0, 1, 0),
330 MK(1, 0, 1, 1),
331 MK(0, 0, 1, 0),
332 MK(1, 0, 1, 2),
333 ME(1)
337 static const BubbleMovement _bubble_float_ne[] = {
338 MK( 0, 0, 1, 0),
339 MK(-1, 0, 1, 1),
340 MK( 0, 0, 1, 0),
341 MK(-1, 0, 1, 2),
342 ME(1)
345 static const BubbleMovement _bubble_float_se[] = {
346 MK(0, 0, 1, 0),
347 MK(0, 1, 1, 1),
348 MK(0, 0, 1, 0),
349 MK(0, 1, 1, 2),
350 ME(1)
353 static const BubbleMovement _bubble_float_nw[] = {
354 MK(0, 0, 1, 0),
355 MK(0, -1, 1, 1),
356 MK(0, 0, 1, 0),
357 MK(0, -1, 1, 2),
358 ME(1)
361 static const BubbleMovement _bubble_burst[] = {
362 MK(0, 0, 1, 2),
363 MK(0, 0, 1, 7),
364 MK(0, 0, 1, 8),
365 MK(0, 0, 1, 9),
366 ME(0)
369 static const BubbleMovement _bubble_absorb[] = {
370 MK(0, 0, 1, 0),
371 MK(0, 0, 1, 1),
372 MK(0, 0, 1, 0),
373 MK(0, 0, 1, 2),
374 MK(0, 0, 1, 0),
375 MK(0, 0, 1, 1),
376 MK(0, 0, 1, 0),
377 MK(0, 0, 1, 2),
378 MK(0, 0, 1, 0),
379 MK(0, 0, 1, 1),
380 MK(0, 0, 1, 0),
381 MK(0, 0, 1, 2),
382 MK(0, 0, 1, 0),
383 MK(0, 0, 1, 1),
384 MK(0, 0, 1, 0),
385 MK(0, 0, 1, 2),
386 MK(0, 0, 1, 0),
387 MK(0, 0, 1, 1),
388 MK(0, 0, 1, 0),
389 MK(0, 0, 1, 2),
390 MK(0, 0, 1, 0),
391 MK(0, 0, 1, 1),
392 MK(0, 0, 1, 0),
393 MK(0, 0, 1, 2),
394 MK(0, 0, 1, 0),
395 MK(0, 0, 1, 1),
396 MK(0, 0, 1, 0),
397 MK(0, 0, 1, 2),
398 MK(0, 0, 1, 0),
399 MK(0, 0, 1, 1),
400 MK(0, 0, 1, 0),
401 MK(0, 0, 1, 2),
402 MK(0, 0, 1, 0),
403 MK(0, 0, 1, 1),
404 MK(0, 0, 1, 0),
405 MK(0, 0, 1, 2),
406 MK(0, 0, 1, 0),
407 MK(0, 0, 1, 1),
408 MK(0, 0, 1, 0),
409 MK(0, 0, 1, 2),
410 MK(0, 0, 1, 0),
411 MK(0, 0, 1, 1),
412 MK(0, 0, 1, 0),
413 MK(0, 0, 1, 2),
414 MK(0, 0, 1, 0),
415 MK(0, 0, 1, 1),
416 MK(0, 0, 1, 0),
417 MK(0, 0, 1, 2),
418 MK(0, 0, 1, 0),
419 MK(0, 0, 1, 1),
420 MK(0, 0, 1, 0),
421 MK(0, 0, 1, 2),
422 MK(0, 0, 1, 0),
423 MK(0, 0, 1, 1),
424 MK(0, 0, 1, 0),
425 MK(0, 0, 1, 2),
426 MK(0, 0, 1, 0),
427 MK(0, 0, 1, 1),
428 MK(0, 0, 1, 0),
429 MK(0, 0, 1, 2),
430 MK(0, 0, 1, 0),
431 MK(0, 0, 1, 1),
432 MK(2, 1, 3, 0),
433 MK(1, 1, 3, 1),
434 MK(2, 1, 3, 0),
435 MK(1, 1, 3, 2),
436 MK(2, 1, 3, 0),
437 MK(1, 1, 3, 1),
438 MK(2, 1, 3, 0),
439 MK(1, 0, 1, 2),
440 MK(0, 0, 1, 0),
441 MK(1, 0, 1, 1),
442 MK(0, 0, 1, 0),
443 MK(1, 0, 1, 2),
444 MK(0, 0, 1, 0),
445 MK(1, 0, 1, 1),
446 MK(0, 0, 1, 0),
447 MK(1, 0, 1, 2),
448 ME(2),
449 MK(0, 0, 0, 0xA),
450 MK(0, 0, 0, 0xB),
451 MK(0, 0, 0, 0xC),
452 MK(0, 0, 0, 0xD),
453 MK(0, 0, 0, 0xE),
454 ME(0)
456 #undef ME
457 #undef MK
459 static const BubbleMovement * const _bubble_movement[] = {
460 _bubble_float_sw,
461 _bubble_float_ne,
462 _bubble_float_se,
463 _bubble_float_nw,
464 _bubble_burst,
465 _bubble_absorb,
468 static bool BubbleTick(EffectVehicle *v)
470 uint anim_state;
472 v->progress++;
473 if ((v->progress & 3) != 0) return true;
475 if (v->spritenum == 0) {
476 v->cur_image++;
477 if (v->cur_image < SPR_BUBBLE_GENERATE_3) {
478 VehicleUpdatePositionAndViewport(v);
479 return true;
481 if (v->animation_substate != 0) {
482 v->spritenum = GB(Random(), 0, 2) + 1;
483 } else {
484 v->spritenum = 6;
486 anim_state = 0;
487 } else {
488 anim_state = v->animation_state + 1;
491 const BubbleMovement *b = &_bubble_movement[v->spritenum - 1][anim_state];
493 if (b->y == 4 && b->x == 0) {
494 delete v;
495 return false;
498 if (b->y == 4 && b->x == 1) {
499 if (v->z_pos > 180 || Chance16I(1, 96, Random())) {
500 v->spritenum = 5;
501 if (_settings_client.sound.ambient) SndPlayVehicleFx(SND_2F_POP, v);
503 anim_state = 0;
506 if (b->y == 4 && b->x == 2) {
507 TileIndex tile;
509 anim_state++;
510 if (_settings_client.sound.ambient) SndPlayVehicleFx(SND_31_EXTRACT, v);
512 tile = TileVirtXY(v->x_pos, v->y_pos);
513 if (IsIndustryTile(tile) && GetIndustryGfx(tile) == GFX_BUBBLE_CATCHER) AddAnimatedTile(tile);
516 v->animation_state = anim_state;
517 b = &_bubble_movement[v->spritenum - 1][anim_state];
519 v->x_pos += b->x;
520 v->y_pos += b->y;
521 v->z_pos += b->z;
522 v->cur_image = SPR_BUBBLE_0 + b->image;
524 VehicleUpdatePositionAndViewport(v);
526 return true;
530 typedef void EffectInitProc(EffectVehicle *v);
531 typedef bool EffectTickProc(EffectVehicle *v);
533 /** Functions to initialise an effect vehicle after construction. */
534 static EffectInitProc * const _effect_init_procs[] = {
535 ChimneySmokeInit, // EV_CHIMNEY_SMOKE
536 SteamSmokeInit, // EV_STEAM_SMOKE
537 DieselSmokeInit, // EV_DIESEL_SMOKE
538 ElectricSparkInit, // EV_ELECTRIC_SPARK
539 SmokeInit, // EV_CRASH_SMOKE
540 ExplosionLargeInit, // EV_EXPLOSION_LARGE
541 BreakdownSmokeInit, // EV_BREAKDOWN_SMOKE
542 ExplosionSmallInit, // EV_EXPLOSION_SMALL
543 BulldozerInit, // EV_BULLDOZER
544 BubbleInit, // EV_BUBBLE
545 SmokeInit, // EV_BREAKDOWN_SMOKE_AIRCRAFT
546 SmokeInit, // EV_COPPER_MINE_SMOKE
548 assert_compile(lengthof(_effect_init_procs) == EV_END);
550 /** Functions for controlling effect vehicles at each tick. */
551 static EffectTickProc * const _effect_tick_procs[] = {
552 ChimneySmokeTick, // EV_CHIMNEY_SMOKE
553 SteamSmokeTick, // EV_STEAM_SMOKE
554 DieselSmokeTick, // EV_DIESEL_SMOKE
555 ElectricSparkTick, // EV_ELECTRIC_SPARK
556 SmokeTick, // EV_CRASH_SMOKE
557 ExplosionLargeTick, // EV_EXPLOSION_LARGE
558 BreakdownSmokeTick, // EV_BREAKDOWN_SMOKE
559 ExplosionSmallTick, // EV_EXPLOSION_SMALL
560 BulldozerTick, // EV_BULLDOZER
561 BubbleTick, // EV_BUBBLE
562 SmokeTick, // EV_BREAKDOWN_SMOKE_AIRCRAFT
563 SmokeTick, // EV_COPPER_MINE_SMOKE
565 assert_compile(lengthof(_effect_tick_procs) == EV_END);
567 /** Transparency options affecting the effects. */
568 static const TransparencyOption _effect_transparency_options[] = {
569 TO_INDUSTRIES, // EV_CHIMNEY_SMOKE
570 TO_INVALID, // EV_STEAM_SMOKE
571 TO_INVALID, // EV_DIESEL_SMOKE
572 TO_INVALID, // EV_ELECTRIC_SPARK
573 TO_INVALID, // EV_CRASH_SMOKE
574 TO_INVALID, // EV_EXPLOSION_LARGE
575 TO_INVALID, // EV_BREAKDOWN_SMOKE
576 TO_INVALID, // EV_EXPLOSION_SMALL
577 TO_INVALID, // EV_BULLDOZER
578 TO_INDUSTRIES, // EV_BUBBLE
579 TO_INVALID, // EV_BREAKDOWN_SMOKE_AIRCRAFT
580 TO_INDUSTRIES, // EV_COPPER_MINE_SMOKE
582 assert_compile(lengthof(_effect_transparency_options) == EV_END);
586 * Create an effect vehicle at a particular location.
587 * @param x The x location on the map.
588 * @param y The y location on the map.
589 * @param z The z location on the map.
590 * @param type The type of effect vehicle.
591 * @return The effect vehicle.
593 EffectVehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicleType type)
595 if (!Vehicle::CanAllocateItem()) return NULL;
597 EffectVehicle *v = new EffectVehicle();
598 v->subtype = type;
599 v->x_pos = x;
600 v->y_pos = y;
601 v->z_pos = z;
602 v->tile = 0;
603 v->UpdateDeltaXY(INVALID_DIR);
604 v->vehstatus = VS_UNCLICKABLE;
606 _effect_init_procs[type](v);
608 VehicleUpdatePositionAndViewport(v);
610 return v;
614 * Create an effect vehicle above a particular location.
615 * @param x The x location on the map.
616 * @param y The y location on the map.
617 * @param z The offset from the ground.
618 * @param type The type of effect vehicle.
619 * @return The effect vehicle.
621 EffectVehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type)
623 int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE);
624 int safe_y = Clamp(y, 0, MapMaxY() * TILE_SIZE);
625 return CreateEffectVehicle(x, y, GetSlopePixelZ(safe_x, safe_y) + z, type);
629 * Create an effect vehicle above a particular vehicle.
630 * @param v The vehicle to base the position on.
631 * @param x The x offset to the vehicle.
632 * @param y The y offset to the vehicle.
633 * @param z The z offset to the vehicle.
634 * @param type The type of effect vehicle.
635 * @return The effect vehicle.
637 EffectVehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type)
639 return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type);
642 bool EffectVehicle::Tick()
644 return _effect_tick_procs[this->subtype](this);
647 void EffectVehicle::UpdateDeltaXY(Direction direction)
649 this->x_offs = 0;
650 this->y_offs = 0;
651 this->x_extent = 1;
652 this->y_extent = 1;
653 this->z_extent = 1;
657 * Determines the transparency option affecting the effect.
658 * @return Transparency option, or TO_INVALID if none.
660 TransparencyOption EffectVehicle::GetTransparencyOption() const
662 return _effect_transparency_options[this->subtype];