implement more awards WIP

This commit is contained in:
IntelOrca 2014-05-27 15:14:45 +01:00
parent ebcbc2d2f1
commit 30e6358fd4
10 changed files with 414 additions and 161 deletions

View File

@ -17,6 +17,7 @@
<ItemGroup>
<ClInclude Include="..\src\addresses.h" />
<ClInclude Include="..\src\audio.h" />
<ClInclude Include="..\src\award.h" />
<ClInclude Include="..\src\climate.h" />
<ClInclude Include="..\src\config.h" />
<ClInclude Include="..\src\date.h" />
@ -58,6 +59,7 @@
<ItemGroup>
<ClCompile Include="..\lodepng\lodepng.c" />
<ClCompile Include="..\src\audio.c" />
<ClCompile Include="..\src\award.c" />
<ClCompile Include="..\src\climate.c" />
<ClCompile Include="..\src\config.c" />
<ClCompile Include="..\src\date.c" />

View File

@ -135,6 +135,9 @@
<ClInclude Include="..\src\marketing.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\award.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\game.c">
@ -326,6 +329,9 @@
<ClCompile Include="..\src\marketing.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\award.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\openrct2.exe">

324
src/award.c Normal file
View File

@ -0,0 +1,324 @@
/*****************************************************************************
* 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 "award.h"
#include "news_item.h"
#include "ride.h"
#include "scenario.h"
#include "window.h"
#define NEGATIVE 0
#define POSITIVE 1
int _awardPositiveMap[] = {
NEGATIVE, // PARK_AWARD_MOST_UNTIDY
POSITIVE, // PARK_AWARD_MOST_TIDY
POSITIVE, // PARK_AWARD_BEST_ROLLERCOASTERS
POSITIVE, // PARK_AWARD_BEST_VALUE
POSITIVE, // PARK_AWARD_MOST_BEAUTIFUL
NEGATIVE, // PARK_AWARD_WORST_VALUE
POSITIVE, // PARK_AWARD_SAFEST
POSITIVE, // PARK_AWARD_BEST_STAFF
POSITIVE, // PARK_AWARD_BEST_FOOD
NEGATIVE, // PARK_AWARD_WORST_FOOD
POSITIVE, // PARK_AWARD_BEST_RESTROOMS
NEGATIVE, // PARK_AWARD_MOST_DISAPPOINTING
POSITIVE, // PARK_AWARD_BEST_WATER_RIDES
POSITIVE, // PARK_AWARD_BEST_CUSTOM_DESIGNED_RIDES
POSITIVE, // PARK_AWARD_MOST_DAZZLING_RIDE_COLOURS
NEGATIVE, // PARK_AWARD_MOST_CONFUSING_LAYOUT
POSITIVE, // PARK_AWARD_BEST_GENTLE_RIDES
};
int award_is_positive(int type)
{
return _awardPositiveMap[type];
}
#pragma region Award checks
static int award_is_deserved_most_untidy(int awardType, int activeAwardTypes)
{
// TODO
return 0;
}
static int award_is_deserved_most_tidy(int awardType, int activeAwardTypes)
{
// TODO
return 0;
}
static int award_is_deserved_best_rollercoasters(int awardType, int activeAwardTypes)
{
int i, rollerCoasters;
rct_ride *ride;
char *object;
rollerCoasters = 0;
FOR_ALL_RIDES(i, ride) {
object = RCT2_ADDRESS(0x009ACFA4, char*)[ride->subtype];
if (RCT2_GLOBAL(object + 0x1BE, uint8) != RIDE_GROUP_ROLLERCOASTER && RCT2_GLOBAL(object + 0x1BF, uint8) != RIDE_GROUP_ROLLERCOASTER)
continue;
if (ride->status != RIDE_STATUS_OPEN || ride->lifecycle_flags & 0x400)
continue;
rollerCoasters++;
}
return (rollerCoasters >= 6);
}
/** Entrance fee is 0.10 less than half of the total ride value. */
static int award_is_deserved_best_value(int awardType, int activeAwardTypes)
{
if (activeAwardTypes & (1 << PARK_AWARD_WORST_VALUE))
return 0;
if (activeAwardTypes & (1 << PARK_AWARD_MOST_DISAPPOINTING))
return 0;
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & (PARK_FLAGS_11 | PARK_FLAGS_PARK_FREE_ENTRY))
return 0;
if (RCT2_GLOBAL(RCT2_TOTAL_RIDE_VALUE, money16) < MONEY(10, 00))
return 0;
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) + MONEY(0, 10) >= RCT2_GLOBAL(RCT2_TOTAL_RIDE_VALUE, money16) / 2)
return 0;
return 1;
}
static int award_is_deserved_most_beautiful(int awardType, int activeAwardTypes)
{
// TODO
return 0;
}
/** Entrance fee is more than total ride value. */
static int award_is_deserved_worse_value(int awardType, int activeAwardTypes)
{
if (activeAwardTypes & (1 << PARK_AWARD_BEST_VALUE))
return 0;
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_11)
return 0;
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) == MONEY(0, 00))
return 0;
if (RCT2_GLOBAL(RCT2_TOTAL_RIDE_VALUE, money16) >= RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16))
return 0;
return 1;
}
static int award_is_deserved_safest(int awardType, int activeAwardTypes)
{
// TODO
return 0;
}
static int award_is_deserved_best_staff(int awardType, int activeAwardTypes)
{
// TODO
return 0;
}
static int award_is_deserved_best_food(int awardType, int activeAwardTypes)
{
// TODO
return 0;
}
static int award_is_deserved_worst_food(int awardType, int activeAwardTypes)
{
// TODO
return 0;
}
static int award_is_deserved_best_restrooms(int awardType, int activeAwardTypes)
{
// TODO
return 0;
}
/** More than half of the rides have satisfication <= 6 and park rating <= 650. */
static int award_is_deserved_most_disappointing(int awardType, int activeAwardTypes)
{
unsigned int i, countedRides, disappointingRides;
rct_ride *ride;
if (activeAwardTypes & (1 << PARK_AWARD_BEST_VALUE))
return 0;
if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, uint16) > 650)
return 0;
// Count the number of disappointing rides
countedRides = 0;
disappointingRides = 0;
FOR_ALL_RIDES(i, ride) {
if (ride->excitement == 0xFFFF || ride->var_158 == 0xFF)
continue;
countedRides++;
// Satification maybe?
if (ride->var_158 <= 6)
disappointingRides++;
}
// Half of the rides are disappointing
return (disappointingRides >= countedRides / 2);
}
/** At least 6 open water rides. */
static int award_is_deserved_best_water_rides(int awardType, int activeAwardTypes)
{
int i, waterRides;
rct_ride *ride;
char *object;
waterRides = 0;
FOR_ALL_RIDES(i, ride) {
object = RCT2_ADDRESS(0x009ACFA4, char*)[ride->subtype];
if (RCT2_GLOBAL(object + 0x1BE, uint8) != RIDE_GROUP_WATER && RCT2_GLOBAL(object + 0x1BF, uint8) != RIDE_GROUP_WATER)
continue;
if (ride->status != RIDE_STATUS_OPEN || ride->lifecycle_flags & 0x400)
continue;
waterRides++;
}
return (waterRides >= 6);
}
static int award_is_deserved_best_custom_designed_rides(int awardType, int activeAwardTypes)
{
// TODO
return 0;
}
static int award_is_deserved_most_dazzling_ride_colours(int awardType, int activeAwardTypes)
{
// TODO
return 0;
}
static int award_is_deserved_most_confusing_layout(int awardType, int activeAwardTypes)
{
// TODO
return 0;
}
/** At least 10 open gentle rides. */
static int award_is_deserved_best_gentle_rides(int awardType, int activeAwardTypes)
{
int i, gentleRides;
rct_ride *ride;
char *object;
gentleRides = 0;
FOR_ALL_RIDES(i, ride) {
object = RCT2_ADDRESS(0x009ACFA4, char*)[ride->subtype];
if (RCT2_GLOBAL(object + 0x1BE, uint8) != RIDE_GROUP_GENTLE && RCT2_GLOBAL(object + 0x1BF, uint8) != RIDE_GROUP_GENTLE)
continue;
if (ride->status != RIDE_STATUS_OPEN || ride->lifecycle_flags & 0x400)
continue;
gentleRides++;
}
return (gentleRides >= 10);
}
typedef int (*award_deserved_check)(int, int);
award_deserved_check _awardChecks[] = {
award_is_deserved_most_untidy,
award_is_deserved_most_tidy,
award_is_deserved_best_rollercoasters,
award_is_deserved_best_value,
award_is_deserved_most_beautiful,
award_is_deserved_worse_value,
award_is_deserved_safest,
award_is_deserved_best_staff,
award_is_deserved_best_food,
award_is_deserved_worst_food,
award_is_deserved_best_restrooms,
award_is_deserved_most_disappointing,
award_is_deserved_best_water_rides,
award_is_deserved_best_custom_designed_rides,
award_is_deserved_most_dazzling_ride_colours,
award_is_deserved_most_confusing_layout,
award_is_deserved_best_gentle_rides
};
static int award_is_deserved(int awardType, int activeAwardTypes)
{
return _awardChecks[awardType](awardType, activeAwardTypes);
}
#pragma endregion
/**
*
* rct2: 0x0066A86C
*/
void award_update_all()
{
int i, activeAwardTypes, freeAwardEntryIndex;
rct_award *awards;
awards = RCT2_ADDRESS(RCT2_ADDRESS_AWARD_LIST, rct_award);
// Only add new awards if park is open
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_OPEN) {
// Set active award types as flags
activeAwardTypes = 0;
freeAwardEntryIndex = -1;
for (i = 0; i < MAX_AWARDS; i++) {
if (awards[i].time != 0)
activeAwardTypes |= (1 << awards[i].type);
else if (freeAwardEntryIndex != -1)
freeAwardEntryIndex = i;
}
// Check if there was a free award entry
if (freeAwardEntryIndex != -1) {
// Get a random award type not already active
int awardType;
do {
awardType = (((scenario_rand() & 0xFF) * 17) >> 8) & 0xFF;
} while (activeAwardTypes & (1 << awardType));
// Check if award is deserved
if (award_is_deserved(awardType, activeAwardTypes)) {
// Add award
awards[freeAwardEntryIndex].type = awardType;
awards[freeAwardEntryIndex].time = 5;
news_item_add_to_queue(NEWS_ITEM_AWARD, STR_NEWS_ITEM_AWARD_MOST_UNTIDY + awardType, 0);
window_invalidate_by_id(WC_PARK_INFORMATION, 0);
}
}
}
// Decrease award times
for (i = 0; i < MAX_AWARDS; i++)
if (awards[i].time != 0)
if (--awards[i].time == 0)
window_invalidate_by_id(WC_PARK_INFORMATION, 0);
}

