(svn r27729) -Codechange: Do not count static NewGRF when checking for the maximum...
[openttd.git] / src / effectvehicle.cpp
blob5921cd190ea1e00132c9bc804851082686447639
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 "industry_map.h"
16 #include "vehicle_func.h"
17 #include "sound_func.h"
18 #include "animated_tile_func.h"
19 #include "effectvehicle_func.h"
20 #include "effectvehicle_base.h"
22 #include "safeguards.h"
25 /**
26 * Increment the sprite unless it has reached the end of the animation.
27 * @param v Vehicle to increment sprite of.
28 * @param last Last sprite of animation.
29 * @return true if the sprite was incremented, false if the end was reached.
31 static bool IncrementSprite(EffectVehicle *v, SpriteID last)
33 if (v->sprite_seq.seq[0].sprite != last) {
34 v->sprite_seq.seq[0].sprite++;
35 return true;
36 } else {
37 return false;
41 static void ChimneySmokeInit(EffectVehicle *v)
43 uint32 r = Random();
44 v->sprite_seq.Set(SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3));
45 v->progress = GB(r, 16, 3);
48 static bool ChimneySmokeTick(EffectVehicle *v)
50 if (v->progress > 0) {
51 v->progress--;
52 } else {
53 TileIndex tile = TileVirtXY(v->x_pos, v->y_pos);
54 if (!IsTileType(tile, MP_INDUSTRY)) {
55 delete v;
56 return false;
59 if (!IncrementSprite(v, SPR_CHIMNEY_SMOKE_7)) {
60 v->sprite_seq.Set(SPR_CHIMNEY_SMOKE_0);
62 v->progress = 7;
63 v->UpdatePositionAndViewport();
66 return true;
69 static void SteamSmokeInit(EffectVehicle *v)
71 v->sprite_seq.Set(SPR_STEAM_SMOKE_0);
72 v->progress = 12;
75 static bool SteamSmokeTick(EffectVehicle *v)
77 bool moved = false;
79 v->progress++;
81 if ((v->progress & 7) == 0) {
82 v->z_pos++;
83 moved = true;
86 if ((v->progress & 0xF) == 4) {
87 if (!IncrementSprite(v, SPR_STEAM_SMOKE_4)) {
88 delete v;
89 return false;
91 moved = true;
94 if (moved) v->UpdatePositionAndViewport();
96 return true;
99 static void DieselSmokeInit(EffectVehicle *v)
101 v->sprite_seq.Set(SPR_DIESEL_SMOKE_0);
102 v->progress = 0;
105 static bool DieselSmokeTick(EffectVehicle *v)
107 v->progress++;
109 if ((v->progress & 3) == 0) {
110 v->z_pos++;
111 v->UpdatePositionAndViewport();
112 } else if ((v->progress & 7) == 1) {
113 if (!IncrementSprite(v, SPR_DIESEL_SMOKE_5)) {
114 delete v;
115 return false;
117 v->UpdatePositionAndViewport();
120 return true;
123 static void ElectricSparkInit(EffectVehicle *v)
125 v->sprite_seq.Set(SPR_ELECTRIC_SPARK_0);
126 v->progress = 1;
129 static bool ElectricSparkTick(EffectVehicle *v)
131 if (v->progress < 2) {
132 v->progress++;
133 } else {
134 v->progress = 0;
136 if (!IncrementSprite(v, SPR_ELECTRIC_SPARK_5)) {
137 delete v;
138 return false;
140 v->UpdatePositionAndViewport();
143 return true;
146 static void SmokeInit(EffectVehicle *v)
148 v->sprite_seq.Set(SPR_SMOKE_0);
149 v->progress = 12;
152 static bool SmokeTick(EffectVehicle *v)
154 bool moved = false;
156 v->progress++;
158 if ((v->progress & 3) == 0) {
159 v->z_pos++;
160 moved = true;
163 if ((v->progress & 0xF) == 4) {
164 if (!IncrementSprite(v, SPR_SMOKE_4)) {
165 delete v;
166 return false;
168 moved = true;
171 if (moved) v->UpdatePositionAndViewport();
173 return true;
176 static void ExplosionLargeInit(EffectVehicle *v)
178 v->sprite_seq.Set(SPR_EXPLOSION_LARGE_0);
179 v->progress = 0;
182 static bool ExplosionLargeTick(EffectVehicle *v)
184 v->progress++;
185 if ((v->progress & 3) == 0) {
186 if (!IncrementSprite(v, SPR_EXPLOSION_LARGE_F)) {
187 delete v;
188 return false;
190 v->UpdatePositionAndViewport();
193 return true;
196 static void BreakdownSmokeInit(EffectVehicle *v)
198 v->sprite_seq.Set(SPR_BREAKDOWN_SMOKE_0);
199 v->progress = 0;
202 static bool BreakdownSmokeTick(EffectVehicle *v)
204 v->progress++;
205 if ((v->progress & 7) == 0) {
206 if (!IncrementSprite(v, SPR_BREAKDOWN_SMOKE_3)) {
207 v->sprite_seq.Set(SPR_BREAKDOWN_SMOKE_0);
209 v->UpdatePositionAndViewport();
212 v->animation_state--;
213 if (v->animation_state == 0) {
214 delete v;
215 return false;
218 return true;
221 static void ExplosionSmallInit(EffectVehicle *v)
223 v->sprite_seq.Set(SPR_EXPLOSION_SMALL_0);
224 v->progress = 0;
227 static bool ExplosionSmallTick(EffectVehicle *v)
229 v->progress++;
230 if ((v->progress & 3) == 0) {
231 if (!IncrementSprite(v, SPR_EXPLOSION_SMALL_B)) {
232 delete v;
233 return false;
235 v->UpdatePositionAndViewport();
238 return true;
241 static void BulldozerInit(EffectVehicle *v)
243 v->sprite_seq.Set(SPR_BULLDOZER_NE);
244 v->progress = 0;
245 v->animation_state = 0;
246 v->animation_substate = 0;
249 struct BulldozerMovement {
250 byte direction:2;
251 byte image:2;
252 byte duration:3;
255 static const BulldozerMovement _bulldozer_movement[] = {
256 { 0, 0, 4 },
257 { 3, 3, 4 },
258 { 2, 2, 7 },
259 { 0, 2, 7 },
260 { 1, 1, 3 },
261 { 2, 2, 7 },
262 { 0, 2, 7 },
263 { 1, 1, 3 },
264 { 2, 2, 7 },
265 { 0, 2, 7 },
266 { 3, 3, 6 },
267 { 2, 2, 6 },
268 { 1, 1, 7 },
269 { 3, 1, 7 },
270 { 0, 0, 3 },
271 { 1, 1, 7 },
272 { 3, 1, 7 },
273 { 0, 0, 3 },
274 { 1, 1, 7 },
275 { 3, 1, 7 }
278 static const struct {
279 int8 x;
280 int8 y;
281 } _inc_by_dir[] = {
282 { -1, 0 },
283 { 0, 1 },
284 { 1, 0 },
285 { 0, -1 }
288 static bool BulldozerTick(EffectVehicle *v)
290 v->progress++;
291 if ((v->progress & 7) == 0) {
292 const BulldozerMovement *b = &_bulldozer_movement[v->animation_state];
294 v->sprite_seq.Set(SPR_BULLDOZER_NE + b->image);
296 v->x_pos += _inc_by_dir[b->direction].x;
297 v->y_pos += _inc_by_dir[b->direction].y;
299 v->animation_substate++;
300 if (v->animation_substate >= b->duration) {
301 v->animation_substate = 0;
302 v->animation_state++;
303 if (v->animation_state == lengthof(_bulldozer_movement)) {
304 delete v;
305 return false;
308 v->UpdatePositionAndViewport();
311 return true;
314 static void BubbleInit(EffectVehicle *v)
316 v->sprite_seq.Set(SPR_BUBBLE_GENERATE_0);
317 v->spritenum = 0;
318 v->progress = 0;
321 struct BubbleMovement {
322 int8 x:4;
323 int8 y:4;
324 int8 z:4;
325 byte image:4;
328 #define MK(x, y, z, i) { x, y, z, i }
329 #define ME(i) { i, 4, 0, 0 }
331 static const BubbleMovement _bubble_float_sw[] = {
332 MK(0, 0, 1, 0),
333 MK(1, 0, 1, 1),
334 MK(0, 0, 1, 0),
335 MK(1, 0, 1, 2),
336 ME(1)
340 static const BubbleMovement _bubble_float_ne[] = {
341 MK( 0, 0, 1, 0),
342 MK(-1, 0, 1, 1),
343 MK( 0, 0, 1, 0),
344 MK(-1, 0, 1, 2),
345 ME(1)
348 static const BubbleMovement _bubble_float_se[] = {
349 MK(0, 0, 1, 0),
350 MK(0, 1, 1, 1),
351 MK(0, 0, 1, 0),
352 MK(0, 1, 1, 2),
353 ME(1)
356 static const BubbleMovement _bubble_float_nw[] = {
357 MK(0, 0, 1, 0),
358 MK(0, -1, 1, 1),
359 MK(0, 0, 1, 0),
360 MK(0, -1, 1, 2),
361 ME(1)
364 static const BubbleMovement _bubble_burst[] = {
365 MK(0, 0, 1, 2),
366 MK(0, 0, 1, 7),
367 MK(0, 0, 1, 8),
368 MK(0, 0, 1, 9),
369 ME(0)
372 static const BubbleMovement _bubble_absorb[] = {
373 MK(0, 0, 1, 0),
374 MK(0, 0, 1, 1),
375 MK(0, 0, 1, 0),
376 MK(0, 0, 1, 2),
377 MK(0, 0, 1, 0),
378 MK(0, 0, 1, 1),
379 MK(0, 0, 1, 0),
380 MK(0, 0, 1, 2),
381 MK(0, 0, 1, 0),
382 MK(0, 0, 1, 1),
383 MK(0, 0, 1, 0),
384 MK(0, 0, 1, 2),
385 MK(0, 0, 1, 0),
386 MK(0, 0, 1, 1),
387 MK(0, 0, 1, 0),
388 MK(0, 0, 1, 2),
389 MK(0, 0, 1, 0),
390 MK(0, 0, 1, 1),
391 MK(0, 0, 1, 0),
392 MK(0, 0, 1, 2),
393 MK(0, 0, 1, 0),
394 MK(0, 0, 1, 1),
395 MK(0, 0, 1, 0),
396 MK(0, 0, 1, 2),
397 MK(0, 0, 1, 0),
398 MK(0, 0, 1, 1),
399 MK(0, 0, 1, 0),
400 MK(0, 0, 1, 2),
401 MK(0, 0, 1, 0),
402 MK(0, 0, 1, 1),
403 MK(0, 0, 1, 0),
404 MK(0, 0, 1, 2),
405 MK(0, 0, 1, 0),
406 MK(0, 0, 1, 1),
407 MK(0, 0, 1, 0),
408 MK(0, 0, 1, 2),
409 MK(0, 0, 1, 0),
410 MK(0, 0, 1, 1),
411 MK(0, 0, 1, 0),
412 MK(0, 0, 1, 2),
413 MK(0, 0, 1, 0),
414 MK(0, 0, 1, 1),
415 MK(0, 0, 1, 0),
416 MK(0, 0, 1, 2),
417 MK(0, 0, 1, 0),
418 MK(0, 0, 1, 1),
419 MK(0, 0, 1, 0),
420 MK(0, 0, 1, 2),
421 MK(0, 0, 1, 0),
422 MK(0, 0, 1, 1),
423 MK(0, 0, 1, 0),
424 MK(0, 0, 1, 2),
425 MK(0, 0, 1, 0),
426 MK(0, 0, 1, 1),
427 MK(0, 0, 1, 0),
428 MK(0, 0, 1, 2),
429 MK(0, 0, 1, 0),
430 MK(0, 0, 1, 1),
431 MK(0, 0, 1, 0),
432 MK(0, 0, 1, 2),
433 MK(0, 0, 1, 0),
434 MK(0, 0, 1, 1),
435 MK(2, 1, 3, 0),
436 MK(1, 1, 3, 1),
437 MK(2, 1, 3, 0),
438 MK(1, 1, 3, 2),
439 MK(2, 1, 3, 0),
440 MK(1, 1, 3, 1),
441 MK(2, 1, 3, 0),
442 MK(1, 0, 1, 2),
443 MK(0, 0, 1, 0),
444 MK(1, 0, 1, 1),
445 MK(0, 0, 1, 0),
446 MK(1, 0, 1, 2),
447 MK(0, 0, 1, 0),
448 MK(1, 0, 1, 1),
449 MK(0, 0, 1, 0),
450 MK(1, 0, 1, 2),
451 ME(2),
452 MK(0, 0, 0, 0xA),
453 MK(0, 0, 0, 0xB),
454 MK(0, 0, 0, 0xC),
455 MK(0, 0, 0, 0xD),
456 MK(0, 0, 0, 0xE),
457 ME(0)
459 #undef ME
460 #undef MK
462 static const BubbleMovement * const _bubble_movement[] = {
463 _bubble_float_sw,
464 _bubble_float_ne,
465 _bubble_float_se,
466 _bubble_float_nw,
467 _bubble_burst,
468 _bubble_absorb,
471 static bool BubbleTick(EffectVehicle *v)
473 uint anim_state;
475 v->progress++;
476 if ((v->progress & 3) != 0) return true;
478 if (v->spritenum == 0) {
479 v->sprite_seq.seq[0].sprite++;
480 if (v->sprite_seq.seq[0].sprite < SPR_BUBBLE_GENERATE_3) {
481 v->UpdatePositionAndViewport();
482 return true;
484 if (v->animation_substate != 0) {
485 v->spritenum = GB(Random(), 0, 2) + 1;
486 } else {
487 v->spritenum = 6;
489 anim_state = 0;
490 } else {
491 anim_state = v->animation_state + 1;
494 const BubbleMovement *b = &_bubble_movement[v->spritenum - 1][anim_state];
496 if (b->y == 4 && b->x == 0) {
497 delete v;
498 return false;
501 if (b->y == 4 && b->x == 1) {
502 if (v->z_pos > 180 || Chance16I(1, 96, Random())) {
503 v->spritenum = 5;
504 if (_settings_client.sound.ambient) SndPlayVehicleFx(SND_2F_POP, v);
506 anim_state = 0;
509 if (b->y == 4 && b->x == 2) {
510 TileIndex tile;
512 anim_state++;
513 if (_settings_client.sound.ambient) SndPlayVehicleFx(SND_31_EXTRACT, v);
515 tile = TileVirtXY(v->x_pos, v->y_pos);
516 if (IsTileType(tile, MP_INDUSTRY) && GetIndustryGfx(tile) == GFX_BUBBLE_CATCHER) AddAnimatedTile(tile);
519 v->animation_state = anim_state;
520 b = &_bubble_movement[v->spritenum - 1][anim_state];
522 v->x_pos += b->x;
523 v->y_pos += b->y;
524 v->z_pos += b->z;
525 v->sprite_seq.Set(SPR_BUBBLE_0 + b->image);
527 v->UpdatePositionAndViewport();
529 return true;
533 typedef void EffectInitProc(EffectVehicle *v);
534 typedef bool EffectTickProc(EffectVehicle *v);
536 /** Functions to initialise an effect vehicle after construction. */
537 static EffectInitProc * const _effect_init_procs[] = {
538 ChimneySmokeInit, // EV_CHIMNEY_SMOKE
539 SteamSmokeInit, // EV_STEAM_SMOKE
540 DieselSmokeInit, // EV_DIESEL_SMOKE
541 ElectricSparkInit, // EV_ELECTRIC_SPARK
542 SmokeInit, // EV_CRASH_SMOKE
543 ExplosionLargeInit, // EV_EXPLOSION_LARGE
544 BreakdownSmokeInit, // EV_BREAKDOWN_SMOKE
545 ExplosionSmallInit, // EV_EXPLOSION_SMALL
546 BulldozerInit, // EV_BULLDOZER
547 BubbleInit, // EV_BUBBLE
548 SmokeInit, // EV_BREAKDOWN_SMOKE_AIRCRAFT
549 SmokeInit, // EV_COPPER_MINE_SMOKE
551 assert_compile(lengthof(_effect_init_procs) == EV_END);
553 /** Functions for controlling effect vehicles at each tick. */
554 static EffectTickProc * const _effect_tick_procs[] = {
555 ChimneySmokeTick, // EV_CHIMNEY_SMOKE
556 SteamSmokeTick, // EV_STEAM_SMOKE
557 DieselSmokeTick, // EV_DIESEL_SMOKE
558 ElectricSparkTick, // EV_ELECTRIC_SPARK
559 SmokeTick, // EV_CRASH_SMOKE
560 ExplosionLargeTick, // EV_EXPLOSION_LARGE
561 BreakdownSmokeTick, // EV_BREAKDOWN_SMOKE
562 ExplosionSmallTick, // EV_EXPLOSION_SMALL
563 BulldozerTick, // EV_BULLDOZER
564 BubbleTick, // EV_BUBBLE
565 SmokeTick, // EV_BREAKDOWN_SMOKE_AIRCRAFT
566 SmokeTick, // EV_COPPER_MINE_SMOKE
568 assert_compile(lengthof(_effect_tick_procs) == EV_END);
570 /** Transparency options affecting the effects. */
571 static const TransparencyOption _effect_transparency_options[] = {
572 TO_INDUSTRIES, // EV_CHIMNEY_SMOKE
573 TO_INVALID, // EV_STEAM_SMOKE
574 TO_INVALID, // EV_DIESEL_SMOKE
575 TO_INVALID, // EV_ELECTRIC_SPARK
576 TO_INVALID, // EV_CRASH_SMOKE
577 TO_INVALID, // EV_EXPLOSION_LARGE
578 TO_INVALID, // EV_BREAKDOWN_SMOKE
579 TO_INVALID, // EV_EXPLOSION_SMALL
580 TO_INVALID, // EV_BULLDOZER
581 TO_INDUSTRIES, // EV_BUBBLE
582 TO_INVALID, // EV_BREAKDOWN_SMOKE_AIRCRAFT
583 TO_INDUSTRIES, // EV_COPPER_MINE_SMOKE
585 assert_compile(lengthof(_effect_transparency_options) == EV_END);
589 * Create an effect vehicle at a particular location.
590 * @param x The x location on the map.
591 * @param y The y location on the map.
592 * @param z The z location on the map.
593 * @param type The type of effect vehicle.
594 * @return The effect vehicle.
596 EffectVehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicleType type)
598 if (!Vehicle::CanAllocateItem()) return NULL;
600 EffectVehicle *v = new EffectVehicle();
601 v->subtype = type;
602 v->x_pos = x;
603 v->y_pos = y;
604 v->z_pos = z;
605 v->tile = 0;
606 v->UpdateDeltaXY(INVALID_DIR);
607 v->vehstatus = VS_UNCLICKABLE;
609 _effect_init_procs[type](v);
611 v->UpdatePositionAndViewport();
613 return v;
617 * Create an effect vehicle above a particular location.
618 * @param x The x location on the map.
619 * @param y The y location on the map.
620 * @param z The offset from the ground.
621 * @param type The type of effect vehicle.
622 * @return The effect vehicle.
624 EffectVehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type)
626 int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE);
627 int safe_y = Clamp(y, 0, MapMaxY() * TILE_SIZE);
628 return CreateEffectVehicle(x, y, GetSlopePixelZ(safe_x, safe_y) + z, type);
632 * Create an effect vehicle above a particular vehicle.
633 * @param v The vehicle to base the position on.
634 * @param x The x offset to the vehicle.
635 * @param y The y offset to the vehicle.
636 * @param z The z offset to the vehicle.
637 * @param type The type of effect vehicle.
638 * @return The effect vehicle.
640 EffectVehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type)
642 return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type);
645 bool EffectVehicle::Tick()
647 return _effect_tick_procs[this->subtype](this);
650 void EffectVehicle::UpdateDeltaXY(Direction direction)
652 this->x_offs = 0;
653 this->y_offs = 0;
654 this->x_extent = 1;
655 this->y_extent = 1;
656 this->z_extent = 1;
660 * Determines the transparency option affecting the effect.
661 * @return Transparency option, or TO_INVALID if none.
663 TransparencyOption EffectVehicle::GetTransparencyOption() const
665 return _effect_transparency_options[this->subtype];