# effectvehicle.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "landscape.h"
    00014 #include "core/random_func.hpp"
    00015 #include "industry_map.h"
    00016 #include "vehicle_func.h"
    00017 #include "sound_func.h"
    00018 #include "animated_tile_func.h"
    00019 #include "effectvehicle_func.h"
    00020 #include "effectvehicle_base.h"
    00021
    00022
    00023 static void ChimneySmokeInit(EffectVehicle *v)
    00024 {
    00025   uint32 r = Random();
    00026   v->cur_image = SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3);
    00027   v->progress = GB(r, 16, 3);
    00028 }
    00029
    00030 static bool ChimneySmokeTick(EffectVehicle *v)
    00031 {
    00032   if (v->progress > 0) {
    00033     v->progress--;
    00034   } else {
    00035     TileIndex tile = TileVirtXY(v->x_pos, v->y_pos);
    00036     if (!IsTileType(tile, MP_INDUSTRY)) {
    00037       delete v;
    00038       return false;
    00039     }
    00040
    00041     if (v->cur_image != SPR_CHIMNEY_SMOKE_7) {
    00042       v->cur_image++;
    00043     } else {
    00044       v->cur_image = SPR_CHIMNEY_SMOKE_0;
    00045     }
    00046     v->progress = 7;
    00047     VehicleUpdatePositionAndViewport(v);
    00048   }
    00049
    00050   return true;
    00051 }
    00052
    00053 static void SteamSmokeInit(EffectVehicle *v)
    00054 {
    00055   v->cur_image = SPR_STEAM_SMOKE_0;
    00056   v->progress = 12;
    00057 }
    00058
    00059 static bool SteamSmokeTick(EffectVehicle *v)
    00060 {
    00061   bool moved = false;
    00062
    00063   v->progress++;
    00064
    00065   if ((v->progress & 7) == 0) {
    00066     v->z_pos++;
    00067     moved = true;
    00068   }
    00069
    00070   if ((v->progress & 0xF) == 4) {
    00071     if (v->cur_image != SPR_STEAM_SMOKE_4) {
    00072       v->cur_image++;
    00073     } else {
    00074       delete v;
    00075       return false;
    00076     }
    00077     moved = true;
    00078   }
    00079
    00080   if (moved) VehicleUpdatePositionAndViewport(v);
    00081
    00082   return true;
    00083 }
    00084
    00085 static void DieselSmokeInit(EffectVehicle *v)
    00086 {
    00087   v->cur_image = SPR_DIESEL_SMOKE_0;
    00088   v->progress = 0;
    00089 }
    00090
    00091 static bool DieselSmokeTick(EffectVehicle *v)
    00092 {
    00093   v->progress++;
    00094
    00095   if ((v->progress & 3) == 0) {
    00096     v->z_pos++;
    00097     VehicleUpdatePositionAndViewport(v);
    00098   } else if ((v->progress & 7) == 1) {
    00099     if (v->cur_image != SPR_DIESEL_SMOKE_5) {
    00100       v->cur_image++;
    00101       VehicleUpdatePositionAndViewport(v);
    00102     } else {
    00103       delete v;
    00104       return false;
    00105     }
    00106   }
    00107
    00108   return true;
    00109 }
    00110
    00111 static void ElectricSparkInit(EffectVehicle *v)
    00112 {
    00113   v->cur_image = SPR_ELECTRIC_SPARK_0;
    00114   v->progress = 1;
    00115 }
    00116
    00117 static bool ElectricSparkTick(EffectVehicle *v)
    00118 {
    00119   if (v->progress < 2) {
    00120     v->progress++;
    00121   } else {
    00122     v->progress = 0;
    00123     if (v->cur_image != SPR_ELECTRIC_SPARK_5) {
    00124       v->cur_image++;
    00125       VehicleUpdatePositionAndViewport(v);
    00126     } else {
    00127       delete v;
    00128       return false;
    00129     }
    00130   }
    00131
    00132   return true;
    00133 }
    00134
    00135 static void SmokeInit(EffectVehicle *v)
    00136 {
    00137   v->cur_image = SPR_SMOKE_0;
    00138   v->progress = 12;
    00139 }
    00140
    00141 static bool SmokeTick(EffectVehicle *v)
    00142 {
    00143   bool moved = false;
    00144
    00145   v->progress++;
    00146
    00147   if ((v->progress & 3) == 0) {
    00148     v->z_pos++;
    00149     moved = true;
    00150   }
    00151
    00152   if ((v->progress & 0xF) == 4) {
    00153     if (v->cur_image != SPR_SMOKE_4) {
    00154       v->cur_image++;
    00155     } else {
    00156       delete v;
    00157       return false;
    00158     }
    00159     moved = true;
    00160   }
    00161
    00162   if (moved) VehicleUpdatePositionAndViewport(v);
    00163
    00164   return true;
    00165 }
    00166
    00167 static void ExplosionLargeInit(EffectVehicle *v)
    00168 {
    00169   v->cur_image = SPR_EXPLOSION_LARGE_0;
    00170   v->progress = 0;
    00171 }
    00172
    00173 static bool ExplosionLargeTick(EffectVehicle *v)
    00174 {
    00175   v->progress++;
    00176   if ((v->progress & 3) == 0) {
    00177     if (v->cur_image != SPR_EXPLOSION_LARGE_F) {
    00178       v->cur_image++;
    00179       VehicleUpdatePositionAndViewport(v);
    00180     } else {
    00181       delete v;
    00182       return false;
    00183     }
    00184   }
    00185
    00186   return true;
    00187 }
    00188
    00189 static void BreakdownSmokeInit(EffectVehicle *v)
    00190 {
    00191   v->cur_image = SPR_BREAKDOWN_SMOKE_0;
    00192   v->progress = 0;
    00193 }
    00194
    00195 static bool BreakdownSmokeTick(EffectVehicle *v)
    00196 {
    00197   v->progress++;
    00198   if ((v->progress & 7) == 0) {
    00199     if (v->cur_image != SPR_BREAKDOWN_SMOKE_3) {
    00200       v->cur_image++;
    00201     } else {
    00202       v->cur_image = SPR_BREAKDOWN_SMOKE_0;
    00203     }
    00204     VehicleUpdatePositionAndViewport(v);
    00205   }
    00206
    00207   v->animation_state--;
    00208   if (v->animation_state == 0) {
    00209     delete v;
    00210     return false;
    00211   }
    00212
    00213   return true;
    00214 }
    00215
    00216 static void ExplosionSmallInit(EffectVehicle *v)
    00217 {
    00218   v->cur_image = SPR_EXPLOSION_SMALL_0;
    00219   v->progress = 0;
    00220 }
    00221
    00222 static bool ExplosionSmallTick(EffectVehicle *v)
    00223 {
    00224   v->progress++;
    00225   if ((v->progress & 3) == 0) {
    00226     if (v->cur_image != SPR_EXPLOSION_SMALL_B) {
    00227       v->cur_image++;
    00228       VehicleUpdatePositionAndViewport(v);
    00229     } else {
    00230       delete v;
    00231       return false;
    00232     }
    00233   }
    00234
    00235   return true;
    00236 }
    00237
    00238 static void BulldozerInit(EffectVehicle *v)
    00239 {
    00240   v->cur_image = SPR_BULLDOZER_NE;
    00241   v->progress = 0;
    00242   v->animation_state = 0;
    00243   v->animation_substate = 0;
    00244 }
    00245
    00246 struct BulldozerMovement {
    00247   byte direction:2;
    00248   byte image:2;
    00249   byte duration:3;
    00250 };
    00251
    00252 static const BulldozerMovement _bulldozer_movement[] = {
    00253   { 0, 0, 4 },
    00254   { 3, 3, 4 },
    00255   { 2, 2, 7 },
    00256   { 0, 2, 7 },
    00257   { 1, 1, 3 },
    00258   { 2, 2, 7 },
    00259   { 0, 2, 7 },
    00260   { 1, 1, 3 },
    00261   { 2, 2, 7 },
    00262   { 0, 2, 7 },
    00263   { 3, 3, 6 },
    00264   { 2, 2, 6 },
    00265   { 1, 1, 7 },
    00266   { 3, 1, 7 },
    00267   { 0, 0, 3 },
    00268   { 1, 1, 7 },
    00269   { 3, 1, 7 },
    00270   { 0, 0, 3 },
    00271   { 1, 1, 7 },
    00272   { 3, 1, 7 }
    00273 };
    00274
    00275 static const struct {
    00276   int8 x;
    00277   int8 y;
    00278 } _inc_by_dir[] = {
    00279   { -1,  0 },
    00280   {  0,  1 },
    00281   {  1,  0 },
    00282   {  0, -1 }
    00283 };
    00284
    00285 static bool BulldozerTick(EffectVehicle *v)
    00286 {
    00287   v->progress++;
    00288   if ((v->progress & 7) == 0) {
    00289     const BulldozerMovement *b = &_bulldozer_movement[v->animation_state];
    00290
    00291     v->cur_image = SPR_BULLDOZER_NE + b->image;
    00292
    00293     v->x_pos += _inc_by_dir[b->direction].x;
    00294     v->y_pos += _inc_by_dir[b->direction].y;
    00295
    00296     v->animation_substate++;
    00297     if (v->animation_substate >= b->duration) {
    00298       v->animation_substate = 0;
    00299       v->animation_state++;
    00300       if (v->animation_state == lengthof(_bulldozer_movement)) {
    00301         delete v;
    00302         return false;
    00303       }
    00304     }
    00305     VehicleUpdatePositionAndViewport(v);
    00306   }
    00307
    00308   return true;
    00309 }
    00310
    00311 static void BubbleInit(EffectVehicle *v)
    00312 {
    00313   v->cur_image = SPR_BUBBLE_GENERATE_0;
    00314   v->spritenum = 0;
    00315   v->progress = 0;
    00316 }
    00317
    00318 struct BubbleMovement {
    00319   int8 x:4;
    00320   int8 y:4;
    00321   int8 z:4;
    00322   byte image:4;
    00323 };
    00324
    00325 #define MK(x, y, z, i) { x, y, z, i }
    00326 #define ME(i) { i, 4, 0, 0 }
    00327
    00328 static const BubbleMovement _bubble_float_sw[] = {
    00329   MK(0, 0, 1, 0),
    00330   MK(1, 0, 1, 1),
    00331   MK(0, 0, 1, 0),
    00332   MK(1, 0, 1, 2),
    00333   ME(1)
    00334 };
    00335
    00336
    00337 static const BubbleMovement _bubble_float_ne[] = {
    00338   MK( 0, 0, 1, 0),
    00339   MK(-1, 0, 1, 1),
    00340   MK( 0, 0, 1, 0),
    00341   MK(-1, 0, 1, 2),
    00342   ME(1)
    00343 };
    00344
    00345 static const BubbleMovement _bubble_float_se[] = {
    00346   MK(0, 0, 1, 0),
    00347   MK(0, 1, 1, 1),
    00348   MK(0, 0, 1, 0),
    00349   MK(0, 1, 1, 2),
    00350   ME(1)
    00351 };
    00352
    00353 static const BubbleMovement _bubble_float_nw[] = {
    00354   MK(0,  0, 1, 0),
    00355   MK(0, -1, 1, 1),
    00356   MK(0,  0, 1, 0),
    00357   MK(0, -1, 1, 2),
    00358   ME(1)
    00359 };
    00360
    00361 static const BubbleMovement _bubble_burst[] = {
    00362   MK(0, 0, 1, 2),
    00363   MK(0, 0, 1, 7),
    00364   MK(0, 0, 1, 8),
    00365   MK(0, 0, 1, 9),
    00366   ME(0)
    00367 };
    00368
    00369 static const BubbleMovement _bubble_absorb[] = {
    00370   MK(0, 0, 1, 0),
    00371   MK(0, 0, 1, 1),
    00372   MK(0, 0, 1, 0),
    00373   MK(0, 0, 1, 2),
    00374   MK(0, 0, 1, 0),
    00375   MK(0, 0, 1, 1),
    00376   MK(0, 0, 1, 0),
    00377   MK(0, 0, 1, 2),
    00378   MK(0, 0, 1, 0),
    00379   MK(0, 0, 1, 1),
    00380   MK(0, 0, 1, 0),
    00381   MK(0, 0, 1, 2),
    00382   MK(0, 0, 1, 0),
    00383   MK(0, 0, 1, 1),
    00384   MK(0, 0, 1, 0),
    00385   MK(0, 0, 1, 2),
    00386   MK(0, 0, 1, 0),
    00387   MK(0, 0, 1, 1),
    00388   MK(0, 0, 1, 0),
    00389   MK(0, 0, 1, 2),
    00390   MK(0, 0, 1, 0),
    00391   MK(0, 0, 1, 1),
    00392   MK(0, 0, 1, 0),
    00393   MK(0, 0, 1, 2),
    00394   MK(0, 0, 1, 0),
    00395   MK(0, 0, 1, 1),
    00396   MK(0, 0, 1, 0),
    00397   MK(0, 0, 1, 2),
    00398   MK(0, 0, 1, 0),
    00399   MK(0, 0, 1, 1),
    00400   MK(0, 0, 1, 0),
    00401   MK(0, 0, 1, 2),
    00402   MK(0, 0, 1, 0),
    00403   MK(0, 0, 1, 1),
    00404   MK(0, 0, 1, 0),
    00405   MK(0, 0, 1, 2),
    00406   MK(0, 0, 1, 0),
    00407   MK(0, 0, 1, 1),
    00408   MK(0, 0, 1, 0),
    00409   MK(0, 0, 1, 2),
    00410   MK(0, 0, 1, 0),
    00411   MK(0, 0, 1, 1),
    00412   MK(0, 0, 1, 0),
    00413   MK(0, 0, 1, 2),
    00414   MK(0, 0, 1, 0),
    00415   MK(0, 0, 1, 1),
    00416   MK(0, 0, 1, 0),
    00417   MK(0, 0, 1, 2),
    00418   MK(0, 0, 1, 0),
    00419   MK(0, 0, 1, 1),
    00420   MK(0, 0, 1, 0),
    00421   MK(0, 0, 1, 2),
    00422   MK(0, 0, 1, 0),
    00423   MK(0, 0, 1, 1),
    00424   MK(0, 0, 1, 0),
    00425   MK(0, 0, 1, 2),
    00426   MK(0, 0, 1, 0),
    00427   MK(0, 0, 1, 1),
    00428   MK(0, 0, 1, 0),
    00429   MK(0, 0, 1, 2),
    00430   MK(0, 0, 1, 0),
    00431   MK(0, 0, 1, 1),
    00432   MK(2, 1, 3, 0),
    00433   MK(1, 1, 3, 1),
    00434   MK(2, 1, 3, 0),
    00435   MK(1, 1, 3, 2),
    00436   MK(2, 1, 3, 0),
    00437   MK(1, 1, 3, 1),
    00438   MK(2, 1, 3, 0),
    00439   MK(1, 0, 1, 2),
    00440   MK(0, 0, 1, 0),
    00441   MK(1, 0, 1, 1),
    00442   MK(0, 0, 1, 0),
    00443   MK(1, 0, 1, 2),
    00444   MK(0, 0, 1, 0),
    00445   MK(1, 0, 1, 1),
    00446   MK(0, 0, 1, 0),
    00447   MK(1, 0, 1, 2),
    00448   ME(2),
    00449   MK(0, 0, 0, 0xA),
    00450   MK(0, 0, 0, 0xB),
    00451   MK(0, 0, 0, 0xC),
    00452   MK(0, 0, 0, 0xD),
    00453   MK(0, 0, 0, 0xE),
    00454   ME(0)
    00455 };
    00456 #undef ME
    00457 #undef MK
    00458
    00459 static const BubbleMovement * const _bubble_movement[] = {
    00460   _bubble_float_sw,
    00461   _bubble_float_ne,
    00462   _bubble_float_se,
    00463   _bubble_float_nw,
    00464   _bubble_burst,
    00465   _bubble_absorb,
    00466 };
    00467
    00468 static bool BubbleTick(EffectVehicle *v)
    00469 {
    00470   uint anim_state;
    00471
    00472   v->progress++;
    00473   if ((v->progress & 3) != 0) return true;
    00474
    00475   if (v->spritenum == 0) {
    00476     v->cur_image++;
    00477     if (v->cur_image < SPR_BUBBLE_GENERATE_3) {
    00478       VehicleUpdatePositionAndViewport(v);
    00479       return true;
    00480     }
    00481     if (v->animation_substate != 0) {
    00482       v->spritenum = GB(Random(), 0, 2) + 1;
    00483     } else {
    00484       v->spritenum = 6;
    00485     }
    00486     anim_state = 0;
    00487   } else {
    00488     anim_state = v->animation_state + 1;
    00489   }
    00490
    00491   const BubbleMovement *b = &_bubble_movement[v->spritenum - 1][anim_state];
    00492
    00493   if (b->y == 4 && b->x == 0) {
    00494     delete v;
    00495     return false;
    00496   }
    00497
    00498   if (b->y == 4 && b->x == 1) {
    00499     if (v->z_pos > 180 || Chance16I(1, 96, Random())) {
    00500       v->spritenum = 5;
    00501       SndPlayVehicleFx(SND_2F_POP, v);
    00502     }
    00503     anim_state = 0;
    00504   }
    00505
    00506   if (b->y == 4 && b->x == 2) {
    00507     TileIndex tile;
    00508
    00509     anim_state++;
    00510     SndPlayVehicleFx(SND_31_EXTRACT, v);
    00511
    00512     tile = TileVirtXY(v->x_pos, v->y_pos);
    00513     if (IsTileType(tile, MP_INDUSTRY) && GetIndustryGfx(tile) == GFX_BUBBLE_CATCHER) AddAnimatedTile(tile);
    00514   }
    00515
    00516   v->animation_state = anim_state;
    00517   b = &_bubble_movement[v->spritenum - 1][anim_state];
    00518
    00519   v->x_pos += b->x;
    00520   v->y_pos += b->y;
    00521   v->z_pos += b->z;
    00522   v->cur_image = SPR_BUBBLE_0 + b->image;
    00523
    00524   VehicleUpdatePositionAndViewport(v);
    00525
    00526   return true;
    00527 }
    00528
    00529
    00530 typedef void EffectInitProc(EffectVehicle *v);
    00531 typedef bool EffectTickProc(EffectVehicle *v);
    00532
    00534 static EffectInitProc * const _effect_init_procs[] = {
    00535   ChimneySmokeInit,   // EV_CHIMNEY_SMOKE
    00536   SteamSmokeInit,     // EV_STEAM_SMOKE
    00537   DieselSmokeInit,    // EV_DIESEL_SMOKE
    00538   ElectricSparkInit,  // EV_ELECTRIC_SPARK
    00539   SmokeInit,          // EV_CRASH_SMOKE
    00540   ExplosionLargeInit, // EV_EXPLOSION_LARGE
    00541   BreakdownSmokeInit, // EV_BREAKDOWN_SMOKE
    00542   ExplosionSmallInit, // EV_EXPLOSION_SMALL
    00543   BulldozerInit,      // EV_BULLDOZER
    00544   BubbleInit,         // EV_BUBBLE
    00545   SmokeInit,          // EV_BREAKDOWN_SMOKE_AIRCRAFT
    00546   SmokeInit,          // EV_COPPER_MINE_SMOKE
    00547 };
    00548 assert_compile(lengthof(_effect_init_procs) == EV_END);
    00549
    00551 static EffectTickProc * const _effect_tick_procs[] = {
    00552   ChimneySmokeTick,   // EV_CHIMNEY_SMOKE
    00553   SteamSmokeTick,     // EV_STEAM_SMOKE
    00554   DieselSmokeTick,    // EV_DIESEL_SMOKE
    00555   ElectricSparkTick,  // EV_ELECTRIC_SPARK
    00556   SmokeTick,          // EV_CRASH_SMOKE
    00557   ExplosionLargeTick, // EV_EXPLOSION_LARGE
    00558   BreakdownSmokeTick, // EV_BREAKDOWN_SMOKE
    00559   ExplosionSmallTick, // EV_EXPLOSION_SMALL
    00560   BulldozerTick,      // EV_BULLDOZER
    00561   BubbleTick,         // EV_BUBBLE
    00562   SmokeTick,          // EV_BREAKDOWN_SMOKE_AIRCRAFT
    00563   SmokeTick,          // EV_COPPER_MINE_SMOKE
    00564 };
    00565 assert_compile(lengthof(_effect_tick_procs) == EV_END);
    00566
    00568 static const TransparencyOption _effect_transparency_options[] = {
    00569   TO_INDUSTRIES,      // EV_CHIMNEY_SMOKE
    00570   TO_INVALID,         // EV_STEAM_SMOKE
    00571   TO_INVALID,         // EV_DIESEL_SMOKE
    00572   TO_INVALID,         // EV_ELECTRIC_SPARK
    00573   TO_INVALID,         // EV_CRASH_SMOKE
    00574   TO_INVALID,         // EV_EXPLOSION_LARGE
    00575   TO_INVALID,         // EV_BREAKDOWN_SMOKE
    00576   TO_INVALID,         // EV_EXPLOSION_SMALL
    00577   TO_INVALID,         // EV_BULLDOZER
    00578   TO_INDUSTRIES,      // EV_BUBBLE
    00579   TO_INVALID,         // EV_BREAKDOWN_SMOKE_AIRCRAFT
    00580   TO_INDUSTRIES,      // EV_COPPER_MINE_SMOKE
    00581 };
    00582 assert_compile(lengthof(_effect_transparency_options) == EV_END);
    00583
    00584
    00593 EffectVehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicleType type)
    00594 {
    00595   if (!Vehicle::CanAllocateItem()) return NULL;
    00596
    00597   EffectVehicle *v = new EffectVehicle();
    00598   v->subtype = type;
    00599   v->x_pos = x;
    00600   v->y_pos = y;
    00601   v->z_pos = z;
    00602   v->tile = 0;
    00603   v->UpdateDeltaXY(INVALID_DIR);
    00604   v->vehstatus = VS_UNCLICKABLE;
    00605
    00606   _effect_init_procs[type](v);
    00607
    00608   VehicleUpdatePositionAndViewport(v);
    00609
    00610   return v;
    00611 }
    00612
    00621 EffectVehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type)
    00622 {
    00623   int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE);
    00624   int safe_y = Clamp(y, 0, MapMaxY() * TILE_SIZE);
    00625   return CreateEffectVehicle(x, y, GetSlopePixelZ(safe_x, safe_y) + z, type);
    00626 }
    00627
    00637 EffectVehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type)
    00638 {
    00639   return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type);
    00640 }
    00641
    00642 bool EffectVehicle::Tick()
    00643 {
    00644   return _effect_tick_procs[this->subtype](this);
    00645 }
    00646
    00647 void EffectVehicle::UpdateDeltaXY(Direction direction)
    00648 {
    00649   this->x_offs        = 0;
    00650   this->y_offs        = 0;
    00651   this->x_extent      = 1;
    00652   this->y_extent      = 1;
    00653   this->z_extent      = 1;
    00654 }
    00655
    00660 TransparencyOption EffectVehicle::GetTransparencyOption() const
    00661 {
    00662   return _effect_transparency_options[this->subtype];
    00663 }