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/>.
10 /** @file effectvehicle.cpp Implementation of everything generic to vehicles. */
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
)
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) {
35 TileIndex tile
= TileVirtXY(v
->x_pos
, v
->y_pos
);
36 if (!IsIndustryTile(tile
)) {
41 if (v
->cur_image
!= SPR_CHIMNEY_SMOKE_7
) {
44 v
->cur_image
= SPR_CHIMNEY_SMOKE_0
;
47 VehicleUpdatePositionAndViewport(v
);
53 static void SteamSmokeInit(EffectVehicle
*v
)
55 v
->cur_image
= SPR_STEAM_SMOKE_0
;
59 static bool SteamSmokeTick(EffectVehicle
*v
)
65 if ((v
->progress
& 7) == 0) {
70 if ((v
->progress
& 0xF) == 4) {
71 if (v
->cur_image
!= SPR_STEAM_SMOKE_4
) {
80 if (moved
) VehicleUpdatePositionAndViewport(v
);
85 static void DieselSmokeInit(EffectVehicle
*v
)
87 v
->cur_image
= SPR_DIESEL_SMOKE_0
;
91 static bool DieselSmokeTick(EffectVehicle
*v
)
95 if ((v
->progress
& 3) == 0) {
97 VehicleUpdatePositionAndViewport(v
);
98 } else if ((v
->progress
& 7) == 1) {
99 if (v
->cur_image
!= SPR_DIESEL_SMOKE_5
) {
101 VehicleUpdatePositionAndViewport(v
);
111 static void ElectricSparkInit(EffectVehicle
*v
)
113 v
->cur_image
= SPR_ELECTRIC_SPARK_0
;
117 static bool ElectricSparkTick(EffectVehicle
*v
)
119 if (v
->progress
< 2) {
123 if (v
->cur_image
!= SPR_ELECTRIC_SPARK_5
) {
125 VehicleUpdatePositionAndViewport(v
);
135 static void SmokeInit(EffectVehicle
*v
)
137 v
->cur_image
= SPR_SMOKE_0
;
141 static bool SmokeTick(EffectVehicle
*v
)
147 if ((v
->progress
& 3) == 0) {
152 if ((v
->progress
& 0xF) == 4) {
153 if (v
->cur_image
!= SPR_SMOKE_4
) {
162 if (moved
) VehicleUpdatePositionAndViewport(v
);
167 static void ExplosionLargeInit(EffectVehicle
*v
)
169 v
->cur_image
= SPR_EXPLOSION_LARGE_0
;
173 static bool ExplosionLargeTick(EffectVehicle
*v
)
176 if ((v
->progress
& 3) == 0) {
177 if (v
->cur_image
!= SPR_EXPLOSION_LARGE_F
) {
179 VehicleUpdatePositionAndViewport(v
);
189 static void BreakdownSmokeInit(EffectVehicle
*v
)
191 v
->cur_image
= SPR_BREAKDOWN_SMOKE_0
;
195 static bool BreakdownSmokeTick(EffectVehicle
*v
)
198 if ((v
->progress
& 7) == 0) {
199 if (v
->cur_image
!= SPR_BREAKDOWN_SMOKE_3
) {
202 v
->cur_image
= SPR_BREAKDOWN_SMOKE_0
;
204 VehicleUpdatePositionAndViewport(v
);
207 v
->animation_state
--;
208 if (v
->animation_state
== 0) {
216 static void ExplosionSmallInit(EffectVehicle
*v
)
218 v
->cur_image
= SPR_EXPLOSION_SMALL_0
;
222 static bool ExplosionSmallTick(EffectVehicle
*v
)
225 if ((v
->progress
& 3) == 0) {
226 if (v
->cur_image
!= SPR_EXPLOSION_SMALL_B
) {
228 VehicleUpdatePositionAndViewport(v
);
238 static void BulldozerInit(EffectVehicle
*v
)
240 v
->cur_image
= SPR_BULLDOZER_NE
;
242 v
->animation_state
= 0;
243 v
->animation_substate
= 0;
246 struct BulldozerMovement
{
252 static const BulldozerMovement _bulldozer_movement
[] = {
275 static const struct {
285 static bool BulldozerTick(EffectVehicle
*v
)
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
)) {
305 VehicleUpdatePositionAndViewport(v
);
311 static void BubbleInit(EffectVehicle
*v
)
313 v
->cur_image
= SPR_BUBBLE_GENERATE_0
;
318 struct BubbleMovement
{
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
[] = {
337 static const BubbleMovement _bubble_float_ne
[] = {
345 static const BubbleMovement _bubble_float_se
[] = {
353 static const BubbleMovement _bubble_float_nw
[] = {
361 static const BubbleMovement _bubble_burst
[] = {
369 static const BubbleMovement _bubble_absorb
[] = {
459 static const BubbleMovement
* const _bubble_movement
[] = {
468 static bool BubbleTick(EffectVehicle
*v
)
473 if ((v
->progress
& 3) != 0) return true;
475 if (v
->spritenum
== 0) {
477 if (v
->cur_image
< SPR_BUBBLE_GENERATE_3
) {
478 VehicleUpdatePositionAndViewport(v
);
481 if (v
->animation_substate
!= 0) {
482 v
->spritenum
= GB(Random(), 0, 2) + 1;
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) {
498 if (b
->y
== 4 && b
->x
== 1) {
499 if (v
->z_pos
> 180 || Chance16I(1, 96, Random())) {
501 if (_settings_client
.sound
.ambient
) SndPlayVehicleFx(SND_2F_POP
, v
);
506 if (b
->y
== 4 && b
->x
== 2) {
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
];
522 v
->cur_image
= SPR_BUBBLE_0
+ b
->image
;
524 VehicleUpdatePositionAndViewport(v
);
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();
603 v
->UpdateDeltaXY(INVALID_DIR
);
604 v
->vehstatus
= VS_UNCLICKABLE
;
606 _effect_init_procs
[type
](v
);
608 VehicleUpdatePositionAndViewport(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
)
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
];