diff --git a/src/addresses.h b/src/addresses.h index 224a5966f4..f18fc89455 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -362,6 +362,11 @@ #define RCT2_ADDRESS_SPRITES_START_MISC 0x013573C2 #define RCT2_ADDRESS_SPRITES_START_LITTER 0x013573C4 +#define RCT2_ADDRESS_SPRITES_COUNT_VEHICLE 0x013573CA +#define RCT2_ADDRESS_SPRITES_COUNT_PEEP 0x013573CC +#define RCT2_ADDRESS_SPRITES_COUNT_MISC 0x013573CE +#define RCT2_ADDRESS_SPRITES_COUNT_LITTER 0x013573D0 + #define RCT2_ADDRESS_PARK_NAME 0x013573D4 #define RCT2_ADDRESS_PARK_NAME_ARGS 0x013573D8 #define RCT2_ADDRESS_INITIAL_CASH 0x013573DC diff --git a/src/localisation/localisation.c b/src/localisation/localisation.c index 2a950495bf..db22c239fd 100644 --- a/src/localisation/localisation.c +++ b/src/localisation/localisation.c @@ -664,6 +664,24 @@ void format_string_raw(char *dest, char *src, void *args) format_string_part_from_raw(&dest, src, (char**)&args); } +/** + * Writes a formatted string to a buffer and converts it to upper case. + * rct2: 0x006C2538 + * dest (edi) + * format (ax) + * args (ecx) + */ +void format_string_to_upper(char *dest, rct_string_id format, void *args) +{ + format_string(dest, format, args); + + char *ch = dest; + while (*ch != 0) { + *ch = toupper(*ch); + ch++; + } +} + /** * rct2: 0x006E37F7 * error (eax) diff --git a/src/localisation/localisation.h b/src/localisation/localisation.h index c7bee7a75c..9d7a8e7f42 100644 --- a/src/localisation/localisation.h +++ b/src/localisation/localisation.h @@ -28,6 +28,7 @@ void format_string(char *dest, rct_string_id format, void *args); void format_string_raw(char *dest, char *src, void *args); +void format_string_to_upper(char *dest, rct_string_id format, void *args); void generate_string_file(); void error_string_quit(int error, rct_string_id format); int get_string_length(char* buffer); diff --git a/src/peep/peep.c b/src/peep/peep.c index 64eb9fc49e..745f851825 100644 --- a/src/peep/peep.c +++ b/src/peep/peep.c @@ -344,10 +344,9 @@ int peep_update_action(sint16* x, sint16* y, sint16* xy_distance, rct_peep* peep peep->var_45 |= (1 << 2); // Create sick at location - RCT2_CALLPROC_X(0x67375D, peep->x, peep->sprite_direction, peep->y, peep->z, 0, 0, peep->sprite_index & 1); - - int sound_id = (scenario_rand() & 3) + 24; + litter_create(peep->x, peep->y, peep->z, peep->sprite_direction, peep->sprite_index & 1); + int sound_id = SOUND_COUGH_1 + (scenario_rand() & 3); sound_play_panned(sound_id, 0x8001, peep->x, peep->y, peep->z); invalidate_sprite((rct_sprite*)peep); @@ -3485,7 +3484,7 @@ static void peep_update_using_bin(rct_peep* peep){ x = peep->x + (scenario_rand() & 7) - 3; y = peep->y + (scenario_rand() & 7) - 3; - RCT2_CALLPROC_X(0x67375D, x, scenario_rand() & 3, y, peep->z, 0, 0, bp); + litter_create(x, y, peep->z, scenario_rand() & 3, bp); peep->item_standard_flags &= ~(1 << cur_container); peep->var_45 |= 8; @@ -3516,7 +3515,7 @@ static void peep_update_using_bin(rct_peep* peep){ x = peep->x + (scenario_rand() & 7) - 3; y = peep->y + (scenario_rand() & 7) - 3; - RCT2_CALLPROC_X(0x67375D, x, scenario_rand() & 3, y, peep->z, 0, 0, bp); + litter_create(x, y, peep->z, scenario_rand() & 3, bp); peep->item_extra_flags &= ~(1 << cur_container); peep->var_45 |= 8; @@ -4021,7 +4020,7 @@ static void peep_update_walking(rct_peep* peep){ int y = peep->y + (scenario_rand() & 0x7) - 3; int direction = (scenario_rand() & 0x3); - RCT2_CALLPROC_X(0x67375D, x, direction, y, peep->z, 0, 0, ebp); + litter_create(x, y, peep->z, direction, ebp); } } } @@ -4053,7 +4052,7 @@ static void peep_update_walking(rct_peep* peep){ int y = peep->y + (scenario_rand() & 0x7) - 3; int direction = (scenario_rand() & 0x3); - RCT2_CALLPROC_X(0x67375D, x, direction, y, peep->z, 0, 0, bp); + litter_create(x, y, peep->z, direction, bp); } } diff --git a/src/scenario.h b/src/scenario.h index 9f5aa3f5a8..7fc1878d1a 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -134,9 +134,10 @@ typedef struct { uint16 sprites_start_litter; uint8 pad_013573C6[2]; uint16 word_013573C8; - uint8 pad_013573CA[4]; - uint16 word_013573CE; - uint16 word_013573D0; + uint16 sprites_count_vehicle; + uint16 sprites_count_peep; + uint16 sprites_count_misc; + uint16 sprites_count_litter; uint8 pad_013573D2[2]; rct_string_id park_name; uint8 pad_013573D6[2]; diff --git a/src/windows/ride_list.c b/src/windows/ride_list.c index c70fb45ac0..704946e326 100644 --- a/src/windows/ride_list.c +++ b/src/windows/ride_list.c @@ -615,6 +615,7 @@ static void window_ride_list_refresh_list(rct_window *w) { int i, countA, countB; rct_ride *ride, *otherRide; + char *bufferA, *bufferB; countA = countB = 0; FOR_ALL_RIDES(i, ride) { @@ -644,13 +645,13 @@ static void window_ride_list_refresh_list(rct_window *w) int current_list_position = list_index; switch (w->list_information_type) { case INFORMATION_TYPE_STATUS: - RCT2_GLOBAL(0x013CE952, uint32) = ride->name_arguments; - RCT2_CALLPROC_X(0x006C2538, ride->name, 0, 0x013CE952, 0, 0, RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, 0); + bufferA = (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER; + bufferB = (char*)0x0141EF68; + format_string_to_upper(bufferA, ride->name, &ride->name_arguments); while (--current_list_position >= 0) { otherRide = &g_ride_list[w->list_item_positions[current_list_position]]; - RCT2_GLOBAL(0x013CE952, uint32) = otherRide->name_arguments; - RCT2_CALLPROC_X(0x006C2538, otherRide->name, 0, 0x013CE952, 0, 0, 0x0141EF68, 0); - if (strcmp((char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68) >= 0) + format_string_to_upper(bufferB, otherRide->name, &otherRide->name_arguments); + if (strcmp(bufferA, bufferB) >= 0) break; window_bubble_list_item(w, current_list_position); diff --git a/src/world/map.c b/src/world/map.c index 602be3f4ee..bcbd88c07a 100644 --- a/src/world/map.c +++ b/src/world/map.c @@ -3095,3 +3095,13 @@ int map_get_highest_z(int tileX, int tileY) z = max(z, (mapElement->properties.surface.terrain & 0x1F) * 16); return z; } + +bool map_element_is_underground(rct_map_element *mapElement) +{ + do { + mapElement++; + if (map_element_is_last_for_tile(mapElement - 1)) + return false; + } while (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SURFACE); + return true; +} diff --git a/src/world/map.h b/src/world/map.h index 0c2882bb0c..46dcc6fa71 100644 --- a/src/world/map.h +++ b/src/world/map.h @@ -334,4 +334,6 @@ void sub_6A7594(); int map_element_get_banner_index(rct_map_element *mapElement); void map_element_remove_banner_entry(rct_map_element *mapElement); +bool map_element_is_underground(rct_map_element *mapElement); + #endif diff --git a/src/world/park.c b/src/world/park.c index b732b8f895..7b52393d88 100644 --- a/src/world/park.c +++ b/src/world/park.c @@ -267,8 +267,8 @@ int calculate_park_rating() for (sprite_idx = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_LITTER, uint16); sprite_idx != SPRITE_INDEX_NULL; sprite_idx = litter->next) { litter = &(g_sprite_list[sprite_idx].litter); - // Guessing this eliminates recently dropped litter - if (litter->var_24 - RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) >= 7680) + // Ignore recently dropped litter + if (litter->creationTick - RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) >= 7680) num_litter++; } result -= 600 - (4 * (150 - min(150, num_litter))); diff --git a/src/world/sprite.c b/src/world/sprite.c index ede41f10d8..1127ec59da 100644 --- a/src/world/sprite.c +++ b/src/world/sprite.c @@ -901,4 +901,78 @@ void sprite_move(sint16 x, sint16 y, sint16 z, rct_sprite* sprite){ void sprite_remove(rct_sprite *sprite) { RCT2_CALLPROC_X(0x0069EDB6, 0, 0, 0, 0, (int)sprite, 0, 0); +} + +static bool litter_can_be_at(int x, int y, int z) +{ + rct_map_element *mapElement; + + if (!map_is_location_owned(x & 0xFFE0, y & 0xFFE0, z)) + return false; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH) + continue; + + int pathZ = mapElement->base_height * 8; + if (pathZ < z || pathZ >= z + 32) + continue; + + if (map_element_is_underground(mapElement)) + return false; + + return true; + } while (!map_element_is_last_for_tile(mapElement++)); + return false; +} + +/** + * + * rct2: 0x0067375D + */ +void litter_create(int x, int y, int z, int direction, int type) +{ + rct_litter *litter, *newestLitter; + uint16 spriteIndex, nextSpriteIndex; + uint32 newestLitterCreationTick; + + x += TileDirectionDelta[direction].x / 8; + y += TileDirectionDelta[direction].y / 8; + + if (!litter_can_be_at(x, y, z)) + return; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_COUNT_LITTER, uint16) >= 500) { + newestLitter = NULL; + newestLitterCreationTick = 0; + for (spriteIndex = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_LITTER, uint16); spriteIndex != SPRITE_INDEX_NULL; spriteIndex = nextSpriteIndex) { + litter = &(g_sprite_list[spriteIndex].litter); + nextSpriteIndex = litter->next; + if (newestLitterCreationTick <= litter->creationTick) { + newestLitterCreationTick = litter->creationTick; + newestLitter = litter; + } + } + + if (newestLitter != NULL) { + sub_6EC60B((rct_sprite*)newestLitter); + sprite_remove((rct_sprite*)newestLitter); + } + } + + litter = (rct_litter*)create_sprite(1); + if (litter == NULL) + return; + + move_sprite_to_list((rct_sprite*)litter, SPRITE_LINKEDLIST_OFFSET_LITTER); + litter->sprite_direction = direction; + litter->sprite_width = 6; + litter->sprite_height_negative = 6; + litter->sprite_height_positive = 3; + litter->sprite_identifier = SPRITE_IDENTIFIER_LITTER; + litter->type = type; + sprite_move(x, y, z, (rct_sprite*)litter); + sub_6EC60B((rct_sprite*)litter); + litter->creationTick = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32); } \ No newline at end of file diff --git a/src/world/sprite.h b/src/world/sprite.h index 7a93a7c1c8..4dbdebae6a 100644 --- a/src/world/sprite.h +++ b/src/world/sprite.h @@ -84,14 +84,18 @@ typedef struct { uint16 next; // 0x04 uint16 previous; // 0x06 uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_... - uint8 pad_09; + uint8 sprite_height_negative; // 0x09 uint16 sprite_index; // 0x0A uint16 pad_0C; sint16 x; // 0x0E sint16 y; // 0x10 sint16 z; // 0x12 - uint8 pad_14[0x10]; - uint32 var_24; + uint8 sprite_width; // 0x14 + uint8 sprite_height_positive; // 0x15 + uint8 pad_16[8]; + uint8 sprite_direction; // 0x1E + uint8 pad_1F[5]; + uint32 creationTick; // 0x24 } rct_litter; typedef struct { @@ -252,5 +256,6 @@ void sprite_move(sint16 x, sint16 y, sint16 z, rct_sprite* sprite); void invalidate_sprite(rct_sprite *sprite); void sub_6EC60B(rct_sprite* sprite); void sprite_remove(rct_sprite *sprite); +void litter_create(int x, int y, int z, int direction, int type); #endif