mirror of https://github.com/OpenRCT2/OpenRCT2.git
754 lines
20 KiB
C
754 lines
20 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 <windows.h>
|
|
#include "addresses.h"
|
|
#include "audio.h"
|
|
#include "news_item.h"
|
|
#include "peep.h"
|
|
#include "rct2.h"
|
|
#include "ride.h"
|
|
#include "sprite.h"
|
|
#include "sprites.h"
|
|
#include "staff.h"
|
|
#include "window.h"
|
|
|
|
static void peep_update(rct_peep *peep);
|
|
|
|
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++;
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* rct2: 0x0068FC1E
|
|
*/
|
|
static void peep_update(rct_peep *peep)
|
|
{
|
|
// RCT2_CALLPROC_X(0x0068FC1E, 0, 0, 0, 0, (int)peep, 0, 0); return;
|
|
|
|
int i, j;
|
|
|
|
if (peep->type == PEEP_TYPE_GUEST) {
|
|
if (peep->var_AD != 255)
|
|
if (++peep->var_AE < 720)
|
|
peep->var_AD = 255;
|
|
|
|
// Update thoughts
|
|
i = 0;
|
|
int ebp = 0;
|
|
int edi = -1;
|
|
for (i = 0; i < PEEP_MAX_THOUGHTS; i++) {
|
|
if (peep->thoughts[i].type == PEEP_THOUGHT_TYPE_NONE)
|
|
break;
|
|
|
|
if (peep->thoughts[i].var_2 == 1) {
|
|
ebp++;
|
|
if (++peep->thoughts[i].var_3 >= 220) {
|
|
peep->thoughts[i].var_3 = 0;
|
|
peep->thoughts[i].var_2++;
|
|
ebp--;
|
|
}
|
|
} else if (peep->thoughts[i].var_2 > 1) {
|
|
if (++peep->thoughts[i].var_3 > 255) {
|
|
if (++peep->thoughts[i].var_3 >= 28) {
|
|
peep->var_45 |= 1;
|
|
|
|
// Clear top thought, push others up
|
|
for (j = i; j < PEEP_MAX_THOUGHTS - 1; j++)
|
|
peep->thoughts[j].type = peep->thoughts[j + 1].type;
|
|
peep->thoughts[PEEP_MAX_THOUGHTS - 1].type = PEEP_THOUGHT_TYPE_NONE;
|
|
}
|
|
}
|
|
} else {
|
|
edi = i;
|
|
}
|
|
}
|
|
if (ebp == 0 && edi != -1) {
|
|
peep->thoughts[edi].var_2 = 1;
|
|
peep->var_45 |= 1;
|
|
}
|
|
}
|
|
|
|
// 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->var_71 == 255 && (RCT2_GLOBAL((int)peep + 0x29, uint8) & 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(0x0068FD2F, 0, 0, 0, 0, (int)peep, 0, 0);
|
|
switch (peep->state) {
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
* 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 (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x80000))
|
|
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 (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x1000000))
|
|
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 (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x2000000))
|
|
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->var_16 == 0x8000)
|
|
continue;
|
|
if (viewport->view_x > peep->var_1A)
|
|
continue;
|
|
if (viewport->view_x + viewport->view_width < peep->var_16)
|
|
continue;
|
|
if (viewport->view_y > peep->var_1C)
|
|
continue;
|
|
if (viewport->view_y + viewport->view_height < peep->var_18)
|
|
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) {
|
|
sound_channel_stop(2); //RCT2_CALLPROC_1(0x00401A05, int, 2);
|
|
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
|
|
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;
|
|
}
|
|
} else {
|
|
// Alter crowd noise volume
|
|
if (RCT2_GLOBAL(0x009AF5FC, uint32) != volume) {
|
|
sound_channel_set_volume(2, volume);//RCT2_CALLPROC_2(0x00401AD3, int, int, 2, volume);
|
|
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);
|
|
peep->var_45 |= 8;
|
|
RCT2_CALLPROC_X(0x0069B8CC, 0, 0, 0, 0, (int)peep, 0, 0);
|
|
}
|
|
}
|
|
|
|
// Clap
|
|
if ((peep->state == PEEP_STATE_WALKING || peep->state == PEEP_STATE_QUEUING) && peep->var_71 >= 254) {
|
|
peep->var_71 = 26;
|
|
peep->var_72 = 0;
|
|
peep->var_70 = 0;
|
|
RCT2_CALLPROC_X(0x00693B58, 0, 0, 0, 0, (int)peep, 0, 0);
|
|
RCT2_CALLPROC_X(0x006EC473, 0, 0, 0, 0, (int)peep, 0, 0);
|
|
}
|
|
}
|
|
|
|
// Play applause noise
|
|
sound_play_panned(SOUND_APPLAUSE, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2, 0, 0, 0);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* 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 0:
|
|
*argument_1 = peep->var_71 == 0xB ? STR_DROWNING : STR_WALKING;
|
|
*argument_2 = 0;
|
|
break;
|
|
case 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 (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride.type * 8, uint32) & 0x400000){
|
|
*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 0x14:
|
|
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->pad_2C == 0){
|
|
*argument_1 = STR_WALKING;
|
|
*argument_2 = 0;
|
|
}
|
|
else if (peep->pad_2C == 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
|
|
);
|
|
}
|