57
src/award.h Normal file
View File

@ -0,0 +1,57 @@
/*****************************************************************************
* 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/>.
*****************************************************************************/
#ifndef _AWARD_H_
#define _AWARD_H_
#include "rct2.h"
typedef struct {
uint16 time;
uint16 type;
} rct_award;
enum {
PARK_AWARD_MOST_UNTIDY,
PARK_AWARD_MOST_TIDY,
PARK_AWARD_BEST_ROLLERCOASTERS,
PARK_AWARD_BEST_VALUE,
PARK_AWARD_MOST_BEAUTIFUL,
PARK_AWARD_WORST_VALUE,
PARK_AWARD_SAFEST,
PARK_AWARD_BEST_STAFF,
PARK_AWARD_BEST_FOOD,
PARK_AWARD_WORST_FOOD,
PARK_AWARD_BEST_RESTROOMS,
PARK_AWARD_MOST_DISAPPOINTING,
PARK_AWARD_BEST_WATER_RIDES,
PARK_AWARD_BEST_CUSTOM_DESIGNED_RIDES,
PARK_AWARD_MOST_DAZZLING_RIDE_COLOURS,
PARK_AWARD_MOST_CONFUSING_LAYOUT,
PARK_AWARD_BEST_GENTLE_RIDES,
PARK_AWARD_COUNT
};
#define MAX_AWARDS 4
int award_is_positive(int type);
void award_update_all();
#endif

