00001
00002
00003
00004
00005
00006
00007
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 }