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 
00021 #include "table/sprites.h"
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     VehicleMove(v, true);
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) VehicleMove(v, true);
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     VehicleMove(v, true);
00098   } else if ((v->progress & 7) == 1) {
00099     if (v->cur_image != SPR_DIESEL_SMOKE_5) {
00100       v->cur_image++;
00101       VehicleMove(v, true);
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       VehicleMove(v, true);
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) VehicleMove(v, true);
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       VehicleMove(v, true);
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     VehicleMove(v, true);
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       VehicleMove(v, true);
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     VehicleMove(v, true);
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       VehicleMove(v, true);
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   VehicleMove(v, true);
00525 
00526   return true;
00527 }
00528 
00529 
00530 typedef void EffectInitProc(EffectVehicle *v);
00531 typedef bool EffectTickProc(EffectVehicle *v);
00532 
00533 static EffectInitProc * const _effect_init_procs[] = {
00534   ChimneySmokeInit,
00535   SteamSmokeInit,
00536   DieselSmokeInit,
00537   ElectricSparkInit,
00538   SmokeInit,
00539   ExplosionLargeInit,
00540   BreakdownSmokeInit,
00541   ExplosionSmallInit,
00542   BulldozerInit,
00543   BubbleInit,
00544 };
00545 
00546 static EffectTickProc * const _effect_tick_procs[] = {
00547   ChimneySmokeTick,
00548   SteamSmokeTick,
00549   DieselSmokeTick,
00550   ElectricSparkTick,
00551   SmokeTick,
00552   ExplosionLargeTick,
00553   BreakdownSmokeTick,
00554   ExplosionSmallTick,
00555   BulldozerTick,
00556   BubbleTick,
00557 };
00558 
00559 
00560 EffectVehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicleType type)
00561 {
00562   if (!Vehicle::CanAllocateItem()) return NULL;
00563 
00564   EffectVehicle *v = new EffectVehicle();
00565   v->subtype = type;
00566   v->x_pos = x;
00567   v->y_pos = y;
00568   v->z_pos = z;
00569   v->tile = 0;
00570   v->UpdateDeltaXY(INVALID_DIR);
00571   v->vehstatus = VS_UNCLICKABLE;
00572 
00573   _effect_init_procs[type](v);
00574 
00575   VehicleMove(v, false);
00576   MarkSingleVehicleDirty(v);
00577 
00578   return v;
00579 }
00580 
00581 EffectVehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type)
00582 {
00583   int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE);
00584   int safe_y = Clamp(y, 0, MapMaxY() * TILE_SIZE);
00585   return CreateEffectVehicle(x, y, GetSlopeZ(safe_x, safe_y) + z, type);
00586 }
00587 
00588 EffectVehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type)
00589 {
00590   return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type);
00591 }
00592 
00593 bool EffectVehicle::Tick()
00594 {
00595   return _effect_tick_procs[this->subtype](this);
00596 }
00597 
00598 void EffectVehicle::UpdateDeltaXY(Direction direction)
00599 {
00600   this->x_offs        = 0;
00601   this->y_offs        = 0;
00602   this->x_extent      = 1;
00603   this->y_extent      = 1;
00604   this->z_extent      = 1;
00605 }

Generated on Sat Dec 26 20:06:00 2009 for OpenTTD by  doxygen 1.5.6