View File

@ -20,6 +20,7 @@
#include <windows.h>
#include "addresses.h"
#include "award.h"
#include "finance.h"
#include "map.h"
#include "marketing.h"
@ -45,22 +46,6 @@ int _suggestedGuestMaximum;
*/
int _guestGenerationProbability;
int park_is_award_positive(int type)
{
// Check if award is negative
switch (type) {
case PARK_AWARD_MOST_UNTIDY:
case PARK_AWARD_WORST_VALUE:
case PARK_AWARD_WORST_FOOD:
case PARK_AWARD_MOST_DISAPPOINTING:
case PARK_AWARD_MOST_CONFUSING_LAYOUT:
return 0;
}
// Otherwise its positive
return 1;
}
int park_is_open()
{
return (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_OPEN) != 0;
@ -484,7 +469,7 @@ static int park_calculate_guest_generation_probability()
continue;
// +/- 0.25% of the probability
if (park_is_award_positive(award->type))
if (award_is_positive(award->type))
probability += probability / 4;
else
probability -= probability / 4;
@ -590,114 +575,4 @@ void park_update()
void park_update_histories()
{
RCT2_CALLPROC_EBPSAFE(0x0066A231);
}
static int park_is_award_deserved(int awardType, int activeAwardTypes)
{
switch (awardType) {
case PARK_AWARD_MOST_UNTIDY:
break;
case PARK_AWARD_MOST_TIDY:
break;
case PARK_AWARD_BEST_ROLLERCOASTERS:
break;
case PARK_AWARD_BEST_VALUE:
if (activeAwardTypes & (1 << PARK_AWARD_WORST_VALUE))
return 0;
if (activeAwardTypes & (1 << PARK_AWARD_MOST_DISAPPOINTING))
return 0;
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & (PARK_FLAGS_11 | PARK_FLAGS_PARK_FREE_ENTRY))
return 0;
if (RCT2_GLOBAL(RCT2_TOTAL_RIDE_VALUE, money16) < MONEY(10, 00))
return 0;
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) + MONEY(0, 10) >= RCT2_GLOBAL(RCT2_TOTAL_RIDE_VALUE, money16) / 2)
return 0;
return 1;
case PARK_AWARD_MOST_BEAUTIFUL:
break;
case PARK_AWARD_WORST_VALUE:
if (activeAwardTypes & (1 << PARK_AWARD_BEST_VALUE))
return 0;
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_11)
return 0;
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16) == MONEY(0, 00))
return 0;
if (RCT2_GLOBAL(RCT2_TOTAL_RIDE_VALUE, money16) >= RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16))
return 0;
return 1;
break;
case PARK_AWARD_SAFEST:
break;
case PARK_AWARD_BEST_STAFF:
break;
case PARK_AWARD_BEST_FOOD:
break;
case PARK_AWARD_WORST_FOOD:
break;
case PARK_AWARD_BEST_RESTROOMS:
break;
case PARK_AWARD_MOST_DISAPPOINTING:
break;
case PARK_AWARD_BEST_WATER_RIDES:
break;
case PARK_AWARD_BEST_CUSTOM_DESIGNED_RIDES:
break;
case PARK_AWARD_MOST_DAZZLING_RIDE_COLOURS:
break;
case PARK_AWARD_MOST_CONFUSING_LAYOUT:
break;
case PARK_AWARD_BEST_GENTLE_RIDES:
break;
}
return 0;
}
/**
*
* rct2: 0x0066A86C
*/
void park_update_awards()
{
int i, activeAwardTypes, freeAwardEntryIndex;
rct_award *awards;
awards = RCT2_ADDRESS(RCT2_ADDRESS_AWARD_LIST, rct_award);
// Only add new awards if park is open
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_OPEN) {
// Set active award types as flags
activeAwardTypes = 0;
freeAwardEntryIndex = -1;
for (i = 0; i < MAX_AWARDS; i++) {
if (awards[i].time != 0)
activeAwardTypes |= (1 << awards[i].type);
else if (freeAwardEntryIndex != -1)
freeAwardEntryIndex = i;
}
// Check if there was a free award entry
if (freeAwardEntryIndex != -1) {
// Get a random award type not already active
int awardType;
do {
awardType = (((scenario_rand() & 0xFF) * 17) >> 8) & 0xFF;
} while (activeAwardTypes & (1 << awardType));
// Check if award is deserved
if (park_is_award_deserved(awardType, activeAwardTypes)) {
// Add award
awards[freeAwardEntryIndex].type = awardType;
awards[freeAwardEntryIndex].time = 5;
news_item_add_to_queue(NEWS_ITEM_AWARD, STR_NEWS_ITEM_AWARD_MOST_UNTIDY + awardType, 0);
window_invalidate_by_id(WC_PARK_INFORMATION, 0);
}
}
}
// Decrease award times
for (i = 0; i < MAX_AWARDS; i++)
if (awards[i].time != 0)
if (--awards[i].time == 0)
window_invalidate_by_id(WC_PARK_INFORMATION, 0);
}

