truelight@0: #include "stdafx.h" truelight@0: #include "ttd.h" truelight@0: #include "vehicle.h" truelight@0: #include "command.h" truelight@0: #include "news.h" truelight@0: #include "gfx.h" truelight@0: #include "station.h" truelight@0: #include "town.h" truelight@0: #include "industry.h" truelight@0: #include "player.h" truelight@0: #include "airport_movement.h" truelight@0: truelight@0: static void DisasterClearSquare(uint tile) truelight@0: { truelight@0: int type; truelight@0: truelight@0: if (!EnsureNoVehicle(tile)) truelight@0: return; truelight@0: truelight@0: type = _map_type_and_height[tile] >> 4; truelight@0: truelight@0: if (type == MP_RAILWAY) { truelight@0: if (IS_HUMAN_PLAYER(_map_owner[tile])) truelight@0: DoClearSquare(tile); truelight@0: } else if (type == MP_HOUSE) { truelight@0: byte p = _current_player; truelight@0: _current_player = OWNER_NONE; truelight@0: DoCommandByTile(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); truelight@0: _current_player = p; truelight@0: } else if (type == MP_TREES || type == MP_CLEAR) { truelight@0: DoClearSquare(tile); truelight@0: } truelight@0: } truelight@0: truelight@0: static const SpriteID _disaster_images_1[] = {0xF41,0xF41,0xF41,0xF41,0xF41,0xF41,0xF41,0xF41}; truelight@0: static const SpriteID _disaster_images_2[] = {0xF44,0xF44,0xF44,0xF44,0xF44,0xF44,0xF44,0xF44}; truelight@0: static const SpriteID _disaster_images_3[] = {0xF4E,0xF4E,0xF4E,0xF4E,0xF4E,0xF4E,0xF4E,0xF4E}; truelight@0: static const SpriteID _disaster_images_4[] = {0xF46,0xF46,0xF47,0xF47,0xF48,0xF48,0xF49,0xF49}; truelight@0: static const SpriteID _disaster_images_5[] = {0xF4A,0xF4A,0xF4B,0xF4B,0xF4C,0xF4C,0xF4D,0xF4D}; truelight@0: static const SpriteID _disaster_images_6[] = {0xF50,0xF50,0xF50,0xF50,0xF50,0xF50,0xF50,0xF50}; truelight@0: static const SpriteID _disaster_images_7[] = {0xF51,0xF51,0xF51,0xF51,0xF51,0xF51,0xF51,0xF51}; truelight@0: static const SpriteID _disaster_images_8[] = {0xF52,0xF52,0xF52,0xF52,0xF52,0xF52,0xF52,0xF52}; truelight@0: static const SpriteID _disaster_images_9[] = {0xF3E,0xF3E,0xF3E,0xF3E,0xF3E,0xF3E,0xF3E,0xF3E}; truelight@0: truelight@0: static const SpriteID * const _disaster_images[] = { truelight@0: _disaster_images_1,_disaster_images_1, truelight@0: _disaster_images_2,_disaster_images_2, truelight@0: _disaster_images_3,_disaster_images_3, truelight@0: _disaster_images_8,_disaster_images_8,_disaster_images_9, truelight@0: _disaster_images_6,_disaster_images_6, truelight@0: _disaster_images_7,_disaster_images_7, truelight@0: _disaster_images_4,_disaster_images_5, truelight@0: }; truelight@0: truelight@0: static void DisasterVehicleUpdateImage(Vehicle *v) truelight@0: { truelight@0: int img = v->u.disaster.image_override; truelight@0: if (img == 0) truelight@0: img = _disaster_images[v->subtype][v->direction]; truelight@0: v->cur_image = img; truelight@0: } truelight@0: truelight@0: static void InitializeDisasterVehicle(Vehicle *v, int x, int y, byte z, byte direction, byte subtype) truelight@0: { truelight@0: v->type = VEH_Disaster; truelight@0: v->x_pos = x; truelight@0: v->y_pos = y; truelight@0: v->z_pos = z; truelight@0: v->tile = TILE_FROM_XY(x,y); truelight@0: v->direction = direction; truelight@0: v->subtype = subtype; truelight@0: v->x_offs = -1; truelight@0: v->y_offs = -1; truelight@0: v->sprite_width = 2; truelight@0: v->sprite_height = 2; truelight@0: v->z_height = 5; truelight@0: v->owner = OWNER_NONE; truelight@0: v->vehstatus = VS_UNCLICKABLE; truelight@0: v->u.disaster.image_override = 0; truelight@0: v->next_order = 0; truelight@0: truelight@0: DisasterVehicleUpdateImage(v); truelight@0: VehiclePositionChanged(v); truelight@0: BeginVehicleMove(v); truelight@0: EndVehicleMove(v); truelight@0: } truelight@0: truelight@0: static void DeleteDisasterVeh(Vehicle *v) truelight@0: { truelight@0: DeleteVehicleChain(v); truelight@0: } truelight@0: truelight@0: static void SetDisasterVehiclePos(Vehicle *v, int x, int y, byte z) truelight@0: { truelight@0: Vehicle *u; truelight@0: int yt; truelight@0: truelight@0: BeginVehicleMove(v); truelight@0: v->x_pos = x; truelight@0: v->y_pos = y; truelight@0: v->z_pos = z; truelight@0: v->tile = TILE_FROM_XY(x,y); truelight@0: truelight@0: DisasterVehicleUpdateImage(v); truelight@0: VehiclePositionChanged(v); truelight@0: EndVehicleMove(v); truelight@0: truelight@0: if ( (u=v->next) != NULL) { truelight@0: BeginVehicleMove(u); truelight@0: truelight@0: u->x_pos = x; truelight@0: u->y_pos = yt = y - 1 - (max(z - GetSlopeZ(x, y-1), 0) >> 3); truelight@0: u->z_pos = GetSlopeZ(x,yt); truelight@0: u->direction = v->direction; truelight@0: truelight@0: DisasterVehicleUpdateImage(u); truelight@0: VehiclePositionChanged(u); truelight@0: EndVehicleMove(u); truelight@0: truelight@0: if ( (u=u->next) != NULL) { truelight@0: BeginVehicleMove(u); truelight@0: u->x_pos = x; truelight@0: u->y_pos = y; truelight@0: u->z_pos = z + 5; truelight@0: VehiclePositionChanged(u); truelight@0: EndVehicleMove(u); truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: truelight@0: static void DisasterTick_Zeppeliner(Vehicle *v) truelight@0: { truelight@0: GetNewVehiclePosResult gp; truelight@0: Station *st; truelight@0: int x,y; truelight@0: byte z; truelight@0: uint tile; truelight@0: truelight@0: ++v->tick_counter; truelight@0: truelight@0: if (v->next_order < 2) { truelight@0: if (v->tick_counter&1) truelight@0: return; truelight@0: truelight@0: GetNewVehiclePos(v, &gp); truelight@0: truelight@0: SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); truelight@0: truelight@0: if (v->next_order == 1) { truelight@0: if (++v->age == 38) { truelight@0: v->next_order = 2; truelight@0: v->age = 0; truelight@0: } truelight@0: truelight@0: if ((v->tick_counter&7)==0) { truelight@0: CreateEffectVehicleRel(v, 0, -17, 2, EV_SMOKE_3); truelight@0: } truelight@0: } else if (v->next_order == 0) { truelight@0: tile = v->tile; /**/ truelight@0: truelight@0: if (IS_TILETYPE(tile, MP_STATION) && truelight@0: IS_BYTE_INSIDE(_map5[tile], 8, 0x43) && truelight@0: IS_HUMAN_PLAYER(_map_owner[tile])) { truelight@0: truelight@0: v->next_order = 1; truelight@0: v->age = 0; truelight@0: truelight@0: SET_DPARAM16(0, _map2[tile]); truelight@0: AddNewsItem(STR_B000_ZEPPELIN_DISASTER_AT, truelight@0: NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0), truelight@0: v->index, truelight@0: 0); truelight@0: } truelight@0: } truelight@0: if (v->y_pos >= (TILES_Y+9) * 16 - 1) truelight@0: DeleteDisasterVeh(v); truelight@0: return; truelight@0: } truelight@0: truelight@0: if (v->next_order > 2) { truelight@0: if (++v->age <= 13320) truelight@0: return; truelight@0: truelight@0: tile = v->tile; /**/ truelight@0: truelight@0: if (IS_TILETYPE(tile, MP_STATION) && truelight@0: IS_BYTE_INSIDE(_map5[tile], 8, 0x43) && truelight@0: IS_HUMAN_PLAYER(_map_owner[tile])) { truelight@0: truelight@0: st = DEREF_STATION(_map2[tile]); truelight@0: CLRBITS(st->airport_flags, RUNWAY_IN_block); truelight@0: } truelight@0: truelight@0: SetDisasterVehiclePos(v, v->x_pos, v->y_pos, v->z_pos); truelight@0: DeleteDisasterVeh(v); truelight@0: return; truelight@0: } truelight@0: truelight@0: x = v->x_pos; truelight@0: y = v->y_pos; truelight@0: z = GetSlopeZ(x,y); truelight@0: if (z < v->z_pos) truelight@0: z = v->z_pos - 1; truelight@0: SetDisasterVehiclePos(v, x, y, z); truelight@0: truelight@0: if (++v->age == 1) { truelight@0: CreateEffectVehicleRel(v, 0, 7, 8, EV_CRASHED_SMOKE); truelight@0: SndPlayVehicleFx(0x10, v); truelight@0: v->u.disaster.image_override = 0xF42; truelight@0: } else if (v->age == 70) { truelight@0: v->u.disaster.image_override = 0xF43; truelight@0: } else if (v->age <= 300) { truelight@0: if (!(v->tick_counter&7)) { truelight@0: uint32 r = Random(); truelight@0: truelight@0: CreateEffectVehicleRel(v, truelight@0: -7 + (r&0xF), truelight@0: -7 + (r>>4&0xF), truelight@0: 5 + (r>>8&0x7), truelight@0: EV_DEMOLISH); truelight@0: } truelight@0: } else if (v->age == 350) { truelight@0: v->next_order = 3; truelight@0: v->age = 0; truelight@0: } truelight@0: truelight@0: tile = v->tile;/**/ truelight@0: if (IS_TILETYPE(tile, MP_STATION) && truelight@0: IS_BYTE_INSIDE(_map5[tile], 8, 0x43) && truelight@0: IS_HUMAN_PLAYER(_map_owner[tile])) { truelight@0: truelight@0: st = DEREF_STATION(_map2[tile]); truelight@0: SETBITS(st->airport_flags, RUNWAY_IN_block); truelight@0: } truelight@0: } truelight@0: truelight@0: // UFO starts in the middle, and flies around a bit until it locates truelight@0: // a road vehicle which it targets. truelight@0: static void DisasterTick_UFO(Vehicle *v) truelight@0: { truelight@0: GetNewVehiclePosResult gp; truelight@0: Vehicle *u; truelight@0: uint dist; truelight@0: byte z; truelight@0: truelight@0: v->u.disaster.image_override = (++v->tick_counter & 8) ? 0xF45 : 0xF44; truelight@0: truelight@0: if (v->next_order == 0) { truelight@0: // fly around randomly truelight@0: int x = GET_TILE_X(v->dest_tile)*16; truelight@0: int y = GET_TILE_Y(v->dest_tile)*16; truelight@0: if (abs(x - v->x_pos) + abs(y - v->y_pos) >= 16) { truelight@0: v->direction = GetDirectionTowards(v, x, y); truelight@0: GetNewVehiclePos(v, &gp); truelight@0: SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); truelight@0: return; truelight@0: } truelight@0: if (++v->age < 6) { truelight@0: v->dest_tile = TILE_MASK(Random()); truelight@0: return; truelight@0: } truelight@0: v->next_order = 1; truelight@0: truelight@0: FOR_ALL_VEHICLES(u) { truelight@0: if (u->type == VEH_Road && IS_HUMAN_PLAYER(u->owner)) { truelight@0: v->dest_tile = u->index; truelight@0: v->age = 0; truelight@0: return; truelight@0: } truelight@0: } truelight@0: truelight@0: DeleteDisasterVeh(v); truelight@0: } else { truelight@0: // target a vehicle truelight@0: u = &_vehicles[v->dest_tile]; truelight@0: if (u->type != VEH_Road) { truelight@0: DeleteDisasterVeh(v); truelight@0: return; truelight@0: } truelight@0: truelight@0: dist = abs(v->x_pos - u->x_pos) + abs(v->y_pos - u->y_pos); truelight@0: truelight@0: if (dist < 16 && !(u->vehstatus&VS_HIDDEN) && u->breakdown_ctr==0) { truelight@0: u->breakdown_ctr = 3; truelight@0: u->breakdown_delay = 140; truelight@0: } truelight@0: truelight@0: v->direction = GetDirectionTowards(v, u->x_pos, u->y_pos); truelight@0: GetNewVehiclePos(v, &gp); truelight@0: truelight@0: z = v->z_pos; truelight@0: if (dist <= 16 && z > u->z_pos) z--; truelight@0: SetDisasterVehiclePos(v, gp.x, gp.y, z); truelight@0: truelight@0: if (z <= u->z_pos && (u->vehstatus&VS_HIDDEN)==0) { truelight@0: v->age++; truelight@0: if (u->u.road.crashed_ctr == 0) { truelight@0: u->u.road.crashed_ctr++; truelight@0: u->vehstatus |= VS_CRASHED; truelight@0: truelight@0: AddNewsItem(STR_B001_ROAD_VEHICLE_DESTROYED, truelight@0: NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0), truelight@0: u->index, truelight@0: 0); truelight@0: } truelight@0: } truelight@0: truelight@0: // destroy? truelight@0: if (v->age > 50) { truelight@0: CreateEffectVehicleRel(v, 0, 7, 8, EV_CRASHED_SMOKE); truelight@0: SndPlayVehicleFx(0x10, v); truelight@0: DeleteDisasterVeh(v); truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: static void DestructIndustry(Industry *i) truelight@0: { truelight@0: uint tile; truelight@0: byte index = i - _industries; truelight@0: truelight@0: for(tile=0; tile != TILES_X*TILES_Y; tile++) { truelight@0: if (IS_TILETYPE(tile, MP_INDUSTRY) && _map2[tile] == index) { truelight@0: _map_owner[tile] = 0; truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: // Airplane which destroys an oil refinery truelight@0: static void DisasterTick_2(Vehicle *v) truelight@0: { truelight@0: GetNewVehiclePosResult gp; truelight@0: truelight@0: v->tick_counter++; truelight@0: v->u.disaster.image_override = (v->next_order == 1 && v->tick_counter&4) ? 0xF4F : 0; truelight@0: truelight@0: GetNewVehiclePos(v, &gp); truelight@0: SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); truelight@0: truelight@0: if (gp.x < -160) { truelight@0: DeleteDisasterVeh(v); truelight@0: return; truelight@0: } truelight@0: truelight@0: if (v->next_order == 2) { truelight@0: if (!(v->tick_counter&3)) { truelight@0: Industry *i = DEREF_INDUSTRY(v->dest_tile); truelight@0: int x = GET_TILE_X(i->xy)*16; truelight@0: int y = GET_TILE_Y(i->xy)*16; truelight@0: uint32 r = Random(); truelight@0: truelight@0: CreateEffectVehicleAbove( truelight@0: x + (r & 0x3F), truelight@0: y + (r >> 6 & 0x3F), truelight@0: (r >> 12 & 0xF), truelight@0: EV_DEMOLISH); truelight@0: truelight@0: if (++v->age >= 55) truelight@0: v->next_order = 3; truelight@0: } truelight@0: } else if (v->next_order == 1) { truelight@0: if (++v->age == 112) { truelight@0: Industry *i; truelight@0: truelight@0: v->next_order = 2; truelight@0: v->age = 0; truelight@0: truelight@0: i = DEREF_INDUSTRY(v->dest_tile); truelight@0: DestructIndustry(i); truelight@0: truelight@0: SET_DPARAM16(0, i->town->index); truelight@0: AddNewsItem(STR_B002_OIL_REFINERY_EXPLOSION, NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy, 0); truelight@0: SndPlayTileFx(0x10, i->xy); truelight@0: } truelight@0: } else if (v->next_order == 0) { truelight@0: int x,y; truelight@0: uint tile; truelight@0: int ind; truelight@0: truelight@0: x = v->x_pos - 15*16; truelight@0: y = v->y_pos; truelight@0: truelight@0: if ( (uint)x > (TILES_X-1) * 16-1) truelight@0: return; truelight@0: truelight@0: tile = TILE_FROM_XY(x,y); truelight@0: if (!IS_TILETYPE(tile, MP_INDUSTRY)) truelight@0: return; truelight@0: truelight@0: v->dest_tile = ind = _map2[tile]; truelight@0: truelight@0: if (DEREF_INDUSTRY(ind)->type == IT_OIL_REFINERY) { truelight@0: v->next_order = 1; truelight@0: v->age = 0; truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: // Helicopter which destroys a factory truelight@0: static void DisasterTick_3(Vehicle *v) truelight@0: { truelight@0: GetNewVehiclePosResult gp; truelight@0: truelight@0: v->tick_counter++; truelight@0: v->u.disaster.image_override = (v->next_order == 1 && v->tick_counter&4) ? 0xF53 : 0; truelight@0: truelight@0: GetNewVehiclePos(v, &gp); truelight@0: SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); truelight@0: truelight@0: if (gp.x > TILES_X * 16 + 9*16 - 1) { truelight@0: DeleteDisasterVeh(v); truelight@0: return; truelight@0: } truelight@0: truelight@0: if (v->next_order == 2) { truelight@0: if (!(v->tick_counter&3)) { truelight@0: Industry *i = DEREF_INDUSTRY(v->dest_tile); truelight@0: int x = GET_TILE_X(i->xy)*16; truelight@0: int y = GET_TILE_Y(i->xy)*16; truelight@0: uint32 r = Random(); truelight@0: truelight@0: CreateEffectVehicleAbove( truelight@0: x + (r & 0x3F), truelight@0: y + (r >> 6 & 0x3F), truelight@0: (r >> 12 & 0xF), truelight@0: EV_DEMOLISH); truelight@0: truelight@0: if (++v->age >= 55) truelight@0: v->next_order = 3; truelight@0: } truelight@0: } else if (v->next_order == 1) { truelight@0: if (++v->age == 112) { truelight@0: Industry *i; truelight@0: truelight@0: v->next_order = 2; truelight@0: v->age = 0; truelight@0: truelight@0: i = DEREF_INDUSTRY(v->dest_tile); truelight@0: DestructIndustry(i); truelight@0: truelight@0: SET_DPARAM16(0, i->town->index); truelight@0: AddNewsItem(STR_B003_FACTORY_DESTROYED_IN_SUSPICIOUS, NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy, 0); truelight@0: SndPlayTileFx(0x10, i->xy); truelight@0: } truelight@0: } else if (v->next_order == 0) { truelight@0: int x,y; truelight@0: uint tile; truelight@0: int ind; truelight@0: truelight@0: x = v->x_pos - 15*16; truelight@0: y = v->y_pos; truelight@0: truelight@0: if ( (uint)x > (TILES_X-1) * 16-1) truelight@0: return; truelight@0: truelight@0: tile = TILE_FROM_XY(x,y); truelight@0: if (!IS_TILETYPE(tile, MP_INDUSTRY)) truelight@0: return; truelight@0: truelight@0: v->dest_tile = ind = _map2[tile]; truelight@0: truelight@0: if (DEREF_INDUSTRY(ind)->type == IT_FACTORY) { truelight@0: v->next_order = 1; truelight@0: v->age = 0; truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: // Helicopter rotor blades truelight@0: static void DisasterTick_3b(Vehicle *v) truelight@0: { truelight@0: if (++v->tick_counter & 1) truelight@0: return; truelight@0: truelight@0: if (++v->cur_image == 0xF40 + 1) truelight@0: v->cur_image = 0xF3E; truelight@0: truelight@0: VehiclePositionChanged(v); truelight@0: BeginVehicleMove(v); truelight@0: EndVehicleMove(v); truelight@0: } truelight@0: truelight@0: // Big UFO which lands on a piece of rail. truelight@0: // Will be shot down by a plane truelight@0: static void DisasterTick_4(Vehicle *v) truelight@0: { truelight@0: GetNewVehiclePosResult gp; truelight@0: byte z; truelight@0: Vehicle *u,*w; truelight@0: Town *t; truelight@0: uint tile,tile_org; truelight@0: truelight@0: v->tick_counter++; truelight@0: truelight@0: if (v->next_order == 1) { truelight@0: int x = GET_TILE_X(v->dest_tile)*16 + 8; truelight@0: int y = GET_TILE_Y(v->dest_tile)*16 + 8; truelight@0: if (abs(v->x_pos - x) + abs(v->y_pos - y) >= 8) { truelight@0: v->direction = GetDirectionTowards(v, x, y); truelight@0: truelight@0: GetNewVehiclePos(v, &gp); truelight@0: SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); truelight@0: return; truelight@0: } truelight@0: truelight@0: z = GetSlopeZ(v->x_pos, v->y_pos); truelight@0: if (z < v->z_pos) { truelight@0: SetDisasterVehiclePos(v, v->x_pos, v->y_pos, v->z_pos - 1); truelight@0: return; truelight@0: } truelight@0: truelight@0: v->next_order = 2; truelight@0: truelight@0: FOR_ALL_VEHICLES(u) { truelight@0: if (u->type == VEH_Train || u->type == VEH_Road) { truelight@0: if (abs(u->x_pos - v->x_pos) + abs(u->y_pos - v->y_pos) <= 12*16) { truelight@0: u->breakdown_ctr = 5; truelight@0: u->breakdown_delay = 0xF0; truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: t = ClosestTownFromTile(v->dest_tile, (uint)-1); truelight@0: SET_DPARAM16(0, t->index); truelight@0: AddNewsItem(STR_B004_UFO_LANDS_NEAR, truelight@0: NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ACCIDENT, 0), truelight@0: v->tile, truelight@0: 0); truelight@0: truelight@0: u = ForceAllocateSpecialVehicle(); truelight@0: if (u == NULL) { truelight@0: DeleteDisasterVeh(v); truelight@0: return; truelight@0: } truelight@0: truelight@0: InitializeDisasterVehicle(u, -6*16, v->y_pos, 135, 5, 11); truelight@0: u->u.disaster.unk2 = v->index; truelight@0: truelight@0: w = ForceAllocateSpecialVehicle(); truelight@0: if (w == NULL) truelight@0: return; truelight@0: truelight@0: u->next = w; truelight@0: InitializeDisasterVehicle(w, -6*16, v->y_pos, 0, 5, 12); truelight@0: w->vehstatus |= VS_DISASTER; truelight@0: } else if (v->next_order < 1) { truelight@0: truelight@0: int x = GET_TILE_X(v->dest_tile)*16; truelight@0: int y = GET_TILE_Y(v->dest_tile)*16; truelight@0: if (abs(x - v->x_pos) + abs(y - v->y_pos) >= 16) { truelight@0: v->direction = GetDirectionTowards(v, x, y); truelight@0: GetNewVehiclePos(v, &gp); truelight@0: SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); truelight@0: return; truelight@0: } truelight@0: truelight@0: if (++v->age < 6) { truelight@0: v->dest_tile = TILE_MASK(Random()); truelight@0: return; truelight@0: } truelight@0: v->next_order = 1; truelight@0: truelight@0: tile_org = tile = TILE_MASK(Random()); truelight@0: do { truelight@0: if (IS_TILETYPE(tile, MP_RAILWAY) && truelight@0: (_map5[tile]&~3)!=0xC0 && IS_HUMAN_PLAYER(_map_owner[tile])) truelight@0: break; truelight@0: tile = TILE_MASK(tile+1); truelight@0: } while (tile != tile_org); truelight@0: v->dest_tile = tile; truelight@0: v->age = 0; truelight@0: } else truelight@0: return; truelight@0: } truelight@0: truelight@0: // The plane which will shoot down the UFO truelight@0: static void DisasterTick_4b(Vehicle *v) truelight@0: { truelight@0: GetNewVehiclePosResult gp; truelight@0: Vehicle *u; truelight@0: int i; truelight@0: truelight@0: v->tick_counter++; truelight@0: truelight@0: GetNewVehiclePos(v, &gp); truelight@0: SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); truelight@0: truelight@0: if (gp.x > TILES_X * 16 + 9*16 - 1) { truelight@0: DeleteDisasterVeh(v); truelight@0: return; truelight@0: } truelight@0: truelight@0: if (v->next_order == 0) { truelight@0: u = &_vehicles[v->u.disaster.unk2]; truelight@0: if (abs(v->x_pos - u->x_pos) > 16) truelight@0: return; truelight@0: v->next_order = 1; truelight@0: truelight@0: CreateEffectVehicleRel(u, 0, 7, 8, EV_CRASHED_SMOKE); truelight@0: SndPlayVehicleFx(0x10, u); truelight@0: truelight@0: DeleteDisasterVeh(u); truelight@0: truelight@0: for(i=0; i!=80; i++) { truelight@0: uint32 r = Random(); truelight@0: CreateEffectVehicleAbove( truelight@0: v->x_pos-32+(r&0x3F), truelight@0: v->y_pos-32+(r>>5&0x3F), truelight@0: 0, truelight@0: EV_DEMOLISH); truelight@0: } truelight@0: truelight@0: BEGIN_TILE_LOOP(tile,6,6,v->tile - TILE_XY(3,3)) truelight@0: tile = TILE_MASK(tile); truelight@0: DisasterClearSquare(tile); truelight@0: END_TILE_LOOP(tile,6,6,v->tile - TILE_XY(3,3)) truelight@0: } truelight@0: } truelight@0: truelight@0: // Submarine handler truelight@0: static void DisasterTick_5_and_6(Vehicle *v) truelight@0: { truelight@0: uint32 r; truelight@0: GetNewVehiclePosResult gp; truelight@0: uint tile; truelight@0: truelight@0: v->tick_counter++; truelight@0: truelight@0: if (++v->age > 8880) { truelight@0: VehiclePositionChanged(v); truelight@0: BeginVehicleMove(v); truelight@0: EndVehicleMove(v); truelight@0: DeleteVehicle(v); truelight@0: return; truelight@0: } truelight@0: truelight@0: if (!(v->tick_counter&1)) truelight@0: return; truelight@0: truelight@0: tile = v->tile + _tileoffs_by_dir[v->direction >> 1]; truelight@0: if (IsValidTile(tile) && truelight@0: (r=GetTileTrackStatus(tile,4),(byte)(r+(r >> 8)) == 0x3F) && truelight@0: !CHANCE16(1,90)) { truelight@0: GetNewVehiclePos(v, &gp); truelight@0: SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); truelight@0: return; truelight@0: } truelight@0: truelight@0: v->direction = (v->direction + ((Random()&1)?2:-2))&7; truelight@0: } truelight@0: truelight@0: truelight@0: static void DisasterTick_NULL(Vehicle *v) {} truelight@0: typedef void DisasterVehicleTickProc(Vehicle *v); truelight@0: truelight@0: static DisasterVehicleTickProc * const _disastervehicle_tick_procs[] = { truelight@0: DisasterTick_Zeppeliner,DisasterTick_NULL, truelight@0: DisasterTick_UFO,DisasterTick_NULL, truelight@0: DisasterTick_2,DisasterTick_NULL, truelight@0: DisasterTick_3,DisasterTick_NULL,DisasterTick_3b, truelight@0: DisasterTick_4,DisasterTick_NULL, truelight@0: DisasterTick_4b,DisasterTick_NULL, truelight@0: DisasterTick_5_and_6, truelight@0: DisasterTick_5_and_6, truelight@0: }; truelight@0: truelight@0: truelight@0: void DisasterVehicle_Tick(Vehicle *v) truelight@0: { truelight@0: _disastervehicle_tick_procs[v->subtype](v); truelight@0: } truelight@0: truelight@0: void HandleClickOnDisasterVeh(Vehicle *v) truelight@0: { truelight@0: // not used truelight@0: } truelight@0: truelight@0: void OnNewDay_DisasterVehicle(Vehicle *v) truelight@0: { truelight@0: // not used truelight@0: } truelight@0: truelight@0: typedef void DisasterInitProc(); truelight@0: truelight@0: // Zeppeliner which crashes on a small airport truelight@0: static void Disaster0_Init() truelight@0: { truelight@0: Vehicle *v = ForceAllocateSpecialVehicle(), *u; truelight@0: Station *st; truelight@0: int x; truelight@0: truelight@0: if (v == NULL) truelight@0: return; truelight@0: truelight@0: for(st=_stations;;) { truelight@0: if (st->xy && st->airport_tile != 0 && truelight@0: st->airport_type <= 1 && truelight@0: IS_HUMAN_PLAYER(st->owner)) { truelight@0: x = (GET_TILE_X(st->xy) + 2) * 16; truelight@0: break; truelight@0: } truelight@0: truelight@0: if (++st == endof(_stations)) { truelight@0: x = (GET_TILE_X(Random())) * 16 + 8; truelight@0: break; truelight@0: } truelight@0: } truelight@0: truelight@0: InitializeDisasterVehicle(v, x, 0, 135, 3, 0); truelight@0: truelight@0: // Allocate shadow too? truelight@0: u = ForceAllocateSpecialVehicle(); truelight@0: if (u != NULL) { truelight@0: v->next = u; truelight@0: InitializeDisasterVehicle(u,x,0,0,3,1); truelight@0: u->vehstatus |= VS_DISASTER; truelight@0: } truelight@0: } truelight@0: truelight@0: static void Disaster1_Init() truelight@0: { truelight@0: Vehicle *v = ForceAllocateSpecialVehicle(), *u; truelight@0: int x; truelight@0: truelight@0: if (v == NULL) truelight@0: return; truelight@0: truelight@0: x = (GET_TILE_X(Random())) * 16 + 8; truelight@0: truelight@0: InitializeDisasterVehicle(v, x, 0, 135, 3, 2); truelight@0: v->dest_tile = TILE_XY(TILES_X/2,TILES_Y/2); truelight@0: v->age = 0; truelight@0: truelight@0: // Allocate shadow too? truelight@0: u = ForceAllocateSpecialVehicle(); truelight@0: if (u != NULL) { truelight@0: v->next = u; truelight@0: InitializeDisasterVehicle(u,x,0,0,3,3); truelight@0: u->vehstatus |= VS_DISASTER; truelight@0: } truelight@0: } truelight@0: truelight@0: static void Disaster2_Init() truelight@0: { truelight@0: Industry *i, *found; truelight@0: Vehicle *v,*u; truelight@0: int x,y; truelight@0: truelight@0: for(found=NULL,i=_industries; i != endof(_industries); i++) { truelight@0: if (i->xy != 0 && truelight@0: i->type == IT_OIL_REFINERY && truelight@0: (found==NULL || CHANCE16(1,2))) { truelight@0: found = i; truelight@0: } truelight@0: } truelight@0: truelight@0: if (found == NULL) truelight@0: return; truelight@0: truelight@0: v = ForceAllocateSpecialVehicle(); truelight@0: if (v == NULL) truelight@0: return; truelight@0: truelight@0: x = (TILES_X+9) * 16 - 1; truelight@0: y = GET_TILE_Y(found->xy)*16 + 37; truelight@0: truelight@0: InitializeDisasterVehicle(v,x,y, 135,1,4); truelight@0: truelight@0: u = ForceAllocateSpecialVehicle(); truelight@0: if (u != NULL) { truelight@0: v->next = u; truelight@0: InitializeDisasterVehicle(u,x,y,0,3,5); truelight@0: u->vehstatus |= VS_DISASTER; truelight@0: } truelight@0: } truelight@0: truelight@0: static void Disaster3_Init() truelight@0: { truelight@0: Industry *i, *found; truelight@0: Vehicle *v,*u,*w; truelight@0: int x,y; truelight@0: truelight@0: for(found=NULL,i=_industries; i != endof(_industries); i++) { truelight@0: if (i->xy != 0 && truelight@0: i->type == IT_FACTORY && truelight@0: (found==NULL || CHANCE16(1,2))) { truelight@0: found = i; truelight@0: } truelight@0: } truelight@0: truelight@0: if (found == NULL) truelight@0: return; truelight@0: truelight@0: v = ForceAllocateSpecialVehicle(); truelight@0: if (v == NULL) truelight@0: return; truelight@0: truelight@0: x = -16 * 16; truelight@0: y = GET_TILE_Y(found->xy)*16 + 37; truelight@0: truelight@0: InitializeDisasterVehicle(v,x,y, 135,5,6); truelight@0: truelight@0: u = ForceAllocateSpecialVehicle(); truelight@0: if (u != NULL) { truelight@0: v->next = u; truelight@0: InitializeDisasterVehicle(u,x,y,0,5,7); truelight@0: u->vehstatus |= VS_DISASTER; truelight@0: truelight@0: w = ForceAllocateSpecialVehicle(); truelight@0: if (w != NULL) { truelight@0: u->next = w; truelight@0: InitializeDisasterVehicle(w,x,y,140,5,8); truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: static void Disaster4_Init() truelight@0: { truelight@0: Vehicle *v = ForceAllocateSpecialVehicle(), *u; truelight@0: int x,y; truelight@0: truelight@0: if (v == NULL) truelight@0: return; truelight@0: truelight@0: x = (GET_TILE_X(Random())) * 16 + 8; truelight@0: truelight@0: y = (TILES_X-1)*16-1; truelight@0: InitializeDisasterVehicle(v, x, y, 135, 7, 9); truelight@0: v->dest_tile = TILE_XY(TILES_X/2,TILES_Y/2); truelight@0: v->age = 0; truelight@0: truelight@0: // Allocate shadow too? truelight@0: u = ForceAllocateSpecialVehicle(); truelight@0: if (u != NULL) { truelight@0: v->next = u; truelight@0: InitializeDisasterVehicle(u,x,y,0,7,10); truelight@0: u->vehstatus |= VS_DISASTER; truelight@0: } truelight@0: } truelight@0: truelight@0: // Submarine type 1 truelight@0: static void Disaster5_Init() truelight@0: { truelight@0: Vehicle *v = ForceAllocateSpecialVehicle(); truelight@0: int x,y; truelight@0: byte dir; truelight@0: uint32 r; truelight@0: truelight@0: if (v == NULL) truelight@0: return; truelight@0: truelight@0: r = Random(); truelight@0: x = (GET_TILE_X(r)) * 16 + 8; truelight@0: truelight@0: y = 8; truelight@0: dir = 3; truelight@0: if (r & 0x80000000) { y = (TILES_X-1) * 16 - 8 - 1; dir = 7; } truelight@0: InitializeDisasterVehicle(v, x, y, 0, dir,13); truelight@0: v->age = 0; truelight@0: } truelight@0: truelight@0: // Submarine type 2 truelight@0: static void Disaster6_Init() truelight@0: { truelight@0: Vehicle *v = ForceAllocateSpecialVehicle(); truelight@0: int x,y; truelight@0: byte dir; truelight@0: uint32 r; truelight@0: truelight@0: if (v == NULL) truelight@0: return; truelight@0: truelight@0: r = Random(); truelight@0: x = (GET_TILE_X(r)) * 16 + 8; truelight@0: truelight@0: y = 8; truelight@0: dir = 3; truelight@0: if (r & 0x80000000) { y = (TILES_X-1) * 16 - 8 - 1; dir = 7; } truelight@0: InitializeDisasterVehicle(v, x, y, 0, dir,14); truelight@0: v->age = 0; truelight@0: } truelight@0: truelight@0: static void Disaster7_Init() truelight@0: { truelight@0: Industry *i; truelight@0: int maxloop = 15; truelight@0: int index = Random() & 0xF; truelight@0: truelight@0: do { truelight@0: for(i=_industries; i != endof(_industries); i++) { truelight@0: if (i->xy != 0 && i->type == IT_COAL_MINE && --index < 0) { truelight@0: truelight@0: SET_DPARAM16(0, i->town->index); truelight@0: AddNewsItem(STR_B005_COAL_MINE_SUBSIDENCE_LEAVES, truelight@0: NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy + TILE_XY(1,1), 0); truelight@0: truelight@0: { truelight@0: uint tile = i->xy; truelight@0: int step = _tileoffs_by_dir[Random() & 3]; truelight@0: int count = 30; truelight@0: do { truelight@0: DisasterClearSquare(tile); truelight@0: tile = TILE_MASK(tile + step); truelight@0: } while (--count); truelight@0: } truelight@0: return; truelight@0: } truelight@0: } truelight@0: } while (--maxloop != 0); truelight@0: } truelight@0: truelight@0: static DisasterInitProc * const _disaster_initprocs[] = { truelight@0: Disaster0_Init, truelight@0: Disaster1_Init, truelight@0: Disaster2_Init, truelight@0: Disaster3_Init, truelight@0: Disaster4_Init, truelight@0: Disaster5_Init, truelight@0: Disaster6_Init, truelight@0: Disaster7_Init, truelight@0: }; truelight@0: truelight@0: typedef struct { truelight@0: byte min,max; truelight@0: } DisasterYears; truelight@0: truelight@0: #define MK(a,b) {a-20,b-20} truelight@0: static const DisasterYears _dis_years[8] = { truelight@0: MK(30,55), truelight@0: MK(40,70), truelight@0: MK(60,90), truelight@0: MK(70,100), truelight@0: MK(100,200), truelight@0: MK(40,65), truelight@0: MK(75,110), truelight@0: MK(50,85), truelight@0: }; truelight@0: truelight@0: truelight@0: void DoDisaster() truelight@0: { truelight@0: byte buf[8]; truelight@0: byte year = _cur_year; truelight@0: int i,j; truelight@0: truelight@0: for(i=j=0; i!=lengthof(_dis_years); i++) { truelight@0: if (year >= _dis_years[i].min && truelight@0: year < _dis_years[i].max) truelight@0: buf[j++] = i; truelight@0: } truelight@0: truelight@0: if (j == 0) truelight@0: return; truelight@0: truelight@0: _disaster_initprocs[buf[(uint16)Random() * j >> 16]](); truelight@0: } truelight@0: truelight@0: truelight@0: static void ResetDisasterDelay() truelight@0: { truelight@0: _disaster_delay = (int)(Random() & 0x1FF) + 730; truelight@0: } truelight@0: truelight@0: void DisasterDailyLoop() truelight@0: { truelight@0: if (--_disaster_delay != 0) truelight@0: return; truelight@0: truelight@0: ResetDisasterDelay(); truelight@0: truelight@0: if (_opt.diff.disasters != 0) truelight@0: DoDisaster(); truelight@0: } truelight@0: truelight@0: void StartupDisasters() { truelight@0: ResetDisasterDelay(); truelight@0: } truelight@0: