1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-19 13:03:11 +01:00
Files
OpenRCT2/src/peep/peep.c
2015-04-12 23:26:15 +02:00

5310 lines
141 KiB
C

/*****************************************************************************
* Copyright (c) 2014 Ted John
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* This file is part of OpenRCT2.
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include "../addresses.h"
#include "../audio/audio.h"
#include "../audio/mixer.h"
#include "../interface/window.h"
#include "../localisation/localisation.h"
#include "../management/news_item.h"
#include "../ride/ride.h"
#include "../scenario.h"
#include "../sprites.h"
#include "../world/sprite.h"
#include "../world/scenery.h"
#include "../management/marketing.h"
#include "peep.h"
#include "staff.h"
static void peep_update(rct_peep *peep);
static int peep_has_empty_container(rct_peep* peep);
static int peep_has_food_standard_flag(rct_peep* peep);
static int peep_has_food_extra_flag(rct_peep* peep);
static int peep_empty_container_standard_flag(rct_peep* peep);
static int peep_empty_container_extra_flag(rct_peep* peep);
static int peep_should_find_bench(rct_peep* peep);
static void peep_stop_purchase_thought(rct_peep* peep, uint8 ride_type);
const char *gPeepEasterEggNames[] = {
"MICHAEL SCHUMACHER",
"JACQUES VILLENEUVE",
"DAMON HILL",
"MR BEAN",
"CHRIS SAWYER",
"KATIE BRAYSHAW",
"MELANIE WARN",
"SIMON FOSTER",
"JOHN WARDLEY",
"LISA STIRLING",
"DONALD MACRAE",
"KATHERINE MCGOWAN",
"FRANCES MCGOWAN",
"CORINA MASSOURA",
"CAROL YOUNG",
"MIA SHERIDAN",
"KATIE RODGER",
"EMMA GARRELL",
"JOANNE BARTON",
"FELICITY ANDERSON",
"KATIE SMITH",
"EILIDH BELL",
"NANCY STILLWAGON",
"ANDY HINE",
"ELISSA WHITE",
"DAVID ELLIS"
};
int peep_get_staff_count()
{
uint16 spriteIndex;
rct_peep *peep;
int count = 0;
FOR_ALL_STAFF(spriteIndex, peep)
count++;
return count;
}
/**
*
* rct2: 0x0068F0A9
*/
void peep_update_all()
{
int i;
uint16 spriteIndex;
rct_peep* peep;
if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 0x0E)
return;
spriteIndex = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_PEEP, uint16);
i = 0;
while (spriteIndex != SPRITE_INDEX_NULL) {
peep = &(g_sprite_list[spriteIndex].peep);
spriteIndex = peep->next;
if ((i & 0x7F) != (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 0x7F)) {
peep_update(peep);
} else {
RCT2_CALLPROC_X(0x0068F41A, 0, 0, 0, i, (int)peep, 0, 0);
if (peep->linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_PEEP)
peep_update(peep);
}
i++;
}
}
/* some sort of check to see if peep is connected to the ground?? */
int sub_68F3AE(rct_peep* peep){
peep->var_C4++;
if ((peep->var_C4 & 0xF) != (peep->sprite_index & 0xF))return 1;
rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32);
uint8 map_type = MAP_ELEMENT_TYPE_PATH;
if (peep->next_var_29 & ((1 << 4) | (1 << 3))){
map_type = MAP_ELEMENT_TYPE_SURFACE;
}
int z = peep->next_z;
do {
if (map_element_get_type(map_element) == map_type){
if (z == map_element->base_height)return 1;
}
} while (!map_element_is_last_for_tile(map_element++));
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
return 0;
}
void sub_693B58(rct_peep* peep){
int ebx;
if (peep->action >= 0xFE){
ebx = RCT2_ADDRESS(0x981D8C, uint8)[peep->var_6D];
}
else{
ebx = RCT2_ADDRESS(0x981D8F, uint8)[peep->action];
}
if (ebx == peep->action_sprite_type)return;
invalidate_sprite((rct_sprite*)peep);
peep->action_sprite_type = ebx;
uint8* edx = RCT2_ADDRESS(0x98270C, uint8*)[peep->sprite_type * 2];
peep->sprite_width = edx[ebx * 4];
peep->sprite_height_negative = edx[ebx * 4 + 1];
peep->sprite_height_positive = edx[ebx * 4 + 2];
// This is pointless as nothing will have changed.
invalidate_sprite((rct_sprite*)peep);
}
/* 0x00693BE5 */
static void sub_693BE5(rct_peep* peep, uint8 al){
if (al == peep->var_6D)return;
peep->var_6D = al;
// If NONE_1 or NONE_2
if (peep->action >= PEEP_ACTION_NONE_1){
peep->action = PEEP_STATE_FALLING;
}
sub_693B58(peep);
}
static void peep_state_reset(rct_peep* peep){
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_1;
peep_window_state_update(peep);
sub_693BE5(peep, 0);
}
/* rct2: 0x69C308
* Check if lost.
*/
void peep_check_if_lost(rct_peep* peep){
if (!(peep->flags & PEEP_FLAGS_LOST)){
if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_COUNT, uint16) < 2)return;
peep->flags ^= PEEP_FLAGS_21;
if (!(peep->flags & PEEP_FLAGS_21)) return;
peep->var_F4++;
if (peep->var_F4 != 254)return;
peep->var_F4 = 230;
}
peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_LOST, 0xFF);
if (peep->happiness_growth_rate < 30) peep->happiness_growth_rate = 0;
else peep->happiness_growth_rate -= 30;
}
/* rct2: 0x69C26B
* Check if cant find ride.
*/
void peep_check_cant_find_ride(rct_peep* peep){
if (peep->guest_heading_to_ride_id == 0xFF) return;
if (peep->var_C6 == 30 || peep->var_C6 == 60){
peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_CANT_FIND, peep->guest_heading_to_ride_id);
if (peep->happiness_growth_rate < 30) peep->happiness_growth_rate = 0;
else peep->happiness_growth_rate -= 30;
}
peep->var_C6--;
if (peep->var_C6 != 0)return;
peep->guest_heading_to_ride_id = 0xFF;
rct_window* w = window_find_by_number(WC_PEEP, peep->sprite_index);
if (w){
window_event_invalidate_call(w);
}
widget_invalidate_by_number(WC_PEEP, peep->sprite_index, 12);
}
/* rct2: 0x69C2D0
* Check if cant find exit.
*/
void peep_check_cant_find_exit(rct_peep* peep){
if (!(peep->flags & PEEP_FLAGS_LEAVING_PARK))return;
if (peep->var_C6 == 1){
peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_CANT_FIND_EXIT, 0xFF);
if (peep->happiness_growth_rate < 30) peep->happiness_growth_rate = 0;
else peep->happiness_growth_rate -= 30;
}
if (--peep->var_C6 == 0) peep->var_C6 = 90;
}
/* rct2: 0x6939EB
* Also used to move peeps to the correct position to
* start an action. Returns 1 if the correct destination
* has not yet been reached. xy_distance is how close the
* peep is to the target.
*/
int peep_update_action(sint16* x, sint16* y, sint16* xy_distance, rct_peep* peep){
RCT2_GLOBAL(0xF1AEF0, uint8) = peep->action_sprite_image_offset;
if (peep->action == 0xFE){
peep->action = 0xFF;
}
*x = peep->x - peep->destination_x;
*y = peep->y - peep->destination_y;
int x_delta = abs(*x);
int y_delta = abs(*y);
*xy_distance = x_delta + y_delta;
if (peep->action >= 0xFE){
if (*xy_distance <= peep->destination_tolerence){
return 0;
}
int direction = 0;
if (x_delta < y_delta){
direction = 8;
if (*y >= 0){
direction = 24;
}
}
else{
direction = 16;
if (*x >= 0){
direction = 0;
}
}
peep->sprite_direction = direction;
*x = peep->x + RCT2_ADDRESS(0x981D7C, uint16)[direction / 4];
*y = peep->y + RCT2_ADDRESS(0x981D7E, uint16)[direction / 4];
peep->no_action_frame_no++;
uint32* edi = RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2];
uint8* _edi = (uint8*)(edi[peep->action_sprite_type * 2 + 1]);
if (peep->no_action_frame_no >= *_edi){
peep->no_action_frame_no = 0;
}
peep->action_sprite_image_offset = _edi[peep->no_action_frame_no + 1];
return 1;
}
uint32* edi = RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2];
uint8* _edi = (uint8*)(edi[peep->action_sprite_type * 2 + 1]);
peep->action_frame++;
int ebx = _edi[peep->action_frame + 1];
// If last frame of action
if (ebx == 0xFF){
peep->action_sprite_image_offset = 0;
peep->action = 0xFF;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
*x = peep->x;
*y = peep->y;
return 1;
}
peep->action_sprite_image_offset = ebx;
// If not throwing up and not at the frame where sick appears.
if (peep->action != PEEP_ACTION_THROW_UP || peep->action_frame != 15){
invalidate_sprite((rct_sprite*)peep);
*x = peep->x;
*y = peep->y;
return 1;
}
// We are throwing up
peep->hunger /= 2;
peep->nausea_growth_rate /= 2;
if (peep->nausea < 30)
peep->nausea = 0;
else
peep->nausea -= 30;
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;
sound_play_panned(sound_id, 0x8001, peep->x, peep->y, peep->z);
invalidate_sprite((rct_sprite*)peep);
*x = peep->x;
*y = peep->y;
return 1;
}
/**
* rct2: 0x0069A409
* Decreases rider count if on/entering a ride.
*/
void peep_decrement_num_riders(rct_peep* peep){
if (peep->state == PEEP_STATE_ON_RIDE
|| peep->state == PEEP_STATE_ENTERING_RIDE){
rct_ride* ride = GET_RIDE(peep->current_ride);
ride->num_riders--;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
}
}
/* Part of 0x0069B8CC rct2:0x0069BC31 */
void set_sprite_type(rct_peep* peep, uint8 type){
if (peep->sprite_type == type)return;
peep->sprite_type = type;
peep->action_sprite_image_offset = 0;
peep->no_action_frame_no = 0;
if (peep->action >= PEEP_ACTION_NONE_1)
peep->action = PEEP_ACTION_NONE_2;
peep->flags &= ~PEEP_FLAGS_SLOW_WALK;
if (RCT2_ADDRESS(0x00982134, uint8)[type] & 1){
peep->flags |= PEEP_FLAGS_SLOW_WALK;
}
peep->action_sprite_type = 0xFF;
sub_693B58(peep);
if (peep->state == PEEP_STATE_SITTING){
peep->action = PEEP_ACTION_NONE_1;
peep->var_6F = 7;
RCT2_CALLPROC_X(0x693BAB, 0, 0, 0, 0, (int)peep, 0, 0);
}
if (peep->state == PEEP_STATE_WATCHING){
peep->action = PEEP_ACTION_NONE_1;
peep->var_6F = 2;
RCT2_CALLPROC_X(0x693BAB, 0, 0, 0, 0, (int)peep, 0, 0);
}
}
typedef struct{
uint8 type; // 0 for standard, 1 for extra
uint32 item; // And this with the relevant flags
uint8 sprite_type;
} item_pref;
item_pref item_order_preference[] = {
{ 0, PEEP_ITEM_ICE_CREAM, 15 },
{ 0, PEEP_ITEM_FRIES, 16},
{ 0, PEEP_ITEM_PIZZA, 22 },
{ 0, PEEP_ITEM_BURGER, 17 },
{ 0, PEEP_ITEM_DRINK, 18 },
{ 0, PEEP_ITEM_COFFEE, 35 },
{ 0, PEEP_ITEM_CHICKEN, 34 },
{ 0, PEEP_ITEM_LEMONADE, 37 },
{ 0, PEEP_ITEM_COTTON_CANDY, 20 },
{ 0, PEEP_ITEM_POPCORN, 22 },
{ 0, PEEP_ITEM_HOT_DOG, 31 },
{ 0, PEEP_ITEM_TENTACLE, 32 },
{ 0, PEEP_ITEM_CANDY_APPLE, 33 },
{ 0, PEEP_ITEM_DONUT, 34 },
{ 1, PEEP_ITEM_PRETZEL, 39 },
{ 1, PEEP_ITEM_COOKIE, 39 },
{ 1, PEEP_ITEM_CHOCOLATE, 35 },
{ 1, PEEP_ITEM_ICED_TEA, 35 },
{ 1, PEEP_ITEM_FUNNEL_CAKE, 43 },
{ 1, PEEP_ITEM_BEEF_NOODLES, 44 },
{ 1, PEEP_ITEM_FRIED_RICE_NOODLES, 44 },
{ 1, PEEP_ITEM_WONTON_SOUP, 46 },
{ 1, PEEP_ITEM_MEATBALL_SOUP, 46 },
{ 1, PEEP_ITEM_FRUIT_JUICE, 43 },
{ 1, PEEP_ITEM_SOYBEAN_MILK, 41 },
{ 1, PEEP_ITEM_SU_JONGKWA, 41 },
{ 1, PEEP_ITEM_SUB_SANDWICH, 47 },
{ 1, PEEP_ITEM_ROAST_SAUSAGE, 45 },
{ 0, PEEP_ITEM_BALLOON, 19 },
{ 0, PEEP_ITEM_HAT, 30},
{ 1, PEEP_ITEM_SUNGLASSES, 40},
{ 0xFF, 0xFFFFFFFF, 0xFF}
};
/* rct2: 0x0069B8CC */
void peep_update_sprite_type(rct_peep* peep){
if (peep->sprite_type == 19 &&
(scenario_rand() & 0xFFFF) <= 327){
uint8 bl = 0;
if ((scenario_rand() & 0xFFFF) <= 13107 &&
peep->x != SPRITE_LOCATION_NULL){
bl = 1;
sound_play_panned(SOUND_BALLOON_POP, 0x8001, peep->x, peep->y, peep->z);
}
if (peep->x != SPRITE_LOCATION_NULL){
create_balloon(peep->x, peep->y, peep->z + 9, peep->balloon_colour, bl);
}
peep->item_standard_flags &= ~PEEP_ITEM_BALLOON;
peep->var_45 |= (1 << 3);
}
if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, uint8) != 0 &&
peep->item_standard_flags & PEEP_ITEM_UMBRELLA &&
peep->x != SPRITE_LOCATION_NULL){
int x = peep->x & 0xFFE0;
int y = peep->y & 0xFFE0;
if (x < 0x1FFF && y < 0x1FFF){
rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32);
while (1) {
if ((peep->z / 32) < map_element->base_height)break;
if (map_element_is_last_for_tile(map_element)){
set_sprite_type(peep, 21);
return;
}
map_element++;
}
}
}
for (item_pref* item_pref = item_order_preference; item_pref->type != 0xFF; item_pref++){
if (item_pref->type == 0){
if (peep->item_standard_flags & item_pref->item){
set_sprite_type(peep, item_pref->sprite_type);
return;
}
}
else{
if (peep->item_extra_flags & item_pref->item){
set_sprite_type(peep, item_pref->sprite_type);
return;
}
}
}
if (peep->state == PEEP_STATE_WATCHING &&
peep->standing_flags & (1<<1)){
set_sprite_type(peep, 38);
return;
}
if (peep->nausea > 170){
set_sprite_type(peep, 28);
return;
}
if (peep->nausea > 140){
set_sprite_type(peep, 27);
return;
}
if (peep->energy <= 64 &&
peep->happiness < 128){
set_sprite_type(peep, 26);
return;
}
if (peep->energy <= 80 &&
peep->happiness < 128){
set_sprite_type(peep, 25);
return;
}
if (peep->bathroom > 220){
set_sprite_type(peep, 29);
return;
}
set_sprite_type(peep, 0);
}
/**
* rct2: 0x0069A42F
* Call after changing a peeps state to insure that
* all relevant windows update. Note also increase ride
* count if on/entering a ride.
*/
void peep_window_state_update(rct_peep* peep){
rct_window* w = window_find_by_number(WC_PEEP, peep->sprite_index);
if (w != NULL)
window_event_invalidate_call(w);
if (peep->type == PEEP_TYPE_GUEST){
// Update action label
widget_invalidate_by_number(WC_PEEP, peep->sprite_index, 12);
if (peep->state == PEEP_STATE_ON_RIDE || peep->state == PEEP_STATE_ENTERING_RIDE){
rct_ride* ride = GET_RIDE(peep->current_ride);
ride->num_riders++;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
}
window_invalidate_by_class(WC_GUEST_LIST);
}
else{
// Update action label
widget_invalidate_by_number(WC_PEEP, peep->sprite_index, 9);
window_invalidate_by_class(WC_STAFF_LIST);
}
}
/* rct2: 0x0069A535*/
void peep_sprite_remove(rct_peep* peep){
//RCT2_CALLPROC_X(0x69A535, 0, 0, 0, 0, (int)peep, 0, 0);
//return;
RCT2_CALLPROC_X(0x0069A512, 0, 0, 0, 0, (int)peep, 0, 0);
invalidate_sprite((rct_sprite*)peep);
window_close_by_number(WC_PEEP, peep->sprite_index);
window_close_by_number(WC_FIRE_PROMPT, peep->sprite_identifier);
if (peep->type == PEEP_TYPE_GUEST){
window_invalidate_by_class(WC_GUEST_LIST);
news_item_disable_news(NEWS_ITEM_PEEP_ON_RIDE, peep->sprite_index);
}
else{
window_invalidate_by_class(WC_STAFF_LIST);
RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[peep->staff_id] = 0;
peep->type = 0xFF;
sub_6C0C3F();
peep->type = PEEP_TYPE_STAFF;
news_item_disable_news(NEWS_ITEM_PEEP, peep->sprite_index);
}
sprite_remove((rct_sprite*)peep);
}
/** New function removes peep from
* park existance. Works with staff.
*/
void peep_remove(rct_peep* peep){
if (peep->type == PEEP_TYPE_GUEST){
if (peep->var_2A == 0){
RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16)--;
RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) |= BTM_TB_DIRTY_FLAG_PEEP_COUNT;
}
if (peep->state == PEEP_STATE_ENTERING_PARK){
RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16)--;
}
}
peep_sprite_remove(peep);
}
/**
* rct2: 0x690028
* Falling and its subset drowning
*/
void peep_update_falling(rct_peep* peep){
if (peep->action == PEEP_ACTION_DROWNING){
// Check to see if we are ready to drown.
sint16 x, y, xy_distance;
peep_update_action(&x, &y, &xy_distance, peep);
//RCT2_CALLPROC_X(0x6939EB, 0, 0, 0, 0, (int)peep, 0, 0);
if (peep->action == PEEP_ACTION_DROWNING) return;
if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & 0x80000)){
RCT2_GLOBAL(0x13CE952, uint16) = peep->name_string_idx;
RCT2_GLOBAL(0x13CE954, uint32) = peep->id;
news_item_add_to_queue(NEWS_ITEM_BLANK, 2347, peep->x | (peep->y << 16));
}
RCT2_GLOBAL(0x135882E, uint16) += 25;
if (RCT2_GLOBAL(0x135882E, uint16) > 1000){
RCT2_GLOBAL(0x135882E, uint16) = 1000;
}
peep_remove(peep);
return;
}
// If not drowning then falling. Note: peeps 'fall' after leaving a ride/enter the park.
rct_map_element *map_element = map_get_first_element_at(peep->x / 32, peep->y / 32);
rct_map_element *saved_map = NULL;
int saved_height = 0;
do {
// If a path check if we are on it
if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_PATH){
int height = map_height_from_slope(peep->x, peep->y, map_element->properties.surface.slope)
+ map_element->base_height * 8;
if (height < peep->z - 1 || height > peep->z + 4) continue;
saved_height = height;
saved_map = map_element;
break;
} // If a surface get the height and see if we are on it
else if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_SURFACE){
// If the surface is water check to see if we could be drowning
if (map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK){
int height = (map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) * 16;
if (height - 4 >= peep->z && height < peep->z + 20){
// Looks like we are drowning!
invalidate_sprite((rct_sprite*)peep);
sprite_move(peep->x, peep->y, height, (rct_sprite*)peep);
// Drop balloon if held
if (peep->item_standard_flags & PEEP_ITEM_BALLOON){
peep->item_standard_flags &= ~PEEP_ITEM_BALLOON;
if (peep->sprite_type == 19 && peep->x != 0x8000){
create_balloon(peep->x, peep->y, height, peep->balloon_colour, 0);
peep->var_45 |= (1 << 3);
peep_update_sprite_type(peep);
}
}
peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_DROWNING, -1);
peep->action = PEEP_ACTION_DROWNING;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
peep_window_state_update(peep);
return;
}
}
int map_height = map_element_height(0xFFFF & peep->x, 0xFFFF & peep->y) & 0xFFFF;
if (map_height < peep->z || map_height - 4 > peep->z) continue;
saved_height = map_height;
saved_map = map_element;
} // If not a path or surface go see next element
else continue;
} while (!map_element_is_last_for_tile(map_element++));
// This will be null if peep is falling
if (saved_map == NULL){
invalidate_sprite((rct_sprite*)peep);
if (peep->z <= 1){
// Remove peep if it has gone to the void
peep_remove(peep);
return;
}
sprite_move(peep->x, peep->y, peep->z - 2, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
invalidate_sprite((rct_sprite*)peep);
sprite_move(peep->x, peep->y, saved_height, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
peep->next_x = peep->x & 0xFFE0;
peep->next_y = peep->y & 0xFFE0;
peep->next_z = saved_map->base_height;
int edx = saved_map->properties.surface.slope & 0x7;
if (map_element_get_type(saved_map) != MAP_ELEMENT_TYPE_PATH){
edx = 8;
}
peep->next_var_29 = edx;
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_1;
peep_window_state_update(peep);
}
/**
* rct2: 0x00691677
*/
void peep_try_get_up_from_sitting(rct_peep* peep){
// Eats all food first
if (peep_has_food(peep))return;
peep->time_to_sitdown--;
if (peep->time_to_sitdown) return;
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_WALKING;
peep_window_state_update(peep);
// Set destination to the center of the tile.
peep->destination_x = (peep->x & 0xFFE0) + 16;
peep->destination_y = (peep->y & 0xFFE0) + 16;
peep->destination_tolerence = 5;
sub_693B58(peep);
}
/**
* rct2: 0x0069152B
*/
void peep_update_sitting(rct_peep* peep){
if (peep->sub_state == 0){
if (!sub_68F3AE(peep))return;
//691541
RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0);
if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return;
int ebx = peep->var_37 & 0x7;
int x = (peep->x & 0xFFE0) + RCT2_ADDRESS(0x981F2C, uint16)[ebx * 2];
int y = (peep->y & 0xFFE0) + RCT2_ADDRESS(0x981F2E, uint16)[ebx * 2];
int z = peep->z;
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, z, (rct_sprite*)peep);
peep->sprite_direction = ((peep->var_37 + 2) & 3) * 8;
invalidate_sprite((rct_sprite*)peep);
peep->action = 254;
peep->var_6F = 7;
RCT2_CALLPROC_X(0x693BAB, 0, 0, 0, 0, (int)peep, 0, 0);
peep->sub_state++;
// Sets time to sit on seat
peep->time_to_sitdown = (129 - peep->energy) * 16 + 50;
}
else if (peep->sub_state == 1){
if (peep->action < 0xFE){
sint16 x, y, xy_distance;
peep_update_action(&x, &y, &xy_distance, peep);
//RCT2_CALLPROC_X(0x6939EB, 0, 0, 0, 0, (int)peep, 0, 0);
if (peep->action != 0xFF) return;
peep->action = 0xFE;
peep_try_get_up_from_sitting(peep);
return;
}
if ((peep->flags & PEEP_FLAGS_LEAVING_PARK)){
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_WALKING;
peep_window_state_update(peep);
// Set destination to the center of the tile
peep->destination_x = (peep->x & 0xFFE0) + 16;
peep->destination_y = (peep->y & 0xFFE0) + 16;
peep->destination_tolerence = 5;
sub_693B58(peep);
return;
}
if (peep->sprite_type == 0x15){
peep_try_get_up_from_sitting(peep);
return;
}
if (peep_has_food(peep)){
if ((scenario_rand() & 0xFFFF) > 1310){
peep_try_get_up_from_sitting(peep);
return;
}
peep->action = PEEP_ACTION_SITTING_EAT_FOOD;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
int rand = scenario_rand();
if ((rand & 0xFFFF) > 131){
peep_try_get_up_from_sitting(peep);
return;
}
if (peep->sprite_type == 0x13 || peep->sprite_type == 0x1E){
peep_try_get_up_from_sitting(peep);
return;
}
peep->action = PEEP_ACTION_SITTING_LOOK_AROUND_LEFT;
if (rand & 0x80000000){
peep->action = PEEP_ACTION_SITTING_LOOK_AROUND_RIGHT;
}
if (rand & 0x40000000){
peep->action = PEEP_ACTION_SITTING_CHECK_WATCH;
}
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
}
/**
*
* rct2: 0x006966A9
*/
void remove_peep_from_queue(rct_peep* peep)
{
rct_ride* ride = GET_RIDE(peep->current_ride);
uint8 cur_station = peep->current_ride_station;
ride->queue_length[cur_station]--;
if (peep->sprite_index == ride->first_peep_in_queue[cur_station])
{
ride->first_peep_in_queue[cur_station] = peep->next_in_queue;
return;
}
for (rct_peep* other_peep = GET_PEEP(ride->first_peep_in_queue[cur_station]);;
other_peep = GET_PEEP(other_peep->next_in_queue)){
if (peep->sprite_index == other_peep->next_in_queue){
other_peep->next_in_queue = peep->next_in_queue;
return;
}
}
}
/* rct2: 0x00691C6E */
static rct_vehicle* peep_choose_car_from_ride(rct_peep* peep, rct_ride* ride, uint8* car_array, uint8 car_array_size){
uint8 chosen_car = scenario_rand();
if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_HAS_G_FORCES
&& ((chosen_car & 0xC) != 0xC)){
chosen_car = (scenario_rand() & 1) ? 0 : car_array_size - 1;
}
else{
chosen_car = (chosen_car * (uint16)car_array_size) >> 8;
}
peep->current_car = car_array[chosen_car];
rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]);
for (int i = peep->current_car; i > 0; --i){
vehicle = GET_VEHICLE(vehicle->next_vehicle_on_train);
}
return vehicle;
}
/* rct2: 0x00691CD1 */
static void peep_choose_seat_from_car(rct_peep* peep, rct_ride* ride, rct_vehicle* vehicle){
uint8 chosen_seat = vehicle->next_free_seat;
if (ride->mode == RIDE_MODE_FORWARD_ROTATION ||
ride->mode == RIDE_MODE_BACKWARD_ROTATION){
chosen_seat = (((~vehicle->var_1F + 1) >> 3) & 0xF) * 2;
if (vehicle->next_free_seat & 1){
chosen_seat++;
}
}
peep->current_seat = chosen_seat;
vehicle->next_free_seat++;
vehicle->peep[peep->current_seat] = peep->sprite_index;
vehicle->peep_tshirt_colours[peep->current_seat] = peep->tshirt_colour;
}
/* rct2: 0x00691D27 */
static void peep_go_to_ride_entrance(rct_peep* peep, rct_ride* ride){
int x = ride->entrances[peep->current_ride_station] & 0xFF;
int y = ride->entrances[peep->current_ride_station] >> 8;
int z = ride->station_heights[peep->current_ride_station];
rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z);
uint8 direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK;
x *= 32;
y *= 32;
x += 16;
y += 16;
sint16 x_shift = RCT2_ADDRESS(0x00981D6C, sint16)[direction * 2];
sint16 y_shift = RCT2_ADDRESS(0x00981D6E, sint16)[direction * 2];
uint8 shift_multiplier = 21;
rct_ride_type* ride_type = GET_RIDE_ENTRY(ride->subtype);
if (ride_type->vehicles[ride_type->default_vehicle].var_12 & (1 << 3) ||
ride_type->vehicles[ride_type->default_vehicle].var_14 & 0x5000){
shift_multiplier = 32;
}
x_shift *= shift_multiplier;
y_shift *= shift_multiplier;
x += x_shift;
y += y_shift;
peep->destination_x = x;
peep->destination_y = y;
peep->destination_tolerence = 2;
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_ENTERING_RIDE;
peep->sub_state = 1;
peep_window_state_update(peep);
peep->var_AC = 0;
peep->var_E2 = 0;
remove_peep_from_queue(peep);
}
/* rct2: 0x00691A3B */
static void peep_update_ride_sub_state_0(rct_peep* peep){
rct_ride* ride = GET_RIDE(peep->current_ride);
if (peep->destination_tolerence != 0){
invalidate_sprite((rct_sprite*)peep);
sint16 x, y, xy_distance;
if (peep_update_action(&x, &y, &xy_distance, peep)){
sint16 z = peep->z;
if (xy_distance < 16){
z = ride->station_heights[peep->current_ride_station] * 8 + 2;
}
sprite_move(x, y, z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
}
else{
peep->destination_tolerence = 0;
peep->sprite_direction ^= (1 << 4);
}
}
uint8 car_array_size = 0xFF;
uint8* car_array = RCT2_ADDRESS(0xF1AD78, uint8);
if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_13){
if (ride->num_riders >= ride->var_0D0)
return;
}
else{
uint8 chosen_train = 0xFF;
if (ride->mode == RIDE_MODE_BUMPERCAR || ride->mode == RIDE_MODE_RACE){
if (ride->lifecycle_flags & RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING)
return;
for (int i = 0; i < ride->num_vehicles; ++i){
rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[i]);
if (vehicle->next_free_seat >= vehicle->num_seats)
continue;
if (vehicle->status != VEHICLE_STATUS_WAITING_FOR_PASSENGERS)
continue;
chosen_train = i;
break;
}
}
else{
chosen_train = ride->var_066[peep->current_ride_station];
}
if (chosen_train == 0xFF){
return;
}
peep->current_train = chosen_train;
uint8* car_array_pointer = car_array;
int i = 0;
uint16 vehicle_id = ride->vehicles[chosen_train];
rct_vehicle* vehicle = GET_VEHICLE(vehicle_id);
for (; vehicle_id != 0xFFFF;
vehicle_id = vehicle->next_vehicle_on_train,
i++){
vehicle = GET_VEHICLE(vehicle_id);
uint8 num_seats = vehicle->num_seats;
if (vehicle_is_used_in_pairs(vehicle)){
num_seats &= VEHICLE_SEAT_NUM_MASK;
if (vehicle->next_free_seat & 1){
peep->current_car = i;
peep_choose_seat_from_car(peep, ride, vehicle);
peep_go_to_ride_entrance(peep, ride);
return;
}
}
if (num_seats == vehicle->next_free_seat)
continue;
if (ride->mode == RIDE_MODE_FORWARD_ROTATION ||
ride->mode == RIDE_MODE_BACKWARD_ROTATION)
{
uint8 position = (((~vehicle->var_1F + 1) >> 3) & 0xF) * 2;
if (vehicle->peep[position] != 0xFFFF)
continue;
}
*car_array_pointer++ = i;
}
car_array_size = car_array_pointer - car_array;
if (car_array_size == 0)return;
}
if (ride->status != RIDE_STATUS_OPEN ||
ride->var_1CA != 0){
if (peep->destination_tolerence == 0){
remove_peep_from_queue(peep);
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
}
return;
}
if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)
return;
if (ride->price != 0){
if (!(peep->item_standard_flags & PEEP_ITEM_VOUCHER) ||
!(peep->voucher_type == VOUCHER_TYPE_RIDE_FREE) ||
!(peep->voucher_arguments == peep->current_ride)){
if (peep->cash_in_pocket <= 0){
peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_SPENT_MONEY, 0xFF);
if (peep->destination_tolerence == 0){
remove_peep_from_queue(peep);
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
}
return;
}
if (ride->price > peep->cash_in_pocket){
peep_insert_new_thought(peep, 0, peep->current_ride);
if (peep->destination_tolerence == 0){
remove_peep_from_queue(peep);
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
}
return;
}
uint16 value = ride->value;
if (value != RIDE_VALUE_UNDEFINED){
if (value * 2 < ride->price){
peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_BAD_VALUE, peep->current_ride);
if (peep->destination_tolerence == 0){
remove_peep_from_queue(peep);
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
}
return;
}
}
}
}
if (!(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_13)){
rct_vehicle* vehicle = peep_choose_car_from_ride(peep, ride, car_array, car_array_size);
peep_choose_seat_from_car(peep, ride, vehicle);
}
peep_go_to_ride_entrance(peep, ride);
}
/* rct2: 0x006921D3 */
void peep_update_ride_sub_state_1(rct_peep* peep){
sint16 x, y, xy_distance;
rct_ride* ride = GET_RIDE(peep->current_ride);
rct_ride_type* ride_entry = gRideTypeList[ride->subtype];
if (peep_update_action(&x, &y, &xy_distance, peep))
{
uint8 vehicle = ride_entry->default_vehicle;
if (ride_entry->vehicles[vehicle].var_12 & (1 << 3) ||
ride_entry->vehicles[vehicle].var_14 & ((1 << 14) | (1<<12)))
RCT2_GLOBAL(0xF1AECA, uint16) = 0x1C;
else
RCT2_GLOBAL(0xF1AECA, uint16) = 0x10;
if (peep->sub_state == 1 &&
xy_distance < RCT2_GLOBAL(0xF1AECA, uint16))
peep->sub_state = 2;
invalidate_sprite((rct_sprite*)peep);
sint16 z = ride->station_heights[peep->current_ride_station] * 8;
RCT2_GLOBAL(0xF1AECA, uint16) += 4;
if (xy_distance < RCT2_GLOBAL(0xF1AECA, uint16)){
z += RCT2_ADDRESS(0x0097D21C, uint8)[ride->type * 8];
}
sprite_move(x, y, z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] &RIDE_TYPE_FLAG_13)
{
sint16 x, y, z;
x = ride->entrances[peep->current_ride_station] & 0xFF;
y = ride->entrances[peep->current_ride_station] >> 8;
z = ride->station_heights[peep->current_ride_station];
rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z);
uint8 direction_entrance = (map_element->type & MAP_ELEMENT_DIRECTION_MASK);
if (ride->type == RIDE_TYPE_MAZE){
peep->maze_last_edge = direction_entrance + 1;
x *= 32;
y *= 32;
x += RCT2_ADDRESS(0x993CCC, sint16)[direction_entrance * 2];
y += RCT2_ADDRESS(0x993CCE, sint16)[direction_entrance * 2];
uint8 direction = direction_entrance * 4 + 11;
if (scenario_rand() & 0x40){
direction += 4;
peep->maze_last_edge += 2;
}
direction &= 0xF;
peep->var_37 = direction;
peep->maze_last_edge &= 3;
x += RCT2_GLOBAL(0x981FD1 + direction, sint16);
y += RCT2_GLOBAL(0x981FD3 + direction, sint16);
peep->destination_x = x;
peep->destination_y = y;
peep->destination_tolerence = 3;
ride->var_120++;
RCT2_CALLPROC_X(0x00695444, 0, 0, 0, peep->current_ride, (int)peep, 0, 0);
peep->sub_state = 17;
return;
}
x = ride->station_starts[peep->current_ride_station] & 0xFF;
y = ride->station_starts[peep->current_ride_station] >> 8;
map_element = ride_get_station_start_track_element(ride, peep->current_ride_station);
uint8 direction_track = map_element->type & MAP_ELEMENT_DIRECTION_MASK;
peep->var_37 = (direction_entrance << 2) | (direction_track << 4);
x *= 32;
y *= 32;
sint8* edx = peep->var_37 * 2 + RCT2_ADDRESS(0x97E1BC, sint8*)[ride->type];
x += edx[0];
y += edx[1];
peep->destination_x = x;
peep->destination_y = y;
peep->current_car = 0;
ride->var_120++;
RCT2_CALLPROC_X(0x00695444, 0, 0, 0, peep->current_ride, (int)peep, 0, 0);
peep->sub_state = 14;
return;
}
rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]);
for (int i = peep->current_car; i != 0; --i){
vehicle = GET_VEHICLE(vehicle->next_vehicle_on_train);
}
ride_entry = GET_RIDE_ENTRY(vehicle->ride_subtype);
rct_ride_type_vehicle* vehicle_type = &ride_entry->vehicles[vehicle->vehicle_type];
if (vehicle_type->var_14 & (1 << 10)){
sint16 x, y, z;
x = ride->entrances[peep->current_ride_station] & 0xFF;
y = ride->entrances[peep->current_ride_station] >> 8;
z = ride->station_heights[peep->current_ride_station];
rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z);
uint8 direction_entrance = map_element->type & MAP_ELEMENT_DIRECTION_MASK;
x = ride->station_starts[peep->current_ride_station] & 0xFF;
y = ride->station_starts[peep->current_ride_station] >> 8;
map_element = ride_get_station_start_track_element(ride, peep->current_ride_station);
uint8 direction_track = map_element->type & MAP_ELEMENT_DIRECTION_MASK;
vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]);
ride_entry = GET_RIDE_ENTRY(vehicle->ride_subtype);
vehicle_type = &ride_entry->vehicles[vehicle->vehicle_type];
uint8 cl = peep->current_seat;
uint8 ch = peep->current_seat & 0xF8;
if (ride->type != RIDE_TYPE_ENTERPRISE)
direction_track *= 2;
if (*vehicle_type->peep_loading_positions == 0){
direction_track /= 2;
cl = 0;
ch = 0;
}
cl += direction_track;
cl &= 0x7;
cl += ch;
peep->var_37 = (direction_entrance | cl * 4) * 4;
x *= 32;
y *= 32;
x += 16;
y += 16;
if (ride->type == RIDE_TYPE_ENTERPRISE)
{
x = vehicle->x;
y = vehicle->y;
}
x += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 1];
y += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 2];
peep->destination_x = x;
peep->destination_y = y;
peep->sub_state = 12;
return;
}
if (vehicle_type->var_14 & (1 << 15)){
peep->destination_x = vehicle->x;
peep->destination_y = vehicle->y;
peep->destination_tolerence = 15;
peep->sub_state = 4;
return;
}
sint8 load_position = vehicle_type->peep_loading_positions[peep->current_seat];
switch (vehicle->sprite_direction / 8){
case 0:
peep->destination_x = vehicle->x - load_position;
break;
case 1:
peep->destination_y = vehicle->y + load_position;
break;
case 2:
peep->destination_x = vehicle->x + load_position;
break;
case 3:
peep->destination_y = vehicle->y - load_position;
break;
}
peep->sub_state = 4;
return;
}
/* rct2: 0x0069321D */
static void peep_go_to_ride_exit(rct_peep* peep, rct_ride* ride, sint16 x, sint16 y, sint16 z, uint8 exit_direction){
z += RCT2_ADDRESS(0x0097D21C, uint8)[ride->type * 8];
sprite_move(x, y, z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
x = ride->exits[peep->current_ride_station] & 0xFF;
y = ride->exits[peep->current_ride_station] >> 8;
x *= 32;
y *= 32;
x += 16;
y += 16;
sint16 x_shift = RCT2_ADDRESS(0x00981D6C, sint16)[exit_direction * 2];
sint16 y_shift = RCT2_ADDRESS(0x00981D6E, sint16)[exit_direction * 2];
sint16 shift_multiplier = 20;
rct_ride_type* ride_type = GET_RIDE_ENTRY(ride->subtype);
rct_ride_type_vehicle* vehicle_entry = &ride_type->vehicles[ride_type->default_vehicle];
if (vehicle_entry->var_12 & (1 << 3) ||
vehicle_entry->var_14 & 0x5000){
shift_multiplier = 32;
}
x_shift *= shift_multiplier;
y_shift *= shift_multiplier;
x -= x_shift;
y -= y_shift;
peep->destination_x = x;
peep->destination_y = y;
peep->destination_tolerence = 2;
peep->sprite_direction = exit_direction * 8;
peep->sub_state = 8;
return;
}
/* rct2: 0x006920B4 */
static void peep_update_ride_sub_state_2_enter_ride(rct_peep* peep, rct_ride* ride){
if (ride->price != 0){
if ((peep->item_standard_flags & PEEP_ITEM_VOUCHER) &&
(peep->voucher_type == VOUCHER_TYPE_RIDE_FREE) &&
(peep->voucher_arguments == peep->current_ride)){
peep->item_standard_flags &= ~PEEP_ITEM_VOUCHER;
peep->var_45 |= (1 << 3);
}
else{
ride->total_profit += ride->price;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
RCT2_GLOBAL(0x0141F56C, uint8) = 20;
RCT2_GLOBAL(0xF1AEC0, uint32) = 230;
RCT2_CALLPROC_X(0x0069926C, 0, ride->price, 0, 0, (int)peep, 0, 0);
}
}
peep->sub_state++;
uint8 queue_time = peep->days_in_queue;
if (queue_time < 253)queue_time += 3;
queue_time /= 2;
if (queue_time != ride->queue_time[peep->current_ride_station]){
ride->queue_time[peep->current_ride_station] = queue_time;
window_invalidate_by_number(WC_RIDE, peep->current_ride);
}
if (peep->flags & PEEP_FLAGS_TRACKING){
RCT2_GLOBAL(0x13CE952, uint16) = peep->name_string_idx;
RCT2_GLOBAL(0x13CE954, uint32) = peep->id;
RCT2_GLOBAL(0x13CE958, uint16) = ride->name;
RCT2_GLOBAL(0x13CE95A, uint32) = ride->name_arguments;
rct_string_id msg_string;
if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_IN_RIDE)
msg_string = 1932;
else
msg_string = 1933;
news_item_add_to_queue(NEWS_ITEM_PEEP_ON_RIDE, msg_string, peep->sprite_index);
}
if (ride->type == RIDE_TYPE_SPIRAL_SLIDE){
sub_693BE5(peep, 1);
}
peep_update_ride_sub_state_1(peep);
}
/* rct2: 0x00691FD4 */
static void peep_update_ride_sub_state_2_rejoin_queue(rct_peep* peep, rct_ride* ride){
sint16 x, y, z;
x = ride->entrances[peep->current_ride_station] & 0xFF;
y = ride->entrances[peep->current_ride_station] >> 8;
z = ride->station_heights[peep->current_ride_station];
rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z);
uint8 direction_entrance = map_element->type & MAP_ELEMENT_DIRECTION_MASK;
x *= 32;
y *= 32;
x += 16 - RCT2_ADDRESS(0x981D6C, sint16)[direction_entrance * 2] * 20;
y += 16 - RCT2_ADDRESS(0x981D6E, sint16)[direction_entrance * 2] * 20;
peep->destination_x = x;
peep->destination_y = y;
peep->destination_tolerence = 2;
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_QUEUING_FRONT;
peep->sub_state = 0;
peep_window_state_update(peep);
peep->next_in_queue = 0xFFFF;
ride->queue_length[peep->current_ride_station]++;
uint16 current_first = ride->first_peep_in_queue[peep->current_ride_station];
if (current_first == 0xFFFF){
ride->first_peep_in_queue[peep->current_ride_station] = peep->sprite_index;
return;
}
rct_peep* queue_peep;
for (queue_peep = GET_PEEP(current_first);
queue_peep->next_in_queue != 0xFFFF;
queue_peep = GET_PEEP(queue_peep->next_in_queue));
queue_peep->next_in_queue = peep->sprite_index;
}
/* rct2: 0x00691E42
* Note: Before this was the entry
* point for sub state 1 and 3. The
* check has been removed that would
* branch it out to 1 and 3. Now uses
* separate functions.
*/
static void peep_update_ride_sub_state_2(rct_peep* peep){
rct_ride* ride = GET_RIDE(peep->current_ride);
if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_13){
if (ride->status != RIDE_STATUS_OPEN ||
ride->var_1CA != 0 ||
(++peep->var_AC) == 0){
peep_update_ride_sub_state_2_rejoin_queue(peep, ride);
return;
}
peep_update_ride_sub_state_2_enter_ride(peep, ride);
return;
}
rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]);
for (int i = peep->current_car; i != 0; --i){
vehicle = GET_VEHICLE(vehicle->next_vehicle_on_train);
}
rct_ride_type* ride_entry = GET_RIDE_ENTRY(vehicle->ride_subtype);
if (ride_entry->vehicles[0].var_12 & (1 << 3)){
vehicle->var_D5 &= ~(1 << 5);
for (int i = 0; i < ride->num_vehicles; ++i){
if (ride->vehicles[i] == 0xFFFF)
continue;
rct_vehicle* train = GET_VEHICLE(ride->vehicles[i]);
rct_vehicle* second_vehicle = GET_VEHICLE(train->next_vehicle_on_train);
if (second_vehicle->num_peeps == 0)
continue;
if (second_vehicle->var_D5 & (1 << 5))
continue;
return;
}
}
if (!vehicle_is_used_in_pairs(vehicle)){
peep_update_ride_sub_state_2_enter_ride(peep, ride);
return;
}
if (ride->mode == RIDE_MODE_FORWARD_ROTATION ||
ride->mode == RIDE_MODE_BACKWARD_ROTATION){
if (peep->current_seat & 1 ||
!(vehicle->next_free_seat & 1)){
peep_update_ride_sub_state_2_enter_ride(peep, ride);
return;
}
}
else{
uint8 current_seat = (peep->current_seat & 0xFE) + 1;
if (current_seat < vehicle->next_free_seat)
{
peep_update_ride_sub_state_2_enter_ride(peep, ride);
return;
}
}
if (ride->status == RIDE_STATUS_OPEN &&
++peep->var_AC != 0 &&
!((GET_VEHICLE(ride->vehicles[peep->current_train]))->var_48 & (1 << 4)))
return;
if (ride->mode != RIDE_MODE_FORWARD_ROTATION &&
ride->mode != RIDE_MODE_BACKWARD_ROTATION){
if (vehicle->next_free_seat - 1 != peep->current_seat)
return;
}
vehicle->next_free_seat--;
vehicle->peep[peep->current_seat] = 0xFFFF;
peep_update_ride_sub_state_2_rejoin_queue(peep, ride);
}
static void peep_update_ride_sub_state_5(rct_peep* peep){
rct_ride* ride = GET_RIDE(peep->current_ride);
rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]);
for (int i = peep->current_car; i != 0; --i){
vehicle = GET_VEHICLE(vehicle->next_vehicle_on_train);
}
if (ride->mode != RIDE_MODE_FORWARD_ROTATION &&
ride->mode != RIDE_MODE_BACKWARD_ROTATION){
if (peep->current_seat != vehicle->num_peeps)
return;
}
if (vehicle_is_used_in_pairs(vehicle)){
rct_peep* seated_peep = GET_PEEP(vehicle->peep[peep->current_seat ^ 1]);
if (seated_peep->sub_state != 5)
return;
vehicle->num_peeps++;
ride->var_120++;
vehicle->var_46 += seated_peep->var_41;
invalidate_sprite((rct_sprite*)seated_peep);
sprite_move(0x8000, 0, 0, (rct_sprite*)seated_peep);
peep_decrement_num_riders(seated_peep);
seated_peep->state = PEEP_STATE_ON_RIDE;
peep_window_state_update(seated_peep);
seated_peep->var_E2 = 0;
seated_peep->sub_state = 6;
RCT2_CALLPROC_X(0x00695444, 0, 0, 0, seated_peep->current_ride, (int)seated_peep, 0, 0);
}
vehicle->num_peeps++;
ride->var_120++;
vehicle->var_46 += peep->var_41;
invalidate_sprite((rct_sprite*)vehicle);
invalidate_sprite((rct_sprite*)peep);
sprite_move(0x8000, 0, 0, (rct_sprite*)peep);
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_ON_RIDE;
peep_window_state_update(peep);
peep->var_E2 = 0;
peep->sub_state = 6;
RCT2_CALLPROC_X(0x00695444, 0, 0, 0, peep->current_ride, (int)peep, 0, 0);
}
/* rct2: 0x00693028*/
static void peep_update_ride_sub_state_7(rct_peep* peep){
rct_ride* ride = GET_RIDE(peep->current_ride);
rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]);
uint8 ride_station = vehicle->current_station;
for (int i = peep->current_car; i != 0; --i){
vehicle = GET_VEHICLE(vehicle->next_vehicle_on_train);
}
// Unsure why backward rotation is missing.
if (ride->mode != RIDE_MODE_FORWARD_ROTATION){
if (vehicle->num_peeps - 1 != peep->current_seat)
return;
}
peep->action_sprite_image_offset++;
if (peep->action_sprite_image_offset & 3)
return;
peep->action_sprite_image_offset = 0;
vehicle->num_peeps--;
vehicle->var_46 -= peep->var_41;
invalidate_sprite((rct_sprite*)vehicle);
peep->current_ride_station = ride_station;
rct_ride_type* ride_entry = GET_RIDE_ENTRY(vehicle->ride_subtype);
rct_ride_type_vehicle* vehicle_entry = &ride_entry->vehicles[vehicle->vehicle_type];
if (!(vehicle_entry->var_14 & (1 << 10))){
sint16 x, y, z;
x = ride->exits[peep->current_ride_station] & 0xFF;
y = ride->exits[peep->current_ride_station] >> 8;
z = ride->station_heights[peep->current_ride_station];
rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z);
uint8 exit_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK;
exit_direction ^= (1 << 1);
if (!(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_16)){
for (; vehicle->var_01 != 0; vehicle = GET_VEHICLE(vehicle->prev_vehicle_on_train)){
uint16 eax = vehicle->var_36 / 4;
if (eax == 0 || eax > 3)
continue;
rct_map_element* inner_map = map_get_first_element_at(vehicle->var_38 / 32, vehicle->var_3A / 32);
for (;; inner_map++){
if (map_element_get_type(inner_map) != MAP_ELEMENT_TYPE_TRACK)
continue;
if (inner_map->base_height == vehicle->var_3C / 8)
break;
}
uint8 al = (inner_map->properties.track.sequence & 0x70) >> 4;
if (al == peep->current_ride_station)
break;
}
ride_entry = GET_RIDE_ENTRY(ride->subtype);
vehicle_entry = &ride_entry->vehicles[ride_entry->default_vehicle];
uint8 shift_multiplier = 12;
if (vehicle_entry->var_14 & (1 << 14)){
shift_multiplier = 9;
}
uint8 direction = exit_direction;
if (vehicle_entry->var_14 & ((1 << 14) | (1 << 12))){
direction = ((vehicle->sprite_direction + 3) / 8) + 1;
direction &= 3;
if (vehicle->var_CD == 6)
direction ^= (1 << 1);
}
sint16 x_shift = RCT2_ADDRESS(0x00981D6C, sint16)[direction * 2];
sint16 y_shift = RCT2_ADDRESS(0x00981D6E, sint16)[direction * 2];
x = vehicle->x + x_shift * shift_multiplier;
y = vehicle->y + y_shift * shift_multiplier;
z *= 8;
peep_go_to_ride_exit(peep, ride, x, y, z, exit_direction);
return;
}
x = vehicle->x + RCT2_ADDRESS(0x00981D6C, sint16)[exit_direction * 2] * 12;
y = vehicle->y + RCT2_ADDRESS(0x00981D6E, sint16)[exit_direction * 2] * 12;
sint8 load_position = vehicle_entry->peep_loading_positions[peep->current_seat];
switch (vehicle->sprite_direction / 8){
case 0:
x -= load_position;
break;
case 1:
y += load_position;
break;
case 2:
x += load_position;
break;
case 3:
y -= load_position;
break;
}
z = ride->station_heights[peep->current_ride_station] * 8;
peep_go_to_ride_exit(peep, ride, x, y, z, exit_direction);
return;
}
sint16 x, y, z;
x = ride->exits[peep->current_ride_station] & 0xFF;
y = ride->exits[peep->current_ride_station] >> 8;
z = ride->station_heights[peep->current_ride_station];
rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z);
uint8 exit_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK;
x = ride->station_starts[peep->current_ride_station] & 0xFF;
y = ride->station_starts[peep->current_ride_station] >> 8;
map_element = ride_get_station_start_track_element(ride, peep->current_ride_station);
uint8 station_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK;
vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]);
ride_entry = GET_RIDE_ENTRY(vehicle->ride_subtype);
rct_ride_type_vehicle* vehicle_type = &ride_entry->vehicles[vehicle->vehicle_type];
uint8 cl = peep->current_seat;
uint8 ch = peep->current_seat & 0xF8;
if (ride->type != RIDE_TYPE_ENTERPRISE)
station_direction *= 2;
if (*vehicle_type->peep_loading_positions == 0){
station_direction /= 2;
cl = 0;
ch = 0;
}
cl += station_direction;
cl &= 0x7;
cl += ch;
peep->var_37 = ((exit_direction | cl * 4) * 4) | 1;
x *= 32;
y *= 32;
x += 16;
y += 16;
if (ride->type == RIDE_TYPE_ENTERPRISE)
{
x = vehicle->x;
y = vehicle->y;
}
sint16 exit_x = x + vehicle_type->peep_loading_positions[(peep->var_37 + 1) * 2 + 1];
sint16 exit_y = y + vehicle_type->peep_loading_positions[(peep->var_37 + 1) * 2 + 2];
z *= 8;
z += RCT2_ADDRESS(0x0097D21C, uint8)[ride->type * 8];
if (ride->type == RIDE_TYPE_MOTION_SIMULATOR)
z += 15;
sprite_move(exit_x, exit_y, z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
x += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 1];
y += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 2];
peep->destination_x = x;
peep->destination_y = y;
peep->destination_tolerence = 2;
peep->sub_state = 13;
}
/* rct2: 0x0069376A */
static void peep_update_ride_prepare_for_state_9(rct_peep* peep){
rct_ride* ride = GET_RIDE(peep->current_ride);
sint16 x = ride->exits[peep->current_ride_station] & 0xFF;
sint16 y = ride->exits[peep->current_ride_station] >> 8;
sint16 z = ride->station_heights[peep->current_ride_station];
rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z);
uint8 exit_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK;
x *= 32;
y *= 32;
x += 16;
y += 16;
sint16 x_shift = RCT2_ADDRESS(0x00981D6C, sint16)[exit_direction * 2];
sint16 y_shift = RCT2_ADDRESS(0x00981D6E, sint16)[exit_direction * 2];
sint16 shift_multiplier = 20;
rct_ride_type* ride_type = GET_RIDE_ENTRY(ride->subtype);
rct_ride_type_vehicle* vehicle_entry = &ride_type->vehicles[ride_type->default_vehicle];
if (vehicle_entry->var_14 & 0x5000){
shift_multiplier = 32;
}
x_shift *= shift_multiplier;
y_shift *= shift_multiplier;
x -= x_shift;
y -= y_shift;
peep->destination_x = x;
peep->destination_y = y;
peep->destination_tolerence = 2;
peep->sub_state = 9;
}
/* rct2: 0x0069374F */
static void peep_update_ride_sub_state_8(rct_peep* peep){
sint16 x, y, xy_distance;
if (peep_update_action(&x, &y, &xy_distance, peep)){
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, peep->z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
peep_update_ride_prepare_for_state_9(peep);
}
/* rct2: 0x0069382E */
static void peep_update_ride_sub_state_9(rct_peep* peep){
sint16 x, y, xy_distance;
rct_ride* ride = GET_RIDE(peep->current_ride);
if (peep_update_action(&x, &y, &xy_distance, peep)){
invalidate_sprite((rct_sprite*)peep);
if (xy_distance >= 16){
sint16 z = ride->station_heights[peep->current_ride_station] * 8;
z += RCT2_ADDRESS(0x97D21C, uint8)[ride->type * 8];
sprite_move(x, y, z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
sub_693BE5(peep, 0);
sprite_move(x, y, peep->z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
}
if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO){
uint8 secondaryItem = RCT2_ADDRESS(0x0097D7CB, uint8)[ride->type * 4];
if (!(RCT2_CALLPROC_X(0x0069AF1E, secondaryItem | (peep->current_ride << 8), 0, ride->price_secondary, 0, (int)peep, 0, 0) & 0x100)){
ride->no_secondary_items_sold++;
}
}
peep->sub_state = 18;
}
/* rct2: 0x006926AD */
static void peep_update_ride_sub_state_12(rct_peep* peep){
sint16 x, y, xy_distance;
rct_ride* ride = GET_RIDE(peep->current_ride);
if (peep_update_action(&x, &y, &xy_distance, peep)){
sint16 z;
if (ride->type == RIDE_TYPE_MOTION_SIMULATOR){
z = ride->station_heights[peep->current_ride_station] * 8 + 2;
if ((peep->var_37 & 3) == 2){
xy_distance -= 12;
if (xy_distance < 0)
xy_distance = 0;
if (xy_distance <= 15){
z += 15 - xy_distance;
}
}
}
else{
z = peep->z;
}
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
if ((peep->var_37 & 3) == 2){
peep->sub_state = 5;
return;
}
peep->var_37++;
rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]);
x = ride->station_starts[peep->current_ride_station] & 0xFF;
y = ride->station_starts[peep->current_ride_station] >> 8;
x *= 32;
y *= 32;
x += 16;
y += 16;
if (ride->type == RIDE_TYPE_ENTERPRISE){
x = vehicle->x;
y = vehicle->y;
}
rct_ride_type* ride_entry = GET_RIDE_ENTRY(vehicle->ride_subtype);
rct_ride_type_vehicle* vehicle_type = &ride_entry->vehicles[vehicle->vehicle_type];
x += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 1];
y += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 2];
peep->destination_x = x;
peep->destination_y = y;
}
/* rct2: 0x0069357D */
static void peep_udpate_ride_sub_state_13(rct_peep* peep){
sint16 x, y, xy_distance;
rct_ride* ride = GET_RIDE(peep->current_ride);
if (peep_update_action(&x, &y, &xy_distance, peep)){
sint16 z;
if (ride->type == RIDE_TYPE_MOTION_SIMULATOR){
z = ride->station_heights[peep->current_ride_station] * 8 + 2;
if ((peep->var_37 & 3) == 1){
if (xy_distance > 15)
xy_distance = 15;
z += xy_distance;
}
}
else{
z = peep->z;
}
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
if ((peep->var_37 & 3) != 0){
if ((peep->var_37 & 3) == 3){
peep_update_ride_prepare_for_state_9(peep);
return;
}
peep->var_37--;
rct_vehicle* vehicle = GET_VEHICLE(ride->vehicles[peep->current_train]);
x = ride->station_starts[peep->current_ride_station] & 0xFF;
y = ride->station_starts[peep->current_ride_station] >> 8;
x *= 32;
y *= 32;
x += 16;
y += 16;
if (ride->type == RIDE_TYPE_ENTERPRISE){
x = vehicle->x;
y = vehicle->y;
}
rct_ride_type* ride_entry = GET_RIDE_ENTRY(vehicle->ride_subtype);
rct_ride_type_vehicle* vehicle_type = &ride_entry->vehicles[vehicle->vehicle_type];
x += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 1];
y += vehicle_type->peep_loading_positions[peep->var_37 * 2 + 2];
peep->destination_x = x;
peep->destination_y = y;
}
peep->var_37 |= 3;
x = ride->exits[peep->current_ride_station] & 0xFF;
y = ride->exits[peep->current_ride_station] >> 8;
sint16 z = ride->station_heights[peep->current_ride_station];
rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z);
uint8 exit_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK;
exit_direction ^= (1 << 1);
x *= 32;
y *= 32;
x += 16;
y += 16;
sint16 x_shift = RCT2_ADDRESS(0x00981D6C, sint16)[exit_direction * 2];
sint16 y_shift = RCT2_ADDRESS(0x00981D6E, sint16)[exit_direction * 2];
sint16 shift_multiplier = 20;
rct_ride_type* ride_type = GET_RIDE_ENTRY(ride->subtype);
rct_ride_type_vehicle* vehicle_entry = &ride_type->vehicles[ride_type->default_vehicle];
if (vehicle_entry->var_14 & 0x5000){
shift_multiplier = 32;
}
x_shift *= shift_multiplier;
y_shift *= shift_multiplier;
x -= x_shift;
y -= y_shift;
peep->destination_x = x;
peep->destination_y = y;
}
/* rct2: 0x006927B3 */
static void peep_update_ride_sub_state_14(rct_peep* peep){
sint16 x, y, xy_distance;
rct_ride* ride = GET_RIDE(peep->current_ride);
if (peep_update_action(&x, &y, &xy_distance, peep)){
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, peep->z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
if ((peep->var_37 & 3) == 3){
peep->sub_state = 15;
peep->destination_x = 0;
peep->destination_y = 0;
peep->var_37 = (peep->var_37 / 4) & 0xC;
sprite_move(0x8000, y, peep->z, (rct_sprite*)peep);
return;
}
else if ((peep->var_37 & 3) == 2){
uint8 last_ride = 0;
if (ride->status != RIDE_STATUS_OPEN)
last_ride = 1;
else if (peep->current_car++ != 0){
if (ride->mode == RIDE_MODE_SINGLE_RIDE_PER_ADMISSION)
last_ride = 1;
if ((uint8)(peep->current_car - 1) > (scenario_rand() & 0xF))
last_ride = 1;
}
if (last_ride){
x = ride->exits[peep->current_ride_station] & 0xFF;
y = ride->exits[peep->current_ride_station] >> 8;
sint16 z = ride->station_heights[peep->current_ride_station];
rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z);
uint8 exit_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK;
peep->var_37 = (exit_direction * 4) | (peep->var_37 & 0x30) | 1;
x = ride->station_starts[peep->current_ride_station] & 0xFF;
y = ride->station_starts[peep->current_ride_station] >> 8;
x *= 32;
y *= 32;
sint8* edx = peep->var_37 * 2 + RCT2_ADDRESS(0x97E1BC, sint8*)[ride->type];
x += edx[0];
y += edx[1];
peep->destination_x = x;
peep->destination_y = y;
peep->sub_state = 16;
return;
}
}
peep->var_37++;
x = ride->station_starts[peep->current_ride_station] & 0xFF;
y = ride->station_starts[peep->current_ride_station] >> 8;
x *= 32;
y *= 32;
sint8* edx = peep->var_37 * 2 + RCT2_ADDRESS(0x97E1BC, sint8*)[ride->type];
x += edx[0];
y += edx[1];
peep->destination_x = x;
peep->destination_y = y;
}
/* rct2: 0x00692D83 */
static void peep_update_ride_sub_state_15(rct_peep* peep){
rct_ride* ride = GET_RIDE(peep->current_ride);
if (ride->type != RIDE_TYPE_SPIRAL_SLIDE)
return;
if ((peep->var_37 & 3) == 0){
switch (peep->destination_x){
case 0:
peep->destination_y++;
if (peep->destination_y >= 30)
peep->destination_x++;
return;
case 1:
if (ride->var_15D != 0)
return;
ride->var_15D++;
ride->slide_peep = peep->sprite_index;
ride->slide_peep_t_shirt_colour = peep->tshirt_colour;
ride->var_176 = 0;
peep->destination_x++;
return;
case 2:
return;
case 3:
{
sint16 x = ride->station_starts[peep->current_ride_station] & 0xFF;
sint16 y = ride->station_starts[peep->current_ride_station] >> 8;
x *= 32;
y *= 32;
uint8 direction = (peep->var_37 / 4) & 3;
sint16 dest_x = x + RCT2_ADDRESS(0x981F1C, sint16)[direction * 2];
sint16 dest_y = y + RCT2_ADDRESS(0x981F1E, sint16)[direction * 2];
peep->destination_x = dest_x;
peep->destination_y = dest_y;
x += RCT2_ADDRESS(0x981F0C, sint16)[direction * 2];
y += RCT2_ADDRESS(0x981F0E, sint16)[direction * 2];
sprite_move(x, y, peep->z, (rct_sprite*)peep);
peep->sprite_direction = (peep->var_37 & 0xC) * 2;
invalidate_sprite((rct_sprite*)peep);
peep->var_37++;
return;
}
default:
return;
}
}
sint16 x, y, xy_distance;
if (peep_update_action(&x, &y, &xy_distance, peep)){
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, peep->z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
peep->var_37 = (peep->var_37 * 4 & 0x30) + 2;
x = ride->station_starts[peep->current_ride_station] & 0xFF;
y = ride->station_starts[peep->current_ride_station] >> 8;
x *= 32;
y *= 32;
sint8* edx = peep->var_37 * 2 + RCT2_ADDRESS(0x97E1BC, sint8*)[ride->type];
x += edx[0];
y += edx[1];
peep->destination_x = x;
peep->destination_y = y;
peep->sub_state = 14;
}
/* rct2: 0x00692C6B */
static void peep_update_ride_sub_state_16(rct_peep* peep){
sint16 x, y, xy_distance;
if (peep_update_action(&x, &y, &xy_distance, peep)){
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, peep->z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
rct_ride* ride = GET_RIDE(peep->current_ride);
if ((peep->var_37 & 0x3) != 0){
if ((peep->var_37 & 0x3) == 3){
peep_update_ride_prepare_for_state_9(peep);
return;
}
peep->var_37--;
x = ride->station_starts[peep->current_ride_station] & 0xFF;
y = ride->station_starts[peep->current_ride_station] >> 8;
x *= 32;
y *= 32;
sint8* edx = peep->var_37 * 2 + RCT2_ADDRESS(0x97E1BC, sint8*)[ride->type];
x += edx[0];
y += edx[1];
peep->destination_x = x;
peep->destination_y = y;
return;
}
peep->var_37 |= 3;
x = ride->exits[peep->current_ride_station] & 0xFF;
y = ride->exits[peep->current_ride_station] >> 8;
sint16 z = ride->station_heights[peep->current_ride_station];
rct_map_element* map_element = ride_get_station_exit_element(ride, x, y, z);
uint8 exit_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK;
exit_direction ^= (1 << 1);
x *= 32;
y *= 32;
x += 16;
y += 16;
sint16 x_shift = RCT2_ADDRESS(0x00981D6C, sint16)[exit_direction * 2];
sint16 y_shift = RCT2_ADDRESS(0x00981D6E, sint16)[exit_direction * 2];
sint16 shift_multiplier = 20;
x_shift *= shift_multiplier;
y_shift *= shift_multiplier;
x -= x_shift;
y -= y_shift;
peep->destination_x = x;
peep->destination_y = y;
}
/* rct2: 0x00692A83 */
static void peep_update_ride_sub_state_17(rct_peep* peep){
sint16 x, y, xy_distance;
if (peep_update_action(&x, &y, &xy_distance, peep)){
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, peep->z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
rct_ride* ride = GET_RIDE(peep->current_ride);
if (peep->var_37 == 16){
peep_update_ride_prepare_for_state_9(peep);
return;
}
if (peep->action >= PEEP_ACTION_NONE_1){
if (peep->energy > 64 &&
(scenario_rand() & 0xFFFF) <= 2427){
peep->action = PEEP_ACTION_JUMP;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
}
}
x = peep->destination_x & 0xFFE0;
y = peep->destination_y & 0xFFE0;
sint16 z = ride->station_heights[0];
// Find the station track element
rct_map_element* mapElement = map_get_first_element_at(x / 32, y / 32);
do {
if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_TRACK && z == mapElement->base_height)
break;
} while (!map_element_is_last_for_tile(mapElement++));
uint16 maze_entry = mapElement->properties.track.maze_entry;
uint16 open_hedges = 0;
uint8 var_37 = peep->var_37;
if (maze_entry & (1 << RCT2_ADDRESS(0x981FF4, uint8)[var_37])){
open_hedges = 1;
}
open_hedges <<= 1;
if (maze_entry & (1 << RCT2_ADDRESS(0x981FF3, uint8)[var_37])){
open_hedges |= 1;
}
open_hedges <<= 1;
if (maze_entry & (1 << RCT2_ADDRESS(0x981FF2, uint8)[var_37])){
open_hedges |= 1;
}
open_hedges <<= 1;
if (maze_entry & (1 << RCT2_ADDRESS(0x981FF1, uint8)[var_37])){
open_hedges |= 1;
}
open_hedges ^= 0xF;
if (open_hedges == 0)
return;
uint8 maze_last_edge = peep->maze_last_edge ^ (1 << 1);
open_hedges &= ~(1 << maze_last_edge);
if (open_hedges == 0)
open_hedges |= (1 << maze_last_edge);
uint8 chosen_edge = scenario_rand() & 0x3;
while (!(open_hedges & (1 << chosen_edge))){
chosen_edge = (chosen_edge + 1) & 3;
}
x = RCT2_ADDRESS(0x993CCC, sint16)[chosen_edge * 2] / 2;
y = RCT2_ADDRESS(0x993CCE, sint16)[chosen_edge * 2] / 2;
x += peep->destination_x;
y += peep->destination_y;
uint8 type = 0;
mapElement = map_get_first_element_at(x / 32, y / 32);
do {
if (z != mapElement->base_height)
continue;
if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_TRACK){
type = 1;
break;
}
if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE &&
mapElement->properties.entrance.type == ENTRANCE_TYPE_RIDE_EXIT){
type = 2;
break;
}
} while (!map_element_is_last_for_tile(mapElement++));
switch (type){
case 0:
peep->maze_last_edge++;
peep->maze_last_edge &= 3;
return;
case 1:
peep->destination_x = x;
peep->destination_y = y;
peep->var_37 = RCT2_ADDRESS(0x981FE1, uint8)[peep->var_37 + chosen_edge];
peep->maze_last_edge = chosen_edge;
break;
case 2:
x = peep->destination_x;
y = peep->destination_y;
if (chosen_edge & 1){
x &= 0xFFE0;
x += 16;
}
else{
y &= 0xFFE0;
y += 16;
}
peep->destination_x = x;
peep->destination_y = y;
peep->var_37 = 16;
peep->maze_last_edge = chosen_edge;
break;
}
if (peep_update_action(&x, &y, &xy_distance, peep)){
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, peep->z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
}
/* rct2: 0x006938D2 */
static void peep_update_ride_sub_state_18(rct_peep* peep){
sint16 x, y, xy_distance;
rct_ride* ride = GET_RIDE(peep->current_ride);
if (peep_update_action(&x, &y, &xy_distance, peep)){
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, ride->station_heights[peep->current_ride_station] * 8, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
RCT2_CALLPROC_X(0x00695444, 0, 0, 0, peep->current_ride | (1 << 8), (int)peep, 0, 0);
if (peep->flags & PEEP_FLAGS_TRACKING){
RCT2_GLOBAL(0x13CE952, uint16) = peep->name_string_idx;
RCT2_GLOBAL(0x13CE954, uint32) = peep->id;
RCT2_GLOBAL(0x13CE958, uint16) = ride->name;
RCT2_GLOBAL(0x13CE95A, uint32) = ride->name_arguments;
news_item_add_to_queue(NEWS_ITEM_PEEP_ON_RIDE, 1934, peep->sprite_index);
}
peep->var_79 = 0xFF;
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
x = peep->x & 0xFFE0;
y = peep->y & 0xFFE0;
// Find the station track element
rct_map_element* mapElement = map_get_first_element_at(x / 32, y / 32);
do {
if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH)
continue;
sint16 z = map_height_from_slope(peep->x, peep->y, mapElement->properties.path.type);
z += mapElement->base_height * 8;
sint16 z_diff = peep->z - z;
if (z_diff > 0 || z_diff < -16)
continue;
sprite_move(peep->x, peep->y, z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
} while (!map_element_is_last_for_tile(mapElement++));
}
/* rct2: 0x0069299C */
static void peep_update_ride_sub_state_19(rct_peep* peep){
sint16 x, y, xy_distance;
if (peep_update_action(&x, &y, &xy_distance, peep)){
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, peep->z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
peep->sub_state++;
}
/* rct2: 0x006929BB */
static void peep_update_ride_sub_state_20(rct_peep* peep){
sint16 x, y;
rct_ride* ride = GET_RIDE(peep->current_ride);
if (ride->type == RIDE_TYPE_FIRST_AID){
if (peep->nausea <= 35){
peep->sub_state++;
x = peep->next_x + 16;
y = peep->next_y + 16;
peep->destination_x = x;
peep->destination_y = y;
peep->destination_tolerence = 3;
peep->happiness_growth_rate = min(peep->happiness_growth_rate + 30, 0xFF);
peep->happiness = peep->happiness_growth_rate;
}
else{
peep->nausea--;
peep->nausea_growth_rate = peep->nausea;
}
return;
}
if (peep->bathroom != 0){
peep->bathroom--;
return;
}
sound_play_panned(SOUND_TOILET_FLUSH, 0x8001, peep->x, peep->y, peep->z);
peep->sub_state++;
x = peep->next_x + 16;
y = peep->next_y + 16;
peep->destination_x = x;
peep->destination_y = y;
peep->destination_tolerence = 3;
peep->happiness_growth_rate = min(peep->happiness_growth_rate + 30, 0xFF);
peep->happiness = peep->happiness_growth_rate;
peep_stop_purchase_thought(peep, ride->type);
}
/* rct2: 0x00692935 */
static void peep_update_ride_sub_state_21(rct_peep* peep){
sint16 x, y, xy_distance;
if (peep_update_action(&x, &y, &xy_distance, peep)){
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, peep->z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
x = peep->x & 0xFFE0;
y = peep->y & 0xFFE0;
if (x != peep->next_x)
return;
if (y != peep->next_y)
return;
}
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_WALKING;
peep_window_state_update(peep);
rct_ride* ride = GET_RIDE(peep->current_ride);
ride->total_customers++;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_CUSTOMER;
RCT2_CALLPROC_X(0x0069A3A2, 0, peep->happiness / 64, 0, 0, 0, peep->current_ride * sizeof(rct_ride), 0);
}
/* rct2: 0x691A30
* Used by entering_ride and queueing_front */
static void peep_update_ride(rct_peep* peep){
switch (peep->sub_state){
case 0:
peep_update_ride_sub_state_0(peep);
break;
case 1:
peep_update_ride_sub_state_1(peep);
break;
case 2:
peep_update_ride_sub_state_2(peep);
break;
case 3:
peep_update_ride_sub_state_1(peep);
break;
case 4:
{
sint16 x, y, xy_distance;
if (!peep_update_action(&x, &y, &xy_distance, peep))
{
peep->sub_state = 5;
break;
}
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, peep->z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
break;
}
case 5:
peep_update_ride_sub_state_5(peep);
break;
case 6:
// No action, on ride.
break;
case 7:
peep_update_ride_sub_state_7(peep);
break;
case 8:
peep_update_ride_sub_state_8(peep);
break;
case 9:
peep_update_ride_sub_state_9(peep);
break;
case 10:
case 11:
assert(false);
break;
case 12:
peep_update_ride_sub_state_12(peep);
break;
case 13:
peep_udpate_ride_sub_state_13(peep);
break;
case 14:
peep_update_ride_sub_state_14(peep);
break;
case 15:
peep_update_ride_sub_state_15(peep);
break;
case 16:
peep_update_ride_sub_state_16(peep);
break;
case 17:
peep_update_ride_sub_state_17(peep);
break;
case 18:
peep_update_ride_sub_state_18(peep);
break;
case 19:
peep_update_ride_sub_state_19(peep);
break;
case 20:
peep_update_ride_sub_state_20(peep);
break;
case 21:
peep_update_ride_sub_state_21(peep);
break;
default:
RCT2_CALLPROC_X(RCT2_ADDRESS(0x9820DC, int)[peep->sub_state], 0, 0, 0, 0, (int)peep, 0, 0);
}
}
/* rct2: 0x006C0E8B
* Also used by inspecting.
*/
static void peep_update_fixing(int steps, rct_peep* peep){
rct_ride* ride = GET_RIDE(peep->current_ride);
if (ride->type == RIDE_TYPE_NULL)
{
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
return;
}
RCT2_CALLPROC_X(RCT2_ADDRESS(0x006C0EB0, uint32)[peep->sub_state], steps, 0, 0, 0, (int)peep, (int)ride, 0);
}
/**
* rct2: 0x69185D
*/
static void peep_update_queuing(rct_peep* peep){
if (!sub_68F3AE(peep)){
remove_peep_from_queue(peep);
return;
}
rct_ride* ride = GET_RIDE(peep->current_ride);
if (ride->status == RIDE_STATUS_CLOSED || ride->status == RIDE_STATUS_TESTING){
remove_peep_from_queue(peep);
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_1;
peep_window_state_update(peep);
return;
}
if (peep->sub_state != 10){
if (peep->next_in_queue == 0xFFFF){
//Happens every time peep goes onto ride.
peep->destination_tolerence = 0;
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_QUEUING_FRONT;
peep_window_state_update(peep);
peep->sub_state = 0;
return;
}
//Give up queueing for the ride
peep->sprite_direction ^= (1 << 4);
invalidate_sprite((rct_sprite*)peep);
remove_peep_from_queue(peep);
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_1;
peep_window_state_update(peep);
return;
}
RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0);
if (peep->action < 0xFE)return;
if (peep->sprite_type == 0){
if (peep->time_in_queue >= 2000 && (0xFFFF & scenario_rand()) <= 119){
// Eat Food/Look at watch
peep->action = PEEP_ACTION_EAT_FOOD;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
}
if (peep->time_in_queue >= 3500 && (0xFFFF & scenario_rand()) <= 93)
{
//Create the ive been waiting in line ages thought
peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_QUEUING_AGES, peep->current_ride);
}
}
else{
if (!(peep->time_in_queue & 0x3F) && peep->action == 0xFE && peep->var_6F == 2){
switch (peep->sprite_type){
case 0xF:
case 0x10:
case 0x11:
case 0x12:
case 0x14:
case 0x16:
case 0x18:
case 0x1F:
case 0x20:
case 0x21:
case 0x22:
case 0x23:
case 0x24:
case 0x25:
case 0x27:
case 0x29:
case 0x2A:
case 0x2B:
case 0x2C:
case 0x2D:
case 0x2E:
case 0x2F:
// Eat food/Look at watch
peep->action = PEEP_ACTION_EAT_FOOD;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
break;
}
}
}
if (peep->time_in_queue < 4300) return;
if (peep->happiness <= 65 && (0xFFFF & scenario_rand()) < 2184){
//Give up queueing for the ride
peep->sprite_direction ^= (1 << 4);
invalidate_sprite((rct_sprite*)peep);
remove_peep_from_queue(peep);
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_1;
peep_window_state_update(peep);
}
}
/* rct2: 0x006BF567 */
static void peep_update_mowing(rct_peep* peep){
peep->var_E2 = 0;
if (!sub_68F3AE(peep))return;
invalidate_sprite((rct_sprite*)peep);
while (1){
sint16 x = 0, y = 0, xy_distance;
if (peep_update_action(&x, &y, &xy_distance, peep)){
int eax = x, ebx, ecx = y, z, ebp, edi;
RCT2_CALLFUNC_X(0x662783, &eax, &ebx, &ecx, &z, (int*)&peep, &edi, &ebp);
x = eax;
y = ecx;
sprite_move(x, y, z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
peep->var_37++;
if (peep->var_37 == 1){
sub_693BE5(peep, 2);
}
if (RCT2_ADDRESS(0x9929C8, uint16)[peep->var_37 * 2] == 0xFFFF){
peep_state_reset(peep);
return;
}
peep->destination_x = RCT2_ADDRESS(0x9929C8, uint16)[peep->var_37 * 2] + peep->next_x;
peep->destination_y = RCT2_ADDRESS(0x9929CA, uint16)[peep->var_37 * 2] + peep->next_y;
if (peep->var_37 != 7)continue;
rct_map_element *map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32);
for (; (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_SURFACE); map_element++);
if ((map_element->properties.surface.terrain & MAP_ELEMENT_SURFACE_TERRAIN_MASK) == (TERRAIN_GRASS << 5)){
map_element->properties.surface.grass_length = 0;
gfx_invalidate_scrollingtext(peep->next_x, peep->next_y, map_element->base_height * 8, map_element->base_height * 8 + 16);
}
peep->staff_lawns_mown++;
peep->var_45 |= (1 << 5);
}
}
/* rct2: 0x006BF7E6 */
static void peep_update_watering(rct_peep* peep){
peep->var_E2 = 0;
if (peep->sub_state == 0){
if (!sub_68F3AE(peep))return;
RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0);
if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return;
peep->sprite_direction = (peep->var_37 & 3) << 3;
peep->action = PEEP_ACTION_STAFF_WATERING;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
peep->sub_state = 1;
}
else if (peep->sub_state == 1){
if (peep->action != PEEP_ACTION_NONE_2){
sint16 x, y, xy_distance;
peep_update_action(&x, &y, &xy_distance, peep);
return;
}
int x = peep->next_x + RCT2_ADDRESS(0x993CCC, sint16)[peep->var_37 * 2];
int y = peep->next_y + RCT2_ADDRESS(0x993CCE, sint16)[peep->var_37 * 2];
rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32);
do{
if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_SCENERY)
continue;
if (abs(((int)peep->next_z) - map_element->base_height) > 4)
continue;
rct_scenery_entry* scenery_entry = g_smallSceneryEntries[map_element->properties.scenery.type];
if (!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_CAN_BE_WATERED))
continue;
map_element->properties.scenery.age = 0;
gfx_invalidate_scrollingtext(x, y, map_element->base_height * 8, map_element->clearance_height * 8);
peep->staff_gardens_watered++;
peep->var_45 |= (1 << 4);
} while (!map_element_is_last_for_tile(map_element++));
peep_state_reset(peep);
}
}
/* rct2: 0x006BF6C9 */
static void peep_update_emptying_bin(rct_peep* peep){
peep->var_E2 = 0;
if (peep->sub_state == 0){
if (!sub_68F3AE(peep))return;
RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0);
if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return;
peep->sprite_direction = (peep->var_37 & 3) << 3;
peep->action = PEEP_ACTION_STAFF_EMPTY_BIN;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
peep->sub_state = 1;
}
else if (peep->sub_state == 1){
if (peep->action == PEEP_ACTION_NONE_2){
peep_state_reset(peep);
return;
}
sint16 x = 0, y = 0, xy_distance;
peep_update_action(&x, &y, &xy_distance, peep);
if (peep->action_frame != 11)return;
rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32);
for (;; map_element++) {
if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_PATH) {
if (peep->next_z == map_element->base_height)
break;
}
if (map_element_is_last_for_tile(map_element)) {
peep_state_reset(peep);
return;
}
}
if ((map_element->properties.path.additions & 0x0F) == 0) {
peep_state_reset(peep);
return;
}
rct_scenery_entry* scenery_entry = g_pathBitSceneryEntries[(map_element->properties.path.additions & 0xF) - 1];
if (
!(scenery_entry->path_bit.var_06 & 1)
|| map_element->flags & (1 << 5)
|| map_element->properties.path.additions & (1 << 7)
) {
peep_state_reset(peep);
return;
}
map_element->properties.path.addition_status |= ((3 << peep->var_37) << peep->var_37);
gfx_invalidate_scrollingtext(peep->next_x, peep->next_y, map_element->base_height * 8, map_element->clearance_height * 8);
peep->staff_bins_emptied++;
peep->var_45 |= (1 << 4);
}
}
/* rct2: 0x6BF641 */
static void peep_update_sweeping(rct_peep* peep){
peep->var_E2 = 0;
if (!sub_68F3AE(peep))return;
invalidate_sprite((rct_sprite*)peep);
if (peep->action == PEEP_ACTION_STAFF_SWEEP && peep->action_frame == 8){
//Remove sick at this location
RCT2_CALLPROC_X(0x6738E1, peep->x, 0, peep->y, peep->z, 0, 0, 0);
peep->staff_litter_swept++;
peep->var_45 |= (1 << 4);
}
sint16 x = 0, y = 0, xy_distance;
if (peep_update_action(&x, &y, &xy_distance, peep)){
int eax = x, ebx, ecx = y, z, ebp, edi;
RCT2_CALLFUNC_X(0x694921, &eax, &ebx, &ecx, &z, (int*)&peep, &edi, &ebp);
x = eax;
y = ecx;
sprite_move(x, y, z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
peep->var_37++;
if (peep->var_37 != 2){
peep->action = PEEP_ACTION_STAFF_SWEEP;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
peep_state_reset(peep);
}
/* rct2: 0x6902A2 */
static void peep_update_1(rct_peep* peep){
if (!sub_68F3AE(peep))return;
peep_decrement_num_riders(peep);
if (peep->type == PEEP_TYPE_GUEST){
peep->state = PEEP_STATE_WALKING;
}
else{
peep->state = PEEP_STATE_PATROLLING;
}
peep_window_state_update(peep);
peep->destination_x = peep->x;
peep->destination_y = peep->y;
peep->destination_tolerence = 10;
peep->var_76 = 0;
peep->var_78 = peep->sprite_direction >> 3;
}
/**
* rct2: 0x690009
*/
static void peep_update_picked(rct_peep* peep){
if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 0x1F) return;
peep->sub_state++;
if (peep->sub_state == 13){
peep_insert_new_thought(peep, PEEP_THOUGHT_HELP, 0xFF);
}
}
/* rct2: 0x6914CD */
static void peep_update_leaving_park(rct_peep* peep){
if (peep->var_37 != 0){
RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0);
if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 2))return;
peep_sprite_remove(peep);
return;
}
sint16 x = 0, y = 0, xy_distance;
if (peep_update_action(&x, &y, &xy_distance, peep)){
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, peep->z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
peep->var_2A = 1;
peep->destination_tolerence = 5;
RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16)--;
RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) |= BTM_TB_DIRTY_FLAG_PEEP_COUNT;
peep->var_37 = 1;
window_invalidate_by_class(WC_GUEST_LIST);
RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0);
if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 2))return;
peep_sprite_remove(peep);
}
/* rct2: 0x6916D6 */
static void peep_update_watching(rct_peep* peep){
if (peep->sub_state == 0){
if (!sub_68F3AE(peep))return;
RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0);
if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return;
peep->destination_x = peep->x;
peep->destination_y = peep->y;
peep->sprite_direction = (peep->var_37 & 3) * 8;
invalidate_sprite((rct_sprite*)peep);
peep->action = 0xFE;
peep->var_6F = 2;
RCT2_CALLPROC_X(0x693BAB, 0, 0, 0, 0, (int)peep, 0, 0);
peep->sub_state++;
peep->time_to_stand = clamp(0, ((129 - peep->energy) * 16 + 50) / 2, 255);
peep_update_sprite_type(peep);
}
else if (peep->sub_state == 1){
if (peep->action < 0xFE){
//6917F6
sint16 x = 0, y = 0, xy_distance;
peep_update_action(&x, &y, &xy_distance, peep);
if (peep->action != 0xFF)return;
peep->action = 0xFE;
}
else{
if (peep_has_food(peep)){
if ((scenario_rand() & 0xFFFF) <= 1310){
peep->action = PEEP_ACTION_EAT_FOOD;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
}
if ((scenario_rand() & 0xFFFF) <= 655){
peep->action = PEEP_ACTION_TAKE_PHOTO;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
if ((peep->standing_flags & 1)){
if ((scenario_rand() & 0xFFFF) <= 655){
peep->action = PEEP_ACTION_WAVE;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
}
}
peep->standing_flags ^= (1 << 7);
if (!(peep->standing_flags & (1 << 7)))return;
peep->time_to_stand--;
if (peep->time_to_stand != 0)return;
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_WALKING;
peep_window_state_update(peep);
peep_update_sprite_type(peep);
// Send peep to the center of current tile.
peep->destination_x = (peep->x & 0xFFE0) + 16;
peep->destination_y = (peep->y & 0xFFE0) + 16;
peep->destination_tolerence = 5;
sub_693B58(peep);
}
}
/**
* rct2: 0x691451
*/
static void peep_update_entering_park(rct_peep* peep){
if (peep->var_37 != 1){
RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0);
if ((RCT2_GLOBAL(0xF1EE18, uint16) & 2)){
RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16)--;
peep_sprite_remove(peep);
}
return;
}
sint16 x = 0, y = 0, xy_distance;
if (peep_update_action(&x, &y, &xy_distance, peep)){
invalidate_sprite((rct_sprite*)peep);
sprite_move(x, y, peep->z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
return;
}
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
peep->var_2A = 0;
peep->time_in_park = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, sint32);
RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16)++;
RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16)--;
RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) |= BTM_TB_DIRTY_FLAG_PEEP_COUNT;
window_invalidate_by_class(WC_GUEST_LIST);
}
/* rct2: 0x00690582*/
static int peep_update_walking_find_bench(rct_peep* peep){
if (!peep_should_find_bench(peep))return 0;
rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32);
for (;; map_element++){
if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_PATH){
if (peep->next_z == map_element->base_height)break;
}
if (map_element_is_last_for_tile(map_element)){
return 0;
}
}
uint8 additions = map_element->properties.path.additions & 0xF;
if (!additions) return 0;
rct_scenery_entry* sceneryEntry = RCT2_ADDRESS(0x9ADA50, rct_scenery_entry*)[additions];
if (!(sceneryEntry->path_bit.var_06 & 0x2))return 0;
if (map_element->flags & MAP_ELEMENT_FLAG_BROKEN)return 0;
if (map_element->properties.path.additions & 0x80)return 0;
int edges = (map_element->properties.path.edges & 0xF) ^ 0xF;
if (edges == 0) return 0;
uint8 chosen_edge = scenario_rand() & 0x3;
for (; !(edges & (1 << chosen_edge));)chosen_edge = (chosen_edge + 1) & 0x3;
uint16 sprite_id = RCT2_ADDRESS(0xF1EF60, uint16)[((peep->x & 0x1FE0) << 3) | (peep->y >> 5)];
uint8 free_edge = 3;
for (rct_sprite* sprite; sprite_id != SPRITE_INDEX_NULL; sprite_id = sprite->unknown.next_in_quadrant){
sprite = &g_sprite_list[sprite_id];
if (sprite->unknown.linked_list_type_offset != SPRITE_LINKEDLIST_OFFSET_PEEP)continue;
if (sprite->peep.state != PEEP_STATE_SITTING)continue;
if (peep->z != sprite->peep.z)continue;
if ((sprite->peep.var_37 & 0x3) != chosen_edge)continue;
free_edge &= ~(1 << ((sprite->peep.var_37 & 0x4) >> 2));
}
if (!free_edge) return 0;
free_edge ^= 0x3;
if (!free_edge){
if (scenario_rand() & 0x8000000) free_edge = 1;
}
peep->var_37 = ((free_edge & 1) << 2) | chosen_edge;
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_SITTING;
peep_window_state_update(peep);
peep->sub_state = 0;
int ebx = peep->var_37 & 0x7;
int x = (peep->x & 0xFFE0) + RCT2_ADDRESS(0x981F2C, uint16)[ebx * 2];
int y = (peep->y & 0xFFE0) + RCT2_ADDRESS(0x981F2E, uint16)[ebx * 2];
peep->destination_x = x;
peep->destination_y = y;
peep->destination_tolerence = 3;
return 1;
}
static int peep_update_walking_find_bin(rct_peep* peep){
if (!peep_has_empty_container(peep)) return 0;
if (peep->next_var_29 & 0x18)return 0;
rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32);
for (;; map_element++){
if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_PATH){
if (peep->next_z == map_element->base_height)break;
}
if (map_element_is_last_for_tile(map_element)){
return 0;
}
}
uint8 additions = map_element->properties.path.additions & 0xF;
if (!additions) return 0;
rct_scenery_entry* sceneryEntry = RCT2_ADDRESS(0x9ADA50, rct_scenery_entry*)[additions];
if (!(sceneryEntry->path_bit.var_06 & 0x1))return 0;
if (map_element->flags & MAP_ELEMENT_FLAG_BROKEN)return 0;
if (map_element->properties.path.additions & 0x80)return 0;
int edges = (map_element->properties.path.edges & 0xF) ^ 0xF;
if (edges == 0) return 0;
uint8 chosen_edge = scenario_rand() & 0x3;
// Note: Bin qunatity is inverted 0 = full, 3 = empty
uint8 bin_quantities = map_element->properties.path.addition_status;
// Rotate the bin to the correct edge. Makes it easier for next calc.
bin_quantities = ror8(ror8(bin_quantities, chosen_edge), chosen_edge);
for (uint8 free_edge = 4; free_edge != 0; free_edge--){
// If not full
if (bin_quantities & 0x3){
if (edges&(1 << chosen_edge))break;
}
chosen_edge = (chosen_edge + 1) & 0x3;
bin_quantities = ror8(bin_quantities, 2);
if ((free_edge - 1) == 0) return 0;
}
peep->var_37 = chosen_edge;
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_USING_BIN;
peep_window_state_update(peep);
peep->sub_state = 0;
int ebx = peep->var_37 & 0x3;
int x = (peep->x & 0xFFE0) + RCT2_ADDRESS(0x992A4C, uint16)[ebx * 2];
int y = (peep->y & 0xFFE0) + RCT2_ADDRESS(0x992A4E, uint16)[ebx * 2];
peep->destination_x = x;
peep->destination_y = y;
peep->destination_tolerence = 3;
return 1;
}
/* rct2: 0x00690848*/
static void peep_update_walking_break_scenery(rct_peep* peep){
if (!(peep->flags & PEEP_FLAGS_ANGRY)){
if (peep->happiness >= 48) return;
if (peep->energy < 85) return;
if (peep->state != PEEP_STATE_WALKING) return;
if ((peep->var_E1 & 0xC0) != 0xC0 &&
(peep->var_E3 & 0xC0) != 0xC0) return;
if ((scenario_rand() & 0xFFFF) > 3276) return;
}
if (peep->next_var_29 & 0x18) return;
rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32);
for (;; map_element++){
if ( map_element_get_type(map_element) == MAP_ELEMENT_TYPE_PATH){
if (peep->next_z == map_element->base_height)break;
}
if (map_element_is_last_for_tile(map_element)){
return;
}
}
uint8 additions = map_element->properties.path.additions & 0xF;
if (!additions) return;
rct_scenery_entry* sceneryEntry = RCT2_ADDRESS(0x9ADA50, rct_scenery_entry*)[additions];
if (!(sceneryEntry->path_bit.var_06 & 0x4))return;
if (map_element->flags & MAP_ELEMENT_FLAG_BROKEN)return;
if (map_element->properties.path.additions & 0x80)return;
int edges = map_element->properties.path.edges & 0xF;
if (edges == 0xF) return;
rct_peep* inner_peep;
uint16 sprite_index;
FOR_ALL_STAFF(sprite_index, inner_peep){
if (inner_peep->staff_type != STAFF_TYPE_SECURITY)continue;
if (inner_peep->x == (sint16)SPRITE_LOCATION_NULL)continue;
int x_diff = abs(inner_peep->x - peep->x);
int y_diff = abs(inner_peep->y - peep->y);
if (max(x_diff, y_diff) < 224)return;
}
map_element->flags |= MAP_ELEMENT_FLAG_BROKEN;
map_invalidate_tile(
peep->next_x,
peep->next_y,
(map_element->base_height << 3) + 32,
map_element->base_height << 3);
peep->var_F3 = 0x10;
return;
}
/* rct2: 0x006912A3 */
static void peep_update_buying(rct_peep* peep)
{
//RCT2_CALLPROC_X(0x006912A3, 0, 0, 0, 0, (int)peep, 0, 0);
//return;
if (!sub_68F3AE(peep))return;
rct_ride* ride = GET_RIDE(peep->current_ride);
if (ride->type == RIDE_TYPE_NULL || ride->status != RIDE_STATUS_OPEN){
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
return;
}
if (peep->sub_state == 1){
if (peep->action != 0xFF){
sint16 x, y, xy_distance;
peep_update_action(&x, &y, &xy_distance, peep);
return;
}
if (ride->type == RIDE_TYPE_ATM){
if (peep->current_ride != peep->previous_ride){
peep->cash_in_pocket += MONEY(50,00);
}
window_invalidate_by_number(WC_PEEP, peep->sprite_index);
}
peep->sprite_direction ^= 0x10;
peep->destination_x = peep->next_x + 16;
peep->destination_y = peep->next_y + 16;
peep->var_78 ^= 2;
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_WALKING;
peep_window_state_update(peep);
return;
}
uint8 item_bought = 0;
if (peep->current_ride != peep->previous_ride){
if (ride->type == RIDE_TYPE_ATM){
item_bought = !(RCT2_CALLPROC_X(0x0069AEB7, peep->current_ride << 8, 0, 0, 0, (int)peep, 0, 0) & 0x100);
if (!item_bought){
peep->previous_ride = peep->current_ride;
peep->previous_ride_time_out = 0;
}
else{
peep->action = PEEP_ACTION_WITHDRAW_MONEY;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
ride->no_primary_items_sold++;
}
}
else{
rct_ride_type* ride_type = gRideTypeList[ride->subtype];
if (ride_type->shop_item_secondary != 0xFF){
money16 price = ride->price_secondary;
item_bought = !(RCT2_CALLPROC_X(0x0069AF1E, ride_type->shop_item_secondary | (peep->current_ride << 8), 0, price, 0, (int)peep, 0, 0) & 0x100);
if (item_bought){
ride->no_secondary_items_sold++;
}
}
if (!item_bought && ride_type->shop_item != 0xFF){
money16 price = ride->price;
item_bought = !(RCT2_CALLPROC_X(0x0069AF1E, ride_type->shop_item | (peep->current_ride << 8), 0, price, 0, (int)peep, 0, 0) & 0x100);
if (item_bought){
ride->no_primary_items_sold++;
}
}
}
}
if (item_bought){
ride_update_popularity(ride, 1);
peep_stop_purchase_thought(peep, ride->type);
}
else{
ride_update_popularity(ride, 0);
}
peep->sub_state = 1;
return;
}
/* rct2: 0x00691089 */
static void peep_update_using_bin(rct_peep* peep){
//RCT2_CALLPROC_X(0x0691089, 0, 0, 0, 0, peep, 0, 0);
//return;
if (peep->sub_state == 0){
if (!sub_68F3AE(peep))return;
RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0);
if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return;
peep->sub_state = 1;
}
else if (peep->sub_state == 1){
if (peep->action != PEEP_ACTION_NONE_2){
sint16 x, y, xy_distance;
peep_update_action(&x, &y, &xy_distance, peep);
return;
}
rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32);
for (;;map_element++){
if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_PATH){
continue;
}
if (map_element->base_height == peep->next_z)break;
if (map_element_is_last_for_tile(map_element)){
peep_state_reset(peep);
return;
}
}
uint8 additions = map_element->properties.path.additions & 0x0F;
if (!additions){
peep_state_reset(peep);
return;
}
rct_scenery_entry* sceneryEntry = RCT2_ADDRESS(0x9ADA50, rct_scenery_entry*)[additions];
if (!(sceneryEntry->path_bit.var_06 & 1)){
peep_state_reset(peep);
return;
}
if (map_element->flags & MAP_ELEMENT_FLAG_BROKEN){
peep_state_reset(peep);
return;
}
if (map_element->properties.path.additions & 0x80){
peep_state_reset(peep);
return;
}
// Bin selection is one of 4 corners
uint8 selected_bin = peep->var_37 * 2;
// This counts down 2 = No rubbish, 0 = full
uint8 rubbish_in_bin = 0x3 & (map_element->properties.path.addition_status >> selected_bin);
uint32 empty_containers = peep_empty_container_standard_flag(peep);
for (uint8 cur_container = 0; cur_container < 32; cur_container++){
if (!(empty_containers & (1 << cur_container))) continue;
if (rubbish_in_bin != 0){
// OpenRCT2 modification: This previously used
// the tick count as a simple random function
// switched to scenario_rand as it is more reliable
if (scenario_rand() & 7) rubbish_in_bin--;
peep->item_standard_flags &= ~(1 << cur_container);
peep->var_45 |= 8;
peep_update_sprite_type(peep);
continue;
}
uint8 bp = RCT2_ADDRESS(0x97EFCC, uint8)[cur_container];
int x, y;
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);
peep->item_standard_flags &= ~(1 << cur_container);
peep->var_45 |= 8;
peep_update_sprite_type(peep);
}
// Original bug: This would clear any rubbish placed by the previous function
//rubbish_in_bin = 0x3 & (map_element->properties.path.addition_status >> selected_bin);
empty_containers = peep_empty_container_extra_flag(peep);
for (uint8 cur_container = 0; cur_container < 32; cur_container++){
if (!(empty_containers & (1 << cur_container))) continue;
if (rubbish_in_bin != 0){
// OpenRCT2 modification: This previously used
// the tick count as a simple random function
// switched to scenario_rand as it is more reliable
if (scenario_rand() & 7) rubbish_in_bin--;
peep->item_extra_flags &= ~(1 << cur_container);
peep->var_45 |= 8;
peep_update_sprite_type(peep);
continue;
}
uint8 bp = RCT2_ADDRESS(0x97EFE8, uint8)[cur_container];
int x, y;
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);
peep->item_extra_flags &= ~(1 << cur_container);
peep->var_45 |= 8;
peep_update_sprite_type(peep);
}
// Place new amount in bin by first clearing the value
map_element->properties.path.addition_status &= ~(3 << selected_bin);
// Then placeing the new value.
map_element->properties.path.addition_status |= rubbish_in_bin << selected_bin;
gfx_invalidate_scrollingtext(peep->next_x, peep->next_y, map_element->base_height << 3, map_element->clearance_height << 3);
peep_state_reset(peep);
}
}
/* rct2: 0x006C16D7 */
static void peep_update_heading_to_inspect(rct_peep* peep){
//RCT2_CALLPROC_X(0x006C16D7, 0, 0, 0, 0, (int)peep, 0, 0);
//return;
rct_ride* ride = GET_RIDE(peep->current_ride);
if (ride->type == RIDE_TYPE_NULL){
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
return;
}
if (ride->exits[peep->current_ride_station] == 0xFFFF){
ride->lifecycle_flags &= ~RIDE_LIFECYCLE_DUE_INSPECTION;
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
return;
}
if (ride->mechanic_status != RIDE_MECHANIC_STATUS_HEADING ||
!(ride->lifecycle_flags & RIDE_LIFECYCLE_DUE_INSPECTION)){
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
return;
}
if (peep->sub_state == 0){
peep->var_74 = 0;
RCT2_CALLPROC_X(0x0069A98C, 0, 0, 0, 0, (int)peep, 0, 0);
peep->sub_state = 2;
}
if (peep->sub_state <= 3){
peep->var_74++;
if (peep->var_74 > 2500){
if (ride->lifecycle_flags & RIDE_LIFECYCLE_DUE_INSPECTION&&
ride->mechanic_status == RIDE_MECHANIC_STATUS_HEADING){
ride->mechanic_status = RIDE_MECHANIC_STATUS_CALLING;
}
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
return;
}
if (!sub_68F3AE(peep))return;
RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0);
if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 0xC))return;
rct_map_element* map_element = RCT2_GLOBAL(0x00F1EE1A, rct_map_element*);
if (peep->current_ride !=
map_element->properties.entrance.ride_index)
return;
uint8 exit_index = ((map_element->properties.entrance.index & 0x70) >> 4);
if (peep->current_ride_station != exit_index)
return;
if (RCT2_GLOBAL(0xF1EE18, uint16)&(1 << 3)){
if (ride->exits[exit_index] != 0xFFFF)return;
}
uint8 direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK;
peep->var_78 = direction;
int x = peep->next_x + 16 + RCT2_ADDRESS(0x00981D6C, sint16)[direction * 2] * 53;
int y = peep->next_y + 16 + RCT2_ADDRESS(0x00981D6E, sint16)[direction * 2] * 53;
peep->destination_x = x;
peep->destination_y = y;
peep->destination_tolerence = 2;
peep->sprite_direction = direction << 3;
peep->z = map_element->base_height * 4;
peep->sub_state = 4;
// Falls through into sub_state 4
}
invalidate_sprite((rct_sprite*)peep);
sint16 delta_y = abs(peep->y - peep->destination_y);
sint16 x, y, xy_distance;
if (!peep_update_action(&x, &y, &xy_distance, peep)){
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_INSPECTING;
peep->sub_state = 0;
peep_window_state_update(peep);
return;
}
int z = ride->station_heights[peep->current_ride_station] * 8;
if (delta_y < 20){
z += RCT2_ADDRESS(0x0097D21C, uint8)[ride->type * 8];
}
sprite_move(x, y, z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
}
/* rct2: 0x006C0CB8 */
static void peep_update_answering(rct_peep* peep){
//RCT2_CALLPROC_X(0x006C0CB8, 0, 0, 0, 0, (int)peep, 0, 0);
//return;
rct_ride* ride = GET_RIDE(peep->current_ride);
if (ride->type == RIDE_TYPE_NULL ||
ride->mechanic_status != RIDE_MECHANIC_STATUS_HEADING){
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
return;
}
if (peep->sub_state == 0){
peep->action = PEEP_ACTION_STAFF_ANSWER_CALL;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
peep->sub_state = 1;
peep_window_state_update(peep);
return;
}
else if (peep->sub_state == 1){
if (peep->action == PEEP_ACTION_NONE_2){
peep->sub_state = 2;
peep_window_state_update(peep);
peep->var_74 = 0;
RCT2_CALLPROC_X(0x0069A98C, 0, 0, 0, 0, (int)peep, 0, 0);
return;
}
sint16 x, y, xy_distance;
peep_update_action(&x, &y, &xy_distance, peep);
return;
}
else if (peep->sub_state <= 3){
peep->var_74++;
if (peep->var_74 > 2500){
if (ride->mechanic_status == RIDE_MECHANIC_STATUS_HEADING){
ride->mechanic_status = RIDE_MECHANIC_STATUS_CALLING;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE;
}
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
return;
}
if (!sub_68F3AE(peep))return;
RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0);
if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 0xC))return;
rct_map_element* map_element = RCT2_GLOBAL(0x00F1EE1A, rct_map_element*);
if (peep->current_ride !=
map_element->properties.entrance.ride_index)
return;
uint8 exit_index = ((map_element->properties.entrance.index & 0x70) >> 4);
if (peep->current_ride_station != exit_index)
return;
if (RCT2_GLOBAL(0xF1EE18, uint16)&(1 << 3)){
if (ride->exits[exit_index] != 0xFFFF)return;
}
uint8 direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK;
peep->var_78 = direction;
int x = peep->next_x + 16 + RCT2_ADDRESS(0x00981D6C, sint16)[direction * 2] * 53;
int y = peep->next_y + 16 + RCT2_ADDRESS(0x00981D6E, sint16)[direction * 2] * 53;
peep->destination_x = x;
peep->destination_y = y;
peep->destination_tolerence = 2;
peep->sprite_direction = direction << 3;
peep->z = map_element->base_height * 4;
peep->sub_state = 4;
// Falls through into sub_state 4
}
invalidate_sprite((rct_sprite*)peep);
sint16 delta_y = abs(peep->y - peep->destination_y);
sint16 x, y, xy_distance;
if (!peep_update_action(&x, &y, &xy_distance, peep)){
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FIXING;
peep->sub_state = 0;
peep_window_state_update(peep);
return;
}
int z = ride->station_heights[peep->current_ride_station] * 8;
if (delta_y < 20){
z += RCT2_ADDRESS(0x0097D21C, uint8)[ride->type * 8];
}
sprite_move(x, y, z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
}
/* rct2: 0x006BF483 */
static int peep_update_patrolling_find_watering(rct_peep* peep){
if (!(peep->staff_orders & STAFF_ORDERS_WATER_FLOWERS))
return 0;
uint8 chosen_position = scenario_rand() & 7;
for (int i = 0; i < 8; ++i, ++chosen_position){
chosen_position &= 7;
int x = peep->next_x + RCT2_ADDRESS(0x00993CCC, sint16)[chosen_position * 2];
int y = peep->next_y + RCT2_ADDRESS(0x00993CCE, sint16)[chosen_position * 2];
rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32);
do {
if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_SCENERY){
continue;
}
uint8 z_diff = abs(peep->next_z - map_element->base_height);
if (z_diff >= 4){
continue;
}
rct_scenery_entry* sceneryEntry = g_smallSceneryEntries[map_element->properties.scenery.type];
if (!(sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_CAN_BE_WATERED)){
continue;
}
if (map_element->properties.scenery.age < 55){
if (chosen_position >= 4){
continue;
}
if (map_element->properties.scenery.age < 40){
continue;
}
}
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_WATERING;
peep->var_37 = chosen_position;
peep_window_state_update(peep);
peep->sub_state = 0;
peep->destination_x = (peep->x & 0xFFE0) + RCT2_ADDRESS(0x992A5C, uint16)[chosen_position * 2];
peep->destination_y = (peep->y & 0xFFE0) + RCT2_ADDRESS(0x992A5E, uint16)[chosen_position * 2];
peep->destination_tolerence = 3;
return 1;
} while (!map_element_is_last_for_tile(map_element++));
}
return 0;
}
/* rct2: 0x006BF3A1 */
static int peep_update_patrolling_find_bin(rct_peep* peep){
if (!(peep->staff_orders & STAFF_ORDERS_EMPTY_BINS))
return 0;
if ((peep->next_var_29 & 0x18) != 0) return 0;
rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32);
if (map_element == NULL)return 0;
for (;; map_element++){
if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_PATH
&& (map_element->base_height == peep->next_z))
break;
if (map_element_is_last_for_tile(map_element))
return 0;
}
uint8 additions = map_element->properties.path.additions & 0xF;
if (additions == 0)return 0;
rct_scenery_entry* sceneryEntry = RCT2_ADDRESS(0x9ADA50, rct_scenery_entry*)[additions];
if (!(sceneryEntry->path_bit.var_06 & 1))
return 0;
if (map_element->flags & MAP_ELEMENT_FLAG_BROKEN)
return 0;
if (map_element->properties.path.additions & 0x80)
return 0;
uint8 bin_positions = map_element->properties.path.edges & 0xF;
uint8 bin_quantity = map_element->properties.path.addition_status;
uint8 chosen_position = 0;
for (; chosen_position < 4; ++chosen_position){
if (!(bin_positions & 1) &&
!(bin_quantity & 3))
break;
bin_positions >>= 1;
bin_quantity >>= 2;
}
if (chosen_position == 4)return 0;
peep->var_37 = chosen_position;
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_EMPTYING_BIN;
peep_window_state_update(peep);
peep->sub_state = 0;
peep->destination_x = (peep->x & 0xFFE0) + RCT2_ADDRESS(0x992A4C, uint16)[chosen_position * 2];
peep->destination_y = (peep->y & 0xFFE0) + RCT2_ADDRESS(0x992A4E, uint16)[chosen_position * 2];
peep->destination_tolerence = 3;
return 1;
}
/* rct2: 0x006BF322 */
static int peep_update_patrolling_find_grass(rct_peep* peep){
if (!(peep->staff_orders & STAFF_ORDERS_MOWING))
return 0;
if (peep->var_E2 < 12)return 0;
if ((peep->next_var_29 & 0x18) != 8) return 0;
rct_map_element* map_element = map_get_surface_element_at(peep->next_x / 32, peep->next_y / 32);
if ((map_element->properties.surface.terrain & MAP_ELEMENT_SURFACE_TERRAIN_MASK) != TERRAIN_GRASS)
return 0;
if (map_element->properties.surface.grass_length < GRASS_LENGTH_CLEAR_1)
return 0;
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_MOWING;
peep_window_state_update(peep);
peep->var_37 = 0;
peep->destination_x = peep->next_x + RCT2_ADDRESS(0x9929CA, uint16)[0 * 2];
peep->destination_y = peep->next_y + RCT2_ADDRESS(0x9929CA, uint16)[0 * 2];
peep->destination_tolerence = 3;
return 1;
}
/* rct2: 0x006BF295 */
static int peep_update_patrolling_find_sweeping(rct_peep* peep){
if (!(peep->staff_orders & STAFF_ORDERS_SWEEPING))
return 0;
uint16 sprite_id = RCT2_ADDRESS(0xF1EF60, uint16)[((peep->x & 0x1FE0) << 3) | (peep->y >> 5)];
for (rct_sprite* sprite = NULL;
sprite_id != 0xFFFF;
sprite_id = sprite->unknown.next_in_quadrant){
sprite = &g_sprite_list[sprite_id];
if (sprite->unknown.linked_list_type_offset != SPRITE_LINKEDLIST_OFFSET_LITTER)continue;
uint16 z_diff = abs(peep->z - sprite->litter.z);
if (z_diff >= 16)continue;
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_SWEEPING;
peep_window_state_update(peep);
peep->var_37 = 0;
peep->destination_x = sprite->litter.x;
peep->destination_y = sprite->litter.y;
peep->destination_tolerence = 5;
return 1;
}
return 0;
}
/* rct2: 0x006BF1FD */
static void peep_update_patrolling(rct_peep* peep){
if (!sub_68F3AE(peep))return;
RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0);
if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return;
if ((peep->next_var_29 & 0x18) == 8){
rct_map_element* map_element = map_get_surface_element_at(peep->next_x / 32, peep->next_y / 32);
if (map_element != NULL){
int water_height = map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK;
if (water_height){
invalidate_sprite((rct_sprite*)peep);
water_height *= 16;
sprite_move(peep->x, peep->y, water_height, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
return;
}
}
}
if (peep->staff_type != STAFF_TYPE_HANDYMAN) return;
if (peep_update_patrolling_find_sweeping(peep))return;
if (peep_update_patrolling_find_grass(peep))return;
if (peep_update_patrolling_find_bin(peep))return;
peep_update_patrolling_find_watering(peep);
}
/* rct2: 0x0069030A */
static void peep_update_walking(rct_peep* peep){
//RCT2_CALLPROC_X(0x0069030A, 0, 0, 0, 0, (int)peep, 0, 0);
//return;
if (!sub_68F3AE(peep))return;
if (peep->flags & PEEP_FLAGS_WAVING){
if (peep->action >= PEEP_ACTION_NONE_1){
if ((0xFFFF & scenario_rand()) < 936){
invalidate_sprite((rct_sprite*)peep);
peep->action = PEEP_ACTION_WAVE_2;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
}
}
}
if (peep->flags & PEEP_FLAGS_PHOTO){
if (peep->action >= PEEP_ACTION_NONE_1){
if ((0xFFFF & scenario_rand()) < 936){
invalidate_sprite((rct_sprite*)peep);
peep->action = PEEP_ACTION_TAKE_PHOTO;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
}
}
}
if (peep->flags & PEEP_FLAGS_PAINTING){
if (peep->action >= PEEP_ACTION_NONE_1){
if ((0xFFFF & scenario_rand()) < 936){
invalidate_sprite((rct_sprite*)peep);
peep->action = PEEP_ACTION_DRAW_PICTURE;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
}
}
}
if (peep->flags & PEEP_FLAGS_LITTER){
if (!(peep->next_var_29 & 0x18)){
if ((0xFFFF & scenario_rand()) <= 4096){
int ebp = (scenario_rand() & 0x3) + 2;
int x = peep->x + (scenario_rand() & 0x7) - 3;
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);
}
}
}
else if (peep_has_empty_container(peep)){
if ((!(peep->next_var_29 & 0x18)) &&
((peep->sprite_index & 0x1FF) == (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 0x1FF))&&
((0xFFFF & scenario_rand()) <= 4096)){
uint8 pos_stnd = 0;
for (int container = peep_empty_container_standard_flag(peep); pos_stnd < 32; pos_stnd++)if (container&(1<<pos_stnd))break;
int bp = 0;
if (pos_stnd != 32){
peep->item_standard_flags &= ~(1 << pos_stnd);
bp = RCT2_ADDRESS(0x97EFCC, uint8)[pos_stnd];
}
else{
uint8 pos_extr = 0;
for (int container = peep_empty_container_extra_flag(peep); pos_extr < 32; pos_extr++)if (container&(1 << pos_extr))break;
peep->item_extra_flags &= ~(1 << pos_extr);
bp = RCT2_ADDRESS(0x97EFE8, uint8)[pos_extr];
}
peep->var_45 |= 8;
peep_update_sprite_type(peep);
int x = peep->x + (scenario_rand() & 0x7) - 3;
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);
}
}
RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0);
if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return;
if ((peep->next_var_29 & 0x18) == 8){
rct_map_element* map_element = map_get_surface_element_at(peep->next_x / 32, peep->next_y / 32);
int water_height = map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK;
if (water_height){
invalidate_sprite((rct_sprite*)peep);
water_height *= 16;
sprite_move(peep->x, peep->y, water_height, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_FALLING;
peep_window_state_update(peep);
return;
}
}
peep_check_if_lost(peep);
peep_check_cant_find_ride(peep);
peep_check_cant_find_exit(peep);
if (peep_update_walking_find_bench(peep))return;
if (peep_update_walking_find_bin(peep))return;
peep_update_walking_break_scenery(peep);
if (peep->state != PEEP_STATE_WALKING)return;
if (peep->flags & PEEP_FLAGS_LEAVING_PARK)return;
if (peep->nausea > 140)return;
if (peep->happiness < 120)return;
if (peep->bathroom > 140)return;
uint16 chance = peep_has_food(peep) ? 13107 : 2849;
if ((scenario_rand() & 0xFFFF) > chance)return;
if (peep->next_var_29 & 0x1C)return;
rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32);
for (;; map_element++){
if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_PATH){
if (peep->next_z == map_element->base_height)break;
}
if (map_element_is_last_for_tile(map_element)){
return;
}
}
uint8 additions = map_element->properties.path.additions & 0xF;
int ebp = 15;
if (additions){
if (!(map_element->properties.path.additions & 0x80)){
rct_scenery_entry* sceneryEntry = RCT2_ADDRESS(0x9ADA50, rct_scenery_entry*)[additions];
if (!(sceneryEntry->path_bit.var_06 & 0x2)) ebp = 9;
}
}
int edges = (map_element->properties.path.edges & 0xF) ^ 0xF;
if (edges == 0) return;
uint8 chosen_edge = scenario_rand() & 0x3;
for (; !(edges & (1 << chosen_edge));)chosen_edge = (chosen_edge + 1) & 3;
uint8 ride_to_view;
uint8 ride_seat_to_view;
{
int eax = chosen_edge, _ebx = 0, ecx, edx = 0, esi = (int)peep, _ebp = 0, edi = 0;
// Work out what to look at
if (RCT2_CALLFUNC_X(0x00690B99, &eax, &_ebx, &ecx, &edx, &esi, &edi, &_ebp) & 0x100)return;
ride_to_view = ecx & 0xFF;
ride_seat_to_view = (ecx & 0xFF00) >> 8;
}
uint16 sprite_id = RCT2_ADDRESS(0xF1EF60, uint16)[((peep->x & 0x1FE0) << 3) | (peep->y >> 5)];
for (rct_sprite* sprite; sprite_id != SPRITE_INDEX_NULL; sprite_id = sprite->unknown.next_in_quadrant){
sprite = &g_sprite_list[sprite_id];
if (sprite->unknown.linked_list_type_offset != SPRITE_LINKEDLIST_OFFSET_PEEP)continue;
if (sprite->peep.state != PEEP_STATE_WATCHING)continue;
if (peep->z != sprite->peep.z)continue;
if ((sprite->peep.var_37 & 0x3) != chosen_edge)continue;
ebp &= ~(1 << ((sprite->peep.var_37 & 0x1C) >> 2));
}
if (!ebp)return;
uint8 chosen_position = scenario_rand() & 0x3;
for (; !(ebp & (1 << chosen_position));)chosen_position = (chosen_position + 1) & 3;
peep->current_ride = ride_to_view;
peep->current_seat = ride_seat_to_view;
peep->var_37 = chosen_edge | (chosen_position << 2);
peep_decrement_num_riders(peep);
peep->state = PEEP_STATE_WATCHING;
peep_window_state_update(peep);
peep->sub_state = 0;
int ebx = peep->var_37 & 0x1F;
int x = (peep->x & 0xFFE0) + RCT2_ADDRESS(0x981F4C, uint16)[ebx * 2];
int y = (peep->y & 0xFFE0) + RCT2_ADDRESS(0x981F4E, uint16)[ebx * 2];
peep->destination_x = x;
peep->destination_y = y;
peep->destination_tolerence = 3;
if (peep->current_seat&1){
peep_insert_new_thought(peep, PEEP_THOUGHT_NEW_RIDE, 0xFF);
}
if (peep->current_ride == 0xFF){
peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_SCENERY, 0xFF);
}
}
/* From peep_update */
static void peep_update_thoughts(rct_peep* peep){
// Thoughts must always have a gap of at least
// 220 ticks in age between them. In order to
// allow this when a thought is new it enters
// a holding zone. Before it becomes fresh.
int add_fresh = 1;
int fresh_thought = -1;
for (int i = 0; i < PEEP_MAX_THOUGHTS; i++) {
if (peep->thoughts[i].type == PEEP_THOUGHT_TYPE_NONE)
break;
if (peep->thoughts[i].var_2 == 1) {
add_fresh = 0;
// If thought is fresh we wait 220 ticks
// before allowing a new thought to become fresh.
if (++peep->thoughts[i].var_3 >= 220) {
peep->thoughts[i].var_3 = 0;
// Thought is no longer fresh
peep->thoughts[i].var_2++;
add_fresh = 1;
}
}
else if (peep->thoughts[i].var_2 > 1) {
if (++peep->thoughts[i].var_3 == 0) {
// When thought is older than ~6900 ticks remove it
if (++peep->thoughts[i].var_2 >= 28) {
peep->var_45 |= 1;
// Clear top thought, push others up
memmove(&peep->thoughts[i], &peep->thoughts[i + 1], sizeof(rct_peep_thought)*(PEEP_MAX_THOUGHTS - i - 1));
peep->thoughts[PEEP_MAX_THOUGHTS - 1].type = PEEP_THOUGHT_TYPE_NONE;
}
}
}
else {
fresh_thought = i;
}
}
// If there are no fresh thoughts
// a previously new thought can become
// fresh.
if (add_fresh && fresh_thought != -1) {
peep->thoughts[fresh_thought].var_2 = 1;
peep->var_45 |= 1;
}
}
/**
*
* rct2: 0x0068FC1E
*/
static void peep_update(rct_peep *peep)
{
//RCT2_CALLPROC_X(0x0068FC1E, 0, 0, 0, 0, (int)peep, 0, 0); return;
//return;
if (peep->type == PEEP_TYPE_GUEST) {
if (peep->previous_ride != 255)
if (++peep->previous_ride_time_out >= 720)
peep->previous_ride = 255;
peep_update_thoughts(peep);
}
// Walking speed logic
unsigned int stepsToTake = peep->energy;
if (stepsToTake < 95 && peep->state == PEEP_STATE_QUEUING)
stepsToTake = 95;
if ((peep->flags & PEEP_FLAGS_SLOW_WALK) && peep->state != PEEP_STATE_QUEUING)
stepsToTake /= 2;
if (peep->action == 255 && (peep->next_var_29 & 4)) {
stepsToTake /= 2;
if (peep->state == PEEP_STATE_QUEUING)
stepsToTake += stepsToTake / 2;
}
unsigned int carryCheck = peep->var_73 + stepsToTake;
peep->var_73 = carryCheck;
if (carryCheck <= 255) {
// loc_68FD3A
RCT2_CALLPROC_X(0x0068FD3A, 0, 0, 0, 0, (int)peep, 0, 0);
} else {
// loc_68FD2F
//RCT2_CALLPROC_X(0x68FD2F, 0, 0, 0, 0, (int)peep, 0, 0);
//return;
switch (peep->state) {
case PEEP_STATE_FALLING:
peep_update_falling(peep);
break;
case PEEP_STATE_1:
peep_update_1(peep);
break;
case PEEP_STATE_QUEUING_FRONT:
peep_update_ride(peep);
break;
case PEEP_STATE_ON_RIDE:
// No action
break;
case PEEP_STATE_LEAVING_RIDE:
peep_update_ride(peep);
break;
case PEEP_STATE_WALKING:
peep_update_walking(peep);
break;
case PEEP_STATE_QUEUING:
peep_update_queuing(peep);
break;
case PEEP_STATE_ENTERING_RIDE:
peep_update_ride(peep);
break;
case PEEP_STATE_SITTING:
peep_update_sitting(peep);
break;
case PEEP_STATE_PICKED:
peep_update_picked(peep);
break;
case PEEP_STATE_PATROLLING:
peep_update_patrolling(peep);
break;
case PEEP_STATE_MOWING:
peep_update_mowing(peep);
break;
case PEEP_STATE_SWEEPING:
peep_update_sweeping(peep);
break;
case PEEP_STATE_ENTERING_PARK:
peep_update_entering_park(peep);
break;
case PEEP_STATE_LEAVING_PARK:
peep_update_leaving_park(peep);
break;
case PEEP_STATE_ANSWERING:
peep_update_answering(peep);
break;
case PEEP_STATE_FIXING:
peep_update_fixing(stepsToTake, peep);
break;
case PEEP_STATE_BUYING:
peep_update_buying(peep);
break;
case PEEP_STATE_WATCHING:
peep_update_watching(peep);
break;
case PEEP_STATE_EMPTYING_BIN:
peep_update_emptying_bin(peep);
break;
case PEEP_STATE_USING_BIN:
peep_update_using_bin(peep);
break;
case PEEP_STATE_WATERING:
peep_update_watering(peep);
break;
case PEEP_STATE_HEADING_TO_INSPECTION:
peep_update_heading_to_inspect(peep);
break;
case PEEP_STATE_INSPECTING:
peep_update_fixing(stepsToTake, peep);
break;
//There shouldnt be any more
default:
assert(0);
break;
}
}
}
/**
*
* rct2: 0x0069BF41
**/
void peep_problem_warnings_update()
{
rct_peep* peep;
rct_ride* ride;
uint16 spriteIndex;
uint16 guests_in_park = RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16);
int hunger_counter = 0, lost_counter = 0, noexit_counter = 0, thirst_counter = 0,
litter_counter = 0, disgust_counter = 0, bathroom_counter = 0 ,vandalism_counter = 0;
static int warning_throttle[7] = { 0, 0, 0, 0, 0, 0, 0 };
RCT2_GLOBAL(RCT2_ADDRESS_RIDE_COUNT, sint16) = ride_get_count(); // refactor this to somewhere else
FOR_ALL_GUESTS(spriteIndex, peep) {
if (peep->var_2A != 0 || peep->thoughts[0].var_2 > 5)
continue;
switch (peep->thoughts[0].type) {
case PEEP_THOUGHT_TYPE_LOST: //0x10
lost_counter++;
break;
case PEEP_THOUGHT_TYPE_HUNGRY: // 0x14
if (peep->guest_heading_to_ride_id == -1){
hunger_counter++;
break;
}
ride = &g_ride_list[peep->guest_heading_to_ride_id];
if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_SELLS_FOOD))
hunger_counter++;
break;
case PEEP_THOUGHT_TYPE_THIRSTY:
if (peep->guest_heading_to_ride_id == -1){
thirst_counter++;
break;
}
ride = &g_ride_list[peep->guest_heading_to_ride_id];
if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_SELLS_DRINKS))
thirst_counter++;
break;
case PEEP_THOUGHT_TYPE_BATHROOM:
if (peep->guest_heading_to_ride_id == -1){
bathroom_counter++;
break;
}
ride = &g_ride_list[peep->guest_heading_to_ride_id];
if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_BATHROOM))
bathroom_counter++;
break;
case PEEP_THOUGHT_TYPE_BAD_LITTER: // 0x1a
litter_counter++;
break;
case PEEP_THOUGHT_TYPE_CANT_FIND_EXIT: // 0x1b
noexit_counter++;
break;
case PEEP_THOUGHT_TYPE_PATH_DISGUSTING: // 0x1f
disgust_counter++;
break;
case PEEP_THOUGHT_TYPE_VANDALISM: //0x21
vandalism_counter++;
break;
default:
break;
}
}
// could maybe be packed into a loop, would lose a lot of clarity though
if (warning_throttle[0])
--warning_throttle[0];
else if ( hunger_counter >= PEEP_HUNGER_WARNING_THRESHOLD && hunger_counter >= guests_in_park / 16) {
warning_throttle[0] = 4;
news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_ARE_HUNGRY, 20);
}
if (warning_throttle[1])
--warning_throttle[1];
else if (thirst_counter >= PEEP_THIRST_WARNING_THRESHOLD && thirst_counter >= guests_in_park / 16) {
warning_throttle[1] = 4;
news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_ARE_THIRSTY, 21);
}
if (warning_throttle[2])
--warning_throttle[2];
else if (bathroom_counter >= PEEP_BATHROOM_WARNING_THRESHOLD && bathroom_counter >= guests_in_park / 16) {
warning_throttle[2] = 4;
news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_CANT_FIND_BATHROOM, 22);
}
if (warning_throttle[3])
--warning_throttle[3];
else if (litter_counter >= PEEP_LITTER_WARNING_THRESHOLD && litter_counter >= guests_in_park / 32) {
warning_throttle[3] = 4;
news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_DISLIKE_LITTER, 26);
}
if (warning_throttle[4])
--warning_throttle[4];
else if (disgust_counter >= PEEP_DISGUST_WARNING_THRESHOLD && disgust_counter >= guests_in_park / 32) {
warning_throttle[4] = 4;
news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_DISGUSTED_BY_PATHS, 31);
}
if (warning_throttle[5])
--warning_throttle[5];
else if (vandalism_counter >= PEEP_VANDALISM_WARNING_THRESHOLD && vandalism_counter >= guests_in_park / 32) {
warning_throttle[5] = 4;
news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_DISLIKE_VANDALISM, 33);
}
if (warning_throttle[6])
--warning_throttle[6];
else if (noexit_counter >= PEEP_NOEXIT_WARNING_THRESHOLD) {
warning_throttle[6] = 4;
news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_GETTING_LOST_OR_STUCK, 27);
} else if (lost_counter >= PEEP_LOST_WARNING_THRESHOLD) {
warning_throttle[6] = 4;
news_item_add_to_queue(NEWS_ITEM_PEEPS, STR_PEEPS_GETTING_LOST_OR_STUCK, 16);
}
}
/**
*
* rct2: 0x006BD18A
*/
void peep_update_crowd_noise()
{
rct_viewport *viewport;
uint16 spriteIndex;
rct_peep *peep;
int visiblePeeps;
if (!(RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0)))
return;
if (RCT2_GLOBAL(0x009AF59C, uint8) != 0)
return;
if (!(RCT2_GLOBAL(0x009AF59D, uint8) & (1 << 0)))
return;
if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2)
return;
viewport = RCT2_GLOBAL(0x00F438A4, rct_viewport*);
if (viewport == (rct_viewport*)-1)
return;
// Count the number of peeps visible
visiblePeeps = 0;
FOR_ALL_GUESTS(spriteIndex, peep) {
if (peep->sprite_left == (sint16)0x8000)
continue;
if (viewport->view_x > peep->sprite_right)
continue;
if (viewport->view_x + viewport->view_width < peep->sprite_left)
continue;
if (viewport->view_y > peep->sprite_bottom)
continue;
if (viewport->view_y + viewport->view_height < peep->sprite_top)
continue;
visiblePeeps += peep->state == PEEP_STATE_QUEUING ? 1 : 2;
}
// This function doesn't account for the fact that the screen might be so big that 100 peeps could potentially be very
// spread out and therefore not produce any crowd noise. Perhaps a more sophisticated solution would check how many peeps
// were in close proximity to each other.
// Allows queuing peeps to make half as much noise, and at least 6 peeps must be visible for any crowd noise
visiblePeeps = (visiblePeeps / 2) - 6;
if (visiblePeeps < 0) {
// Mute crowd noise
if (RCT2_GLOBAL(0x009AF5FC, uint32) != 1) {
#ifdef USE_MIXER
Mixer_Stop_Channel(gCrowdSoundChannel);
gCrowdSoundChannel = 0;
#else
sound_channel_stop(2); //RCT2_CALLPROC_1(0x00401A05, int, 2);
#endif
RCT2_GLOBAL(0x009AF5FC, uint32) = 1;
}
} else {
sint32 volume;
// Formula to scale peeps to dB where peeps [0, 120] scales approximately logarithmically to [-3314, -150] dB/100
// 207360000 maybe related to DSBVOLUME_MIN which is -10,000 (dB/100)
volume = 120 - min(visiblePeeps, 120);
volume = volume * volume * volume * volume;
volume = (((207360000 - volume) >> viewport->zoom) - 207360000) / 65536 - 150;
// Check if crowd noise is already playing
if (RCT2_GLOBAL(0x009AF5FC, uint32) == 1) {
// Load and play crowd noise
#ifdef USE_MIXER
if (!gCrowdSoundChannel) {
gCrowdSoundChannel = Mixer_Play_Music(PATH_ID_CSS2);
}
if (gCrowdSoundChannel) {
Mixer_Channel_Volume(gCrowdSoundChannel, DStoMixerVolume(volume));
RCT2_GLOBAL(0x009AF5FC, uint32) = volume;
}
#else
if (sound_channel_load_file2(2, (char*)get_file_path(PATH_ID_CSS2), 0)) {
sound_channel_play(2, 1, volume, 0, 0);
RCT2_GLOBAL(0x009AF5FC, uint32) = volume;
}
#endif
} else {
// Alter crowd noise volume
if (RCT2_GLOBAL(0x009AF5FC, uint32) != volume) {
#ifdef USE_MIXER
Mixer_Channel_Volume(gCrowdSoundChannel, DStoMixerVolume(volume));
#else
sound_channel_set_volume(2, volume);//RCT2_CALLPROC_2(0x00401AD3, int, int, 2, volume);
#endif
RCT2_GLOBAL(0x009AF5FC, uint32) = volume;
}
}
}
}
/**
*
* rct2: 0x0069BE9B
*/
void peep_applause()
{
uint16 spriteIndex;
rct_peep* peep;
FOR_ALL_GUESTS(spriteIndex, peep) {
if (peep->var_2A != 0)
continue;
// Release balloon
if (peep->item_standard_flags & PEEP_ITEM_BALLOON) {
peep->item_standard_flags &= ~PEEP_ITEM_BALLOON;
if (peep->x != 0x8000) {
create_balloon(peep->x, peep->y, peep->z + 9, peep->balloon_colour, 0);
peep->var_45 |= 8;
peep_update_sprite_type(peep);
}
}
// Clap
if ((peep->state == PEEP_STATE_WALKING || peep->state == PEEP_STATE_QUEUING) && peep->action >= 254) {
peep->action = PEEP_ACTION_CLAP;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
}
}
// Play applause noise
sound_play_panned(SOUND_APPLAUSE, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2, 0, 0, 0);
}
/**
*
* rct2: 0x0069C35E
*/
void peep_update_days_in_queue()
{
uint16 sprite_index;
rct_peep *peep;
FOR_ALL_GUESTS(sprite_index, peep) {
if (peep->var_2A == 0 && peep->state == PEEP_STATE_QUEUING) {
if (peep->days_in_queue < 255) {
peep->days_in_queue += 1;
}
}
}
}
/**
*
* rct2: 0x0069A05D
*/
rct_peep *peep_generate(int x, int y, int z)
{
//int eax, ebx, ecx, _edx, esi, edi, ebp;
//eax = x;
//ecx = y;
//_edx = z;
//RCT2_CALLFUNC_X(0x0069A05D, &eax, &ebx, &ecx, &_edx, &esi, &edi, &ebp);
//return (rct_peep*)esi;
if (RCT2_GLOBAL(0x13573C8, uint16) < 400)
return NULL;
rct_peep* peep = (rct_peep*)create_sprite(1);
move_sprite_to_list((rct_sprite*)peep, SPRITE_LINKEDLIST_OFFSET_PEEP);
peep->sprite_identifier = 1;
peep->sprite_type = 0;
peep->var_2A = 1;
peep->state = PEEP_STATE_FALLING;
peep->action = PEEP_ACTION_NONE_2;
peep->var_6D = 0;
peep->action_sprite_image_offset = 0;
peep->no_action_frame_no = 0;
peep->action_sprite_type = 0;
peep->flags = 0;
peep->favourite_ride = 0xFF;
peep->var_FA = 0;
uint8* edx = RCT2_ADDRESS(0x98270C, uint8*)[peep->sprite_type * 2];
peep->sprite_width = edx[peep->action_sprite_type * 4];
peep->sprite_height_negative = edx[peep->action_sprite_type * 4 + 1];
peep->sprite_height_positive = edx[peep->action_sprite_type * 4 + 2];
peep->sprite_direction = 0;
sprite_move(x, y, z, (rct_sprite*)peep);
invalidate_sprite((rct_sprite*)peep);
peep->var_41 = (scenario_rand() & 0x1F) + 45;
peep->var_C4 = 0;
peep->var_79 = 0xFF;
peep->type = PEEP_TYPE_GUEST;
peep->previous_ride = 0xFF;
peep->thoughts->type = PEEP_THOUGHT_TYPE_NONE;
peep->var_45 = 0;
uint8 al = (scenario_rand() & 0x7) + 3;
uint8 ah = min(al, 7) - 3;
if (al >= 7) al = 15;
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PREF_LESS_INTENSE_RIDES){
ah = 0;
al = 4;
}
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PREF_MORE_INTENSE_RIDES){
ah = 9;
al = 15;
}
peep->intensity = (al << 4) | ah;
uint8 nausea_tolerance = scenario_rand() & 0x7;
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PREF_MORE_INTENSE_RIDES){
nausea_tolerance += 4;
}
peep->nausea_tolerance = RCT2_ADDRESS(0x009823A0, uint8)[nausea_tolerance];
sint8 happiness = (scenario_rand() & 0x1F) - 15 + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8);
if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8) == 0)
happiness += 0x80;
peep->happiness = happiness;
peep->happiness_growth_rate = happiness;
peep->nausea = 0;
peep->nausea_growth_rate = 0;
sint8 hunger = (scenario_rand() & 0x1F) - 15 + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HUNGER, uint8);
peep->hunger = hunger;
sint8 thirst = (scenario_rand() & 0x1F) - 15 + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_THIRST, uint8);
peep->thirst = thirst;
peep->bathroom = 0;
peep->var_42 = 0;
memset(&peep->rides_been_on, 0, 32);
peep->no_of_rides = 0;
memset(&peep->var_48, 0, 16);
peep->id = RCT2_GLOBAL(0x013B0E6C, uint32)++;
peep->name_string_idx = 767;
money32 cash = (scenario_rand() & 0x3) * 100 - 100 + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16);
if (cash < 0) cash = 0;
if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) == 0){
cash = 500;
}
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY){
cash = 0;
}
if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) == 0xFFFF){
cash = 0;
}
peep->cash_in_pocket = cash;
peep->cash_spent = 0;
peep->time_in_park = -1;
peep->var_CC = 0xFFFF;
peep->item_standard_flags = 0;
peep->item_extra_flags = 0;
peep->guest_heading_to_ride_id = 0xFF;
peep->var_E1 = 0;
peep->var_E3 = 0;
peep->var_EF = 0;
peep->paid_to_enter = 0;
peep->paid_on_rides = 0;
peep->paid_on_food = 0;
peep->paid_on_drink = 0;
peep->paid_on_souvenirs = 0;
peep->no_of_food = 0;
peep->no_of_drinks = 0;
peep->no_of_souvenirs = 0;
peep->var_F2 = 0;
peep->var_F3 = 0;
peep->var_F4 = 0;
uint8 tshirt_colour = scenario_rand() % 33;
peep->tshirt_colour = RCT2_ADDRESS(0x009823D5, uint8)[tshirt_colour];
uint8 trousers_colour = scenario_rand() % 25;
peep->trousers_colour = RCT2_ADDRESS(0x009823BC, uint8)[trousers_colour];
uint8 energy = (scenario_rand() & 0x3F) + 65;
peep->energy = energy;
peep->energy_growth_rate = energy;
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_SHOW_REAL_GUEST_NAMES){
RCT2_CALLPROC_X(0x0069C483, 0, 0, 0, 0, (int)peep, 0, 0);
}
RCT2_CALLPROC_X(0x00699115, 0, 0, 0, 0, (int)peep, 0, 0);
RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16)++;
return peep;
}
/**
* rct2: 0x00698B0D
* peep.sprite_index (eax)
* thought.type (ebx)
* argument_1 (ecx & ebx)
* argument_2 (edx)
*/
void get_arguments_from_action(rct_peep* peep, uint32 *argument_1, uint32* argument_2){
rct_ride ride;
switch (peep->state){
case PEEP_STATE_FALLING:
*argument_1 = peep->action == PEEP_ACTION_DROWNING ? STR_DROWNING : STR_WALKING;
*argument_2 = 0;
break;
case PEEP_STATE_1:
*argument_1 = STR_WALKING;
*argument_2 = 0;
break;
case PEEP_STATE_ON_RIDE:
case PEEP_STATE_LEAVING_RIDE:
case PEEP_STATE_ENTERING_RIDE:
*argument_1 = STR_ON_RIDE;
ride = g_ride_list[peep->current_ride];
if (ride_type_has_flag(ride.type, RIDE_TYPE_FLAG_IN_RIDE))
*argument_1 = STR_IN_RIDE;
*argument_1 |= (ride.name << 16);
*argument_2 = ride.name_arguments;
break;
case PEEP_STATE_BUYING:
ride = g_ride_list[peep->current_ride];
*argument_1 = STR_AT_RIDE | (ride.name << 16);
*argument_2 = ride.name_arguments;
break;
case PEEP_STATE_WALKING:
case PEEP_STATE_USING_BIN:
if (peep->guest_heading_to_ride_id != 0xFF){
ride = g_ride_list[peep->guest_heading_to_ride_id];
*argument_1 = STR_HEADING_FOR | (ride.name << 16);
*argument_2 = ride.name_arguments;
}
else{
*argument_1 = peep->flags & PEEP_FLAGS_LEAVING_PARK ? STR_LEAVING_PARK : STR_WALKING;
*argument_2 = 0;
}
break;
case PEEP_STATE_QUEUING_FRONT:
case PEEP_STATE_QUEUING:
ride = g_ride_list[peep->current_ride];
*argument_1 = STR_QUEUING_FOR | (ride.name << 16);
*argument_2 = ride.name_arguments;
break;
case PEEP_STATE_SITTING:
*argument_1 = STR_SITTING;
*argument_2 = 0;
break;
case PEEP_STATE_WATCHING:
if (peep->current_ride != 0xFF){
ride = g_ride_list[peep->current_ride];
*argument_1 = STR_WATCHING_RIDE | (ride.name << 16);
*argument_2 = ride.name_arguments;
if (peep->current_seat & 0x1)
*argument_1 = STR_WATCHING_CONSTRUCTION_OF | (ride.name << 16);
else
*argument_1 = STR_WATCHING_RIDE | (ride.name << 16);
}
else{
*argument_1 = peep->current_seat & 0x1 ? STR_WATCHING_NEW_RIDE_BEING_CONSTRUCTED : STR_LOOKING_AT_SCENERY;
*argument_2 = 0;
}
break;
case PEEP_STATE_PICKED:
*argument_1 = STR_SELECT_LOCATION;
*argument_2 = 0;
break;
case PEEP_STATE_PATROLLING:
case PEEP_STATE_ENTERING_PARK:
case PEEP_STATE_LEAVING_PARK:
*argument_1 = STR_WALKING;
*argument_2 = 0;
break;
case PEEP_STATE_MOWING:
*argument_1 = STR_MOWING_GRASS;
*argument_2 = 0;
break;
case PEEP_STATE_SWEEPING:
*argument_1 = STR_SWEEPING_FOOTPATH;
*argument_2 = 0;
break;
case PEEP_STATE_WATERING:
*argument_1 = STR_WATERING_GARDENS;
*argument_2 = 0;
break;
case PEEP_STATE_EMPTYING_BIN:
*argument_1 = STR_EMPTYING_LITTER_BIN;
*argument_2 = 0;
break;
case PEEP_STATE_ANSWERING:
if (peep->sub_state == 0){
*argument_1 = STR_WALKING;
*argument_2 = 0;
}
else if (peep->sub_state == 1){
*argument_1 = STR_ANSWERING_RADIO_CALL;
*argument_2 = 0;
}
else{
ride = g_ride_list[peep->current_ride];
*argument_1 = STR_RESPONDING_TO_RIDE_BREAKDOWN_CALL | (ride.name << 16);
*argument_2 = ride.name_arguments;
}
break;
case PEEP_STATE_FIXING:
ride = g_ride_list[peep->current_ride];
*argument_1 = STR_FIXING_RIDE | (ride.name << 16);
*argument_2 = ride.name_arguments;
break;
case PEEP_STATE_HEADING_TO_INSPECTION:
ride = g_ride_list[peep->current_ride];
*argument_1 = STR_HEADING_TO_RIDE_FOR_INSPECTION | (ride.name << 16);
*argument_2 = ride.name_arguments;
break;
case PEEP_STATE_INSPECTING:
ride = g_ride_list[peep->current_ride];
*argument_1 = STR_INSPECTING_RIDE | (ride.name << 16);
*argument_2 = ride.name_arguments;
break;
}
}
/**
* rct2: 0x00698342
* thought.item (eax)
* thought.type (ebx)
* argument_1 (esi & ebx)
* argument_2 (esi+2)
*/
void get_arguments_from_thought(rct_peep_thought thought, uint32* argument_1, uint32* argument_2){
int esi = 0x9AC86C;
if ((RCT2_ADDRESS(0x981DB1, uint16)[thought.type] & 0xFF) & 1){
rct_ride* ride = &g_ride_list[thought.item];
esi = (int)(&(ride->name));
}
else if ((RCT2_ADDRESS(0x981DB1, uint16)[thought.type] & 0xFF) & 2){
if (thought.item < 0x20){
RCT2_GLOBAL(0x9AC86C, uint16) = thought.item + STR_ITEM_START;
}
else{
RCT2_GLOBAL(0x9AC86C, uint16) = thought.item + STR_ITEM2_START;
}
}
else if ((RCT2_ADDRESS(0x981DB1, uint16)[thought.type] & 0xFF) & 4){
if (thought.item < 0x20){
RCT2_GLOBAL(0x9AC86C, uint16) = thought.item + STR_ITEM_SINGULAR_START;
}
else
{
RCT2_GLOBAL(0x9AC86C, uint16) = thought.item + STR_ITEM2_SINGULAR_START;
}
}
else{
esi = 0x9AC864; //No thought?
}
*argument_1 = ((thought.type + STR_THOUGHT_START) & 0xFFFF) | (*((uint16*)esi) << 16);
*argument_2 = *((uint32*)(esi + 2)); //Always 0 apart from on rides?
}
/**
* rct2: 0x00698827
* returns 1 on pickup (CF not set)
*/
int peep_can_be_picked_up(rct_peep* peep){
return RCT2_ADDRESS(0x982004, uint8)[peep->state] & 1;
}
enum{
PEEP_FACE_OFFSET_ANGRY = 0,
PEEP_FACE_OFFSET_VERY_VERY_SICK,
PEEP_FACE_OFFSET_VERY_SICK,
PEEP_FACE_OFFSET_SICK,
PEEP_FACE_OFFSET_VERY_TIRED,
PEEP_FACE_OFFSET_TIRED,
PEEP_FACE_OFFSET_VERY_VERY_UNHAPPY,
PEEP_FACE_OFFSET_VERY_UNHAPPY,
PEEP_FACE_OFFSET_UNHAPPY,
PEEP_FACE_OFFSET_NORMAL,
PEEP_FACE_OFFSET_HAPPY,
PEEP_FACE_OFFSET_VERY_HAPPY,
PEEP_FACE_OFFSET_VERY_VERY_HAPPY,
};
const int face_sprite_small[] = {
SPR_PEEP_SMALL_FACE_ANGRY,
SPR_PEEP_SMALL_FACE_VERY_VERY_SICK,
SPR_PEEP_SMALL_FACE_VERY_SICK,
SPR_PEEP_SMALL_FACE_SICK,
SPR_PEEP_SMALL_FACE_VERY_TIRED,
SPR_PEEP_SMALL_FACE_TIRED,
SPR_PEEP_SMALL_FACE_VERY_VERY_UNHAPPY,
SPR_PEEP_SMALL_FACE_VERY_UNHAPPY,
SPR_PEEP_SMALL_FACE_UNHAPPY,
SPR_PEEP_SMALL_FACE_NORMAL,
SPR_PEEP_SMALL_FACE_HAPPY,
SPR_PEEP_SMALL_FACE_VERY_HAPPY,
SPR_PEEP_SMALL_FACE_VERY_VERY_HAPPY,
};
const int face_sprite_large[] = {
SPR_PEEP_LARGE_FACE_ANGRY,
SPR_PEEP_LARGE_FACE_VERY_VERY_SICK,
SPR_PEEP_LARGE_FACE_VERY_SICK,
SPR_PEEP_LARGE_FACE_SICK,
SPR_PEEP_LARGE_FACE_VERY_TIRED,
SPR_PEEP_LARGE_FACE_TIRED,
SPR_PEEP_LARGE_FACE_VERY_VERY_UNHAPPY,
SPR_PEEP_LARGE_FACE_VERY_UNHAPPY,
SPR_PEEP_LARGE_FACE_UNHAPPY,
SPR_PEEP_LARGE_FACE_NORMAL,
SPR_PEEP_LARGE_FACE_HAPPY,
SPR_PEEP_LARGE_FACE_VERY_HAPPY,
SPR_PEEP_LARGE_FACE_VERY_VERY_HAPPY,
};
int get_face_sprite_offset(rct_peep *peep){
// ANGRY
if (peep->var_F3) return PEEP_FACE_OFFSET_ANGRY;
// VERY_VERY_SICK
if (peep->nausea > 200) return PEEP_FACE_OFFSET_VERY_VERY_SICK;
// VERY_SICK
if (peep->nausea > 170) return PEEP_FACE_OFFSET_VERY_SICK;
// SICK
if (peep->nausea > 140) return PEEP_FACE_OFFSET_SICK;
// VERY_TIRED
if (peep->energy < 46) return PEEP_FACE_OFFSET_VERY_TIRED;
// TIRED
if (peep->energy < 70) return PEEP_FACE_OFFSET_TIRED;
int offset = PEEP_FACE_OFFSET_VERY_VERY_UNHAPPY;
//There are 7 different happiness based faces
for (int i = 37; peep->happiness >= i; i += 37)
{
offset++;
}
return offset;
}
/**
* Function split into large and small sprite
* rct2: 0x00698721
*/
int get_peep_face_sprite_small(rct_peep *peep){
return face_sprite_small[get_face_sprite_offset(peep)];
}
/**
* Function split into large and small sprite
* rct2: 0x00698721
*/
int get_peep_face_sprite_large(rct_peep *peep){
return face_sprite_large[get_face_sprite_offset(peep)];
}
/**
*
* rct2: 0x0069A5A0
* tests if a peep's name matches a cheat code, normally returns using a register flag
* @param index (eax)
* @param ride (esi)
*/
int peep_check_easteregg_name(int index, rct_peep *peep)
{
char buffer[256];
format_string(buffer, peep->name_string_idx, &peep->id);
return _stricmp(buffer, gPeepEasterEggNames[index]) == 0;
}
int peep_get_easteregg_name_id(rct_peep *peep)
{
char buffer[256];
int i;
format_string(buffer, peep->name_string_idx, &peep->id);
for (i = 0; i < countof(gPeepEasterEggNames); i++)
if (_stricmp(buffer, gPeepEasterEggNames[i]) == 0)
return i;
return -1;
}
int peep_is_mechanic(rct_peep *peep)
{
return (
peep->sprite_identifier == SPRITE_IDENTIFIER_PEEP &&
peep->type == PEEP_TYPE_STAFF &&
peep->staff_type == STAFF_TYPE_MECHANIC
);
}
static int peep_has_food_standard_flag(rct_peep* peep){
return peep->item_standard_flags &(
PEEP_ITEM_DRINK |
PEEP_ITEM_BURGER |
PEEP_ITEM_FRIES |
PEEP_ITEM_ICE_CREAM |
PEEP_ITEM_COTTON_CANDY |
PEEP_ITEM_PIZZA |
PEEP_ITEM_POPCORN |
PEEP_ITEM_HOT_DOG |
PEEP_ITEM_TENTACLE |
PEEP_ITEM_CANDY_APPLE |
PEEP_ITEM_DONUT |
PEEP_ITEM_COFFEE |
PEEP_ITEM_CHICKEN |
PEEP_ITEM_LEMONADE);
}
static int peep_has_food_extra_flag(rct_peep* peep){
return peep->item_extra_flags &(
PEEP_ITEM_PRETZEL |
PEEP_ITEM_CHOCOLATE |
PEEP_ITEM_ICED_TEA |
PEEP_ITEM_FUNNEL_CAKE |
PEEP_ITEM_BEEF_NOODLES |
PEEP_ITEM_FRIED_RICE_NOODLES |
PEEP_ITEM_WONTON_SOUP |
PEEP_ITEM_MEATBALL_SOUP |
PEEP_ITEM_FRUIT_JUICE |
PEEP_ITEM_SOYBEAN_MILK |
PEEP_ITEM_SU_JONGKWA |
PEEP_ITEM_SUB_SANDWICH |
PEEP_ITEM_COOKIE |
PEEP_ITEM_ROAST_SAUSAGE
);
}
/* To simplify check of 0x36BA3E0 and 0x11FF78
* returns 0 on no food.
*/
int peep_has_food(rct_peep* peep){
return peep_has_food_standard_flag(peep) ||
peep_has_food_extra_flag(peep);
}
static int peep_empty_container_standard_flag(rct_peep* peep){
return peep->item_standard_flags &(
PEEP_ITEM_EMPTY_CAN |
PEEP_ITEM_EMPTY_BURGER_BOX |
PEEP_ITEM_EMPTY_CUP |
PEEP_ITEM_RUBBISH |
PEEP_ITEM_EMPTY_BOX |
PEEP_ITEM_EMPTY_BOTTLE
);
}
static int peep_empty_container_extra_flag(rct_peep* peep){
return peep->item_extra_flags &(
PEEP_ITEM_EMPTY_BOWL_RED |
PEEP_ITEM_EMPTY_DRINK_CARTON |
PEEP_ITEM_EMPTY_JUICE_CUP |
PEEP_ITEM_EMPTY_BOWL_BLUE
);
}
static int peep_has_empty_container(rct_peep* peep){
return peep_empty_container_standard_flag(peep) ||
peep_empty_container_extra_flag(peep);
}
/* Simplifies 0x690582. Returns 1 if should find bench*/
static int peep_should_find_bench(rct_peep* peep){
if (!(peep->flags & PEEP_FLAGS_LEAVING_PARK)){
if (peep_has_food(peep)){
if (peep->hunger < 128 || peep->happiness < 128){
if (!(peep->next_var_29 & 0x1C)){
return 1;
}
}
}
if (peep->nausea <= 170 && peep->energy > 50){
return 0;
}
if (!(peep->next_var_29 & 0x1C)){
return 1;
}
}
return 0;
}
/**
* rct2: 0x699F5A
* al:thought_type
* ah:thought_arguments
* esi: peep
*/
void peep_insert_new_thought(rct_peep *peep, uint8 thought_type, uint8 thought_arguments){
uint8 action = RCT2_ADDRESS(0x981DB0, uint16)[thought_type] & 0xFF;
if (action != 0xFF && peep->action >= 254){
peep->action = action;
peep->action_frame = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
invalidate_sprite((rct_sprite*)peep);
}
for (int i = 0; i < PEEP_MAX_THOUGHTS; ++i){
rct_peep_thought* thought = &peep->thoughts[i];
// Remove the oldest thought by setting it to NONE.
if (thought->type == PEEP_THOUGHT_TYPE_NONE) break;
if (thought->type == thought_type && thought->item == thought_arguments){
// If the thought type has not changed then we need to move
// it to the top of the thought list. This is done by first removing the
// existing thought and placing it at the top.
memmove(thought, thought + 1, sizeof(rct_peep_thought)*(PEEP_MAX_THOUGHTS - i - 1));
break;
}
}
memmove(&peep->thoughts[1], &peep->thoughts[0], sizeof(rct_peep_thought)*(PEEP_MAX_THOUGHTS - 1));
peep->thoughts[0].type = thought_type;
peep->thoughts[0].item = thought_arguments;
peep->thoughts[0].var_2 = 0;
peep->thoughts[0].var_3 = 0;
peep->var_45 |= (1 << 0);
}
/* rct2: 0x00699FE3
* Stops peeps that are having thoughts
* such as "I'm hungry" after visiting a food shop.
* Works for Thirst/Hungry/Low Money/Bathroom
*/
static void peep_stop_purchase_thought(rct_peep* peep, uint8 ride_type){
uint8 thought_type = PEEP_THOUGHT_TYPE_HUNGRY;
if (!(RCT2_ADDRESS(0x97CF40, uint32)[ride_type * 2] & 0x800000)){
thought_type = PEEP_THOUGHT_TYPE_THIRSTY;
if (!(RCT2_ADDRESS(0x97CF40, uint32)[ride_type * 2] & 0x1000000)){
thought_type = PEEP_THOUGHT_RUNNING_OUT;
if (ride_type != RIDE_TYPE_ATM){
thought_type = PEEP_THOUGHT_TYPE_BATHROOM;
if (!(RCT2_ADDRESS(0x97CF40, uint32)[ride_type * 2] & 0x2000000)){
return;
}
}
}
}
//Remove the related thought
for (int i = 0; i < PEEP_MAX_THOUGHTS; ++i){
rct_peep_thought* thought = &peep->thoughts[i];
if (thought->type == PEEP_THOUGHT_TYPE_NONE) break;
if (thought->type != thought_type)continue;
memmove(thought, thought + 1, sizeof(rct_peep_thought)*(PEEP_MAX_THOUGHTS - i - 1));
peep->thoughts[PEEP_MAX_THOUGHTS - 1].type = PEEP_THOUGHT_TYPE_NONE;
peep->var_45 |= (1 << 0);
i--;
}
}
void peep_set_map_tooltip(rct_peep *peep)
{
if (peep->type == PEEP_TYPE_GUEST) {
RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = peep->flags & PEEP_FLAGS_TRACKING ? 1450 : 1449;
RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint32) = get_peep_face_sprite_small(peep);
RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 6, uint16) = peep->name_string_idx;
RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 8, uint32) = peep->id;
uint32 arg0, arg1;
get_arguments_from_action(peep, &arg0, &arg1);
RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 12, uint32) = arg0;
RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 16, uint32) = arg1;
} else {
RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1451;
RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = peep->name_string_idx;
RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 4, uint32) = peep->id;
uint32 arg0, arg1;
get_arguments_from_action(peep, &arg0, &arg1);
RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 8, uint32) = arg0;
RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 12, uint32) = arg1;
}
}