effectvehicle.cpp

Go to the documentation of this file.
00001 /* $Id: effectvehicle.cpp 24900 2013-01-08 22:46:42Z planetmaker $ */
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       if (_settings_client.sound.ambient) 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     if (_settings_client.sound.ambient) 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 }