diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index e492c0aa92..00362abcc4 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -17,6 +17,7 @@ + @@ -58,6 +59,7 @@ + diff --git a/projects/openrct2.vcxproj.filters b/projects/openrct2.vcxproj.filters index dc799bd2b0..dd606605a9 100644 --- a/projects/openrct2.vcxproj.filters +++ b/projects/openrct2.vcxproj.filters @@ -135,6 +135,9 @@ Header Files + + Header Files + @@ -326,6 +329,9 @@ Source Files + + Source Files + diff --git a/src/award.c b/src/award.c new file mode 100644 index 0000000000..b627b07c17 --- /dev/null +++ b/src/award.c @@ -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 . + *****************************************************************************/ + +#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); +} \ No newline at end of file diff --git a/src/award.h b/src/award.h new file mode 100644 index 0000000000..26074cdaa8 --- /dev/null +++ b/src/award.h @@ -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 . + *****************************************************************************/ + +#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 \ No newline at end of file diff --git a/src/park.c b/src/park.c index f879a409ef..4ab075f148 100644 --- a/src/park.c +++ b/src/park.c @@ -20,6 +20,7 @@ #include #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); } \ No newline at end of file diff --git a/src/park.h b/src/park.h index eb7d61e358..8908e4a31f 100644 --- a/src/park.h +++ b/src/park.h @@ -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 diff --git a/src/ride.c b/src/ride.c index 7490f60dd3..1535bc7406 100644 --- a/src/ride.c +++ b/src/ride.c @@ -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] = { diff --git a/src/ride.h b/src/ride.h index 5c1101e310..e5dff8e8f1 100644 --- a/src/ride.h +++ b/src/ride.h @@ -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(); diff --git a/src/scenario.c b/src/scenario.c index 93b93fbbbf..26bc659709 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -21,6 +21,7 @@ #include #include #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(); } } diff --git a/src/window_park.c b/src/window_park.c index a87c9d0ee4..782cbe65c5 100644 --- a/src/window_park.c +++ b/src/window_park.c @@ -20,6 +20,7 @@ #include #include "addresses.h" +#include "award.h" #include "config.h" #include "date.h" #include "game.h"