View File

@ -26,32 +26,6 @@
#define DECRYPT_MONEY(money) rol32((money) ^ 0xF4EC9621, 13)
#define ENCRYPT_MONEY(money) (ror32((money), 13) ^ 0xF4EC9621)
typedef struct {
uint16 time;
uint16 type;
} rct_award;
enum {
PARK_AWARD_MOST_UNTIDY,
PARK_AWARD_MOST_TIDY,
PARK_AWARD_BEST_ROLLERCOASTERS,
PARK_AWARD_BEST_VALUE,
PARK_AWARD_MOST_BEAUTIFUL,
PARK_AWARD_WORST_VALUE,
PARK_AWARD_SAFEST,
PARK_AWARD_BEST_STAFF,
PARK_AWARD_BEST_FOOD,
PARK_AWARD_WORST_FOOD,
PARK_AWARD_BEST_RESTROOMS,
PARK_AWARD_MOST_DISAPPOINTING,
PARK_AWARD_BEST_WATER_RIDES,
PARK_AWARD_BEST_CUSTOM_DESIGNED_RIDES,
PARK_AWARD_MOST_DAZZLING_RIDE_COLOURS,
PARK_AWARD_MOST_CONFUSING_LAYOUT,
PARK_AWARD_BEST_GENTLE_RIDES,
PARK_AWARD_COUNT
};
enum {
PARK_FLAGS_PARK_OPEN = (1 << 0),
PARK_FLAGS_FORBID_LANDSCAPE_CHANGES = (1 << 2),
@ -69,9 +43,6 @@ enum {
PARK_FLAGS_18 = (1 << 18)
};
#define MAX_AWARDS 4
int park_is_award_positive(int type);
int park_is_open();
void park_init();
void park_reset_awards_and_history();
@ -84,6 +55,5 @@ void reset_park_entrances();
void park_update();
void park_update_histories();
void park_update_awards();
#endif

View File

@ -25,9 +25,6 @@
#include "peep.h"
#include "window.h"
#define GET_RIDE(x) (&(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride)[x]))
#define GET_RIDE_MEASUREMENT(x) (&(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_MEASUREMENTS, rct_ride_measurement)[x]))
#pragma region Ride classification table
const uint8 gRideClassifications[255] = {

View File

@ -308,10 +308,30 @@ enum {
RIDE_COLOUR_SCHEME_DIFFERENT_PER_CAR
};
enum {
RIDE_GROUP_TRANSPORT,
RIDE_GROUP_GENTLE,
RIDE_GROUP_ROLLERCOASTER,
RIDE_GROUP_THRILL,
RIDE_GROUP_WATER,
RIDE_GROUP_SHOP
};
#define MAX_RIDES 255
#define MAX_RIDE_MEASUREMENTS 8
#define RIDE_RELIABILITY_UNDEFINED 0xFFFF
/** Helper macros until rides are stored in this module. */
#define GET_RIDE(x) (&(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride)[x]))
#define GET_RIDE_MEASUREMENT(x) (&(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_MEASUREMENTS, rct_ride_measurement)[x]))
/**
* Helper macro loop for enumerating through all the non null rides.
*/
#define FOR_ALL_RIDES(i, ride) \
for (i = 0; i < MAX_RIDES; i++) \
if ((ride = &(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride)[i]))->type != RIDE_TYPE_NULL)
extern const uint8 gRideClassifications[255];
int ride_get_count();

View File

@ -21,6 +21,7 @@
#include <windows.h>
#include <string.h>
#include "addresses.h"
#include "award.h"
#include "date.h"
#include "finance.h"
#include "game.h"
@ -634,7 +635,7 @@ void scenario_update()
RCT2_CALLPROC_EBPSAFE(0x0069DEAD);
scenario_objectives_check();
scenario_entrance_fee_too_high_check();
park_update_awards();
award_update_all();
}
}

View File

@ -20,6 +20,7 @@
#include <string.h>
#include "addresses.h"
#include "award.h"
#include "config.h"
#include "date.h"
#include "game.h"