# effectvehicle.cpp

Go to the documentation of this file.

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