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