diff --git a/src/ride/vehicle.c b/src/ride/vehicle.c index c4db2e5857..69216f6ead 100644 --- a/src/ride/vehicle.c +++ b/src/ride/vehicle.c @@ -71,7 +71,7 @@ static void vehicle_update_collision_setup(rct_vehicle* vehicle); static int vehicle_update_motion_bumper_car(rct_vehicle* vehicle); static bool vehicle_update_bumper_car_collision(rct_vehicle *vehicle, sint16 x, sint16 y, uint16 *spriteId); static void sub_6D63D4(rct_vehicle *vehicle); -static bool sub_6DD078(rct_vehicle *vehicle, uint16* otherVehicleIndex); +static bool vehicle_update_motion_collision_detection(rct_vehicle *vehicle, sint16 x, sint16 y, sint16 z, uint16 *otherVehicleIndex); static void vehicle_update_sound(rct_vehicle *vehicle); static int vehicle_update_scream_sound(rct_vehicle *vehicle); @@ -3175,8 +3175,7 @@ static void vehicle_update_travelling_boat(rct_vehicle* vehicle) static void loc_6DA9F9(rct_vehicle *vehicle, int x, int y, int bx, int dx) { vehicle->remaining_distance = 0; - // z = vehicle->z; - if (!sub_6DD078(vehicle, NULL)) { + if (!vehicle_update_motion_collision_detection(vehicle, x, y, vehicle->z, NULL)) { vehicle->track_x = bx; vehicle->track_y = dx; @@ -3315,7 +3314,7 @@ static void vehicle_update_motion_boat_hire(rct_vehicle *vehicle) x = vehicle->x + RCT2_ADDRESS(0x009A36C4, sint16)[edi * 4]; y = vehicle->y + RCT2_ADDRESS(0x009A36C6, sint16)[edi * 4]; z = vehicle->z; - if (sub_6DD078(vehicle, NULL)) { + if (vehicle_update_motion_collision_detection(vehicle, x, y, z, NULL)) { goto loc_6DAA79; } @@ -3376,8 +3375,7 @@ static void vehicle_update_motion_boat_hire(rct_vehicle *vehicle) // loc_6DA9D1: vehicle->remaining_distance = 0; - // z = vehicle->z; - if (!sub_6DD078(vehicle, NULL)) { + if (!vehicle_update_motion_collision_detection(vehicle, x, y, vehicle->z, NULL)) { unk_F64E20->x = x; unk_F64E20->y = y; } @@ -6359,24 +6357,164 @@ static void sub_6DB807(rct_vehicle *vehicle) sprite_move(x, y, z, (rct_sprite*)vehicle); } -/** Collision? - * +/** + * Collision Detection * rct2: 0x006DD078 * @param vehicle (esi) + * @param x (ax) + * @param y (cx) + * @param z (dx) * @param otherVehicleIndex (bp) */ -static bool sub_6DD078(rct_vehicle *vehicle, uint16* otherVehicleIndex) -{ - registers regs = { 0 }; - regs.esi = (int)vehicle; - if (otherVehicleIndex != NULL) { - regs.bp = *otherVehicleIndex; +static bool vehicle_update_motion_collision_detection( + rct_vehicle *vehicle, sint16 x, sint16 y, sint16 z, uint16* otherVehicleIndex +) { + if (vehicle->update_flags & VEHICLE_UPDATE_FLAG_1) return false; + + rct_ride_type_vehicle *vehicleEntry = vehicle_get_vehicle_entry(vehicle); + + if (!(vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_6)){ + vehicle->var_C4 = 0; + rct_vehicle* collideVehicle = GET_VEHICLE(*otherVehicleIndex); + + if (vehicle == collideVehicle) return false; + + sint32 x_diff = abs(x - collideVehicle->x); + if (x_diff > 0x7FFF) return false; + + sint32 y_diff = abs(y - collideVehicle->y); + if (y_diff > 0x7FFF) return false; + + if (x_diff + y_diff > 0xFFFF) return false; + + sint32 z_diff = abs(z - collideVehicle->z); + if (x_diff + y_diff + z_diff > 0xFFFF) return false; + + uint16 ecx = min(vehicle->var_44 + collideVehicle->var_44, 560); + ecx = ((ecx >> 1) * 30) >> 8; + + if (x_diff + y_diff + z_diff >= ecx) return false; + + uint8 direction = (vehicle->sprite_direction - collideVehicle->sprite_direction + 7) & 0x1F; + if (direction >= 0xF) return false; + + return true; } - bool result = RCT2_CALLFUNC_Y(0x006DD078, ®s) & 0x100; - if (otherVehicleIndex != NULL) { - *otherVehicleIndex = regs.bp; + + uint16 eax = ((x / 32) << 8) + (y / 32); + // TODO change to using a better technique + uint32* ebp = RCT2_ADDRESS(0x009A37C4, uint32); + bool mayCollide = false; + uint16 collideId = 0xFFFF; + rct_vehicle* collideVehicle = NULL; + for(; ebp <= RCT2_ADDRESS(0x009A37E4, uint32); ebp++){ + collideId = RCT2_ADDRESS(0x00F1EF60, uint16)[eax]; + for(; collideId != 0xFFFF; collideId = collideVehicle->next_in_quadrant){ + collideVehicle = GET_VEHICLE(collideId); + if (collideVehicle == vehicle) continue; + + if (collideVehicle->sprite_identifier != SPRITE_IDENTIFIER_VEHICLE) continue; + + sint32 z_diff = abs(collideVehicle->z - z); + + if (z_diff > 16) continue; + + rct_ride_type_vehicle* collideType = vehicle_get_vehicle_entry(collideVehicle); + + if (!(collideType->flags_b & VEHICLE_ENTRY_FLAG_B_6)) continue; + + sint32 x_diff = abs(collideVehicle->x - x); + if (x_diff > 0x7FFF) continue; + + sint32 y_diff = abs(collideVehicle->y - y); + if (y_diff > 0x7FFF) continue; + + if (x_diff + y_diff > 0xFFFF) continue; + + uint8 cl = min(vehicle->var_CD, collideVehicle->var_CD); + uint8 ch = max(vehicle->var_CD, collideVehicle->var_CD); + if (cl != ch){ + if (cl == 5 && ch == 6) continue; + } + + uint32 ecx = vehicle->var_44 + collideVehicle->var_44; + ecx = ((ecx >> 1) * 30) >> 8; + + if (x + y >= ecx) continue; + + if (!(collideType->flags_b & VEHICLE_ENTRY_FLAG_B_14)){ + mayCollide = true; + break; + } + + uint8 direction = (vehicle->sprite_direction - collideVehicle->sprite_direction - 6) & 0x1F; + + if (direction < 0x14) continue; + + sint16 next_x_diff = abs(x + RCT2_ADDRESS(0x009A3B04, sint16)[vehicle->sprite_direction*2]-collideVehicle->x); + sint16 next_y_diff = abs(y + RCT2_ADDRESS(0x009A3B06, sint16)[vehicle->sprite_direction*2]-collideVehicle->y); + + if (next_x_diff + next_y_diff < x_diff + y_diff){ + mayCollide = true; + break; + } + + } + if (mayCollide == true) { + break; + } + + // TODO change this + eax += *ebp; } - return result; + + if (mayCollide == false) { + vehicle->var_C4 = 0; + return false; + } + + vehicle->var_C4++; + if (vehicle->var_C4 < 200) { + vehicle->update_flags |= VEHICLE_UPDATE_FLAG_6; + *otherVehicleIndex = collideId; + return true; + } + + // TODO Is it possible for collideVehicle to be NULL? + + if (vehicle->status == VEHICLE_STATUS_MOVING_TO_END_OF_STATION){ + if (vehicle->sprite_direction == 0) { + if (vehicle->x <= collideVehicle->x) { + return false; + } + } + else if (vehicle->sprite_direction == 8) { + if (vehicle->x >= collideVehicle->x) { + return false; + } + } + else if (vehicle->sprite_direction == 16) { + if (vehicle->y >= collideVehicle->y) { + return false; + } + } + else if (vehicle->sprite_direction == 24) { + if (vehicle->y <= collideVehicle->y) { + return false; + } + } + } + + if (collideVehicle->status == VEHICLE_STATUS_TRAVELLING_BOAT && + vehicle->status != VEHICLE_STATUS_ARRIVING && + vehicle->status != VEHICLE_STATUS_TRAVELLING + ) { + return false; + } + + vehicle->update_flags |= VEHICLE_UPDATE_FLAG_6; + *otherVehicleIndex = collideId; + return true; } /** @@ -6799,7 +6937,7 @@ loc_6DB8A5: if (vehicle == RCT2_GLOBAL(0x00F64E00, rct_vehicle*)) { if (RCT2_GLOBAL(0x00F64E08, sint32) >= 0) { regs.bp = vehicle->prev_vehicle_on_ride; - if (sub_6DD078(vehicle, (uint16 *)®s.bp)) { + if (vehicle_update_motion_collision_detection(vehicle, x, y, z, (uint16 *)®s.bp)) { goto loc_6DB967; } } @@ -7078,7 +7216,7 @@ loc_6DBD42: if (vehicle == RCT2_GLOBAL(0x00F64E00, rct_vehicle*)) { if (RCT2_GLOBAL(0x00F64E08, sint32) < 0) { regs.bp = vehicle->next_vehicle_on_ride; - if (sub_6DD078(vehicle, (uint16 *)®s.bp)) { + if (vehicle_update_motion_collision_detection(vehicle, x, y, z, (uint16*)®s.bp)) { goto loc_6DBE7F; } } @@ -7728,7 +7866,7 @@ loc_6DC8A1: if (vehicle == RCT2_GLOBAL(0x00F64E00, rct_vehicle*)) { if (RCT2_GLOBAL(0x00F64E08, sint32) >= 0) { regs.bp = vehicle->var_44; - sub_6DD078(vehicle, (uint16 *)®s.bp); + vehicle_update_motion_collision_detection(vehicle, x, y, z, (uint16*)®s.bp); } } goto loc_6DC99A; @@ -7868,7 +8006,7 @@ loc_6DCC2C: if (vehicle == RCT2_GLOBAL(0x00F64E00, rct_vehicle*)) { if (RCT2_GLOBAL(0x00F64E08, sint32) >= 0) { regs.bp = vehicle->var_44; - if (sub_6DD078(vehicle, (uint16 *)®s.bp)) { + if (vehicle_update_motion_collision_detection(vehicle, x, y, z, (uint16*)®s.bp)) { goto loc_6DCD6B; } }