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 #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
00535 static EffectInitProc * const _effect_init_procs[] = {
00536 ChimneySmokeInit,
00537 SteamSmokeInit,
00538 DieselSmokeInit,
00539 ElectricSparkInit,
00540 SmokeInit,
00541 ExplosionLargeInit,
00542 BreakdownSmokeInit,
00543 ExplosionSmallInit,
00544 BulldozerInit,
00545 BubbleInit,
00546 SmokeInit,
00547 SmokeInit,
00548 };
00549 assert_compile(lengthof(_effect_init_procs) == EV_END);
00550
00552 static EffectTickProc * const _effect_tick_procs[] = {
00553 ChimneySmokeTick,
00554 SteamSmokeTick,
00555 DieselSmokeTick,
00556 ElectricSparkTick,
00557 SmokeTick,
00558 ExplosionLargeTick,
00559 BreakdownSmokeTick,
00560 ExplosionSmallTick,
00561 BulldozerTick,
00562 BubbleTick,
00563 SmokeTick,
00564 SmokeTick,
00565 };
00566 assert_compile(lengthof(_effect_tick_procs) == EV_END);
00567
00569 static const TransparencyOption _effect_transparency_options[] = {
00570 TO_INDUSTRIES,
00571 TO_INVALID,
00572 TO_INVALID,
00573 TO_INVALID,
00574 TO_INVALID,
00575 TO_INVALID,
00576 TO_INVALID,
00577 TO_INVALID,
00578 TO_INVALID,
00579 TO_INDUSTRIES,
00580 TO_INVALID,
00581 TO_INDUSTRIES,
00582 };
00583 assert_compile(lengthof(_effect_transparency_options) == EV_END);
00584
00585
00594 EffectVehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicleType type)
00595 {
00596 if (!Vehicle::CanAllocateItem()) return NULL;
00597
00598 EffectVehicle *v = new EffectVehicle();
00599 v->subtype = type;
00600 v->x_pos = x;
00601 v->y_pos = y;
00602 v->z_pos = z;
00603 v->tile = 0;
00604 v->UpdateDeltaXY(INVALID_DIR);
00605 v->vehstatus = VS_UNCLICKABLE;
00606
00607 _effect_init_procs[type](v);
00608
00609 VehicleMove(v, false);
00610 MarkSingleVehicleDirty(v);
00611
00612 return v;
00613 }
00614
00623 EffectVehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type)
00624 {
00625 int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE);
00626 int safe_y = Clamp(y, 0, MapMaxY() * TILE_SIZE);
00627 return CreateEffectVehicle(x, y, GetSlopeZ(safe_x, safe_y) + z, type);
00628 }
00629
00639 EffectVehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type)
00640 {
00641 return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type);
00642 }
00643
00644 bool EffectVehicle::Tick()
00645 {
00646 return _effect_tick_procs[this->subtype](this);
00647 }
00648
00649 void EffectVehicle::UpdateDeltaXY(Direction direction)
00650 {
00651 this->x_offs = 0;
00652 this->y_offs = 0;
00653 this->x_extent = 1;
00654 this->y_extent = 1;
00655 this->z_extent = 1;
00656 }
00657
00662 TransparencyOption EffectVehicle::GetTransparencyOption() const
00663 {
00664 return _effect_transparency_options[this->subtype];
00665 }