diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index b480d80723..38e1118dbe 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -41,6 +41,7 @@ + @@ -94,6 +95,7 @@ + diff --git a/projects/openrct2.vcxproj.filters b/projects/openrct2.vcxproj.filters index 5f0581eca7..b1610b9290 100644 --- a/projects/openrct2.vcxproj.filters +++ b/projects/openrct2.vcxproj.filters @@ -174,6 +174,9 @@ Header Files + + Header Files + @@ -425,6 +428,9 @@ Windows + + Source Files + diff --git a/src/addresses.h b/src/addresses.h index 00f77551f9..56dd5fa803 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -285,6 +285,9 @@ #define RCT2_ADDRESS_SECURITY_COLOUR 0x01357BCF #define RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES 0x01357CF2 +#define RCT2_ADDRESS_RESEARH_PROGRESS_STAGE 0x01357CF3 + +#define RCT2_ADDRESS_RESEARH_PROGRESS 0x013580E4 #define RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY 0x013580E7 #define RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_MONTH 0x013580E8 diff --git a/src/game.c b/src/game.c index 8348b053cd..34d32ddfa2 100644 --- a/src/game.c +++ b/src/game.c @@ -31,6 +31,7 @@ #include "park.h" #include "peep.h" #include "rct2.h" +#include "research.h" #include "ride.h" #include "sawyercoding.h" #include "scenario.h" @@ -494,7 +495,7 @@ void game_logic_update() RCT2_CALLPROC_EBPSAFE(0x00672AA4); // update text effects RCT2_CALLPROC_EBPSAFE(0x006ABE4C); // update rides park_update(); - RCT2_CALLPROC_EBPSAFE(0x00684C7A); // update research + research_update(); RCT2_CALLPROC_EBPSAFE(0x006B5A2A); // update ride ratings ride_measurements_update(); RCT2_CALLPROC_EBPSAFE(0x0068AFAD); diff --git a/src/research.c b/src/research.c new file mode 100644 index 0000000000..ab7e3b2cf2 --- /dev/null +++ b/src/research.c @@ -0,0 +1,131 @@ +/***************************************************************************** + * 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 "date.h" +#include "research.h" +#include "rct2.h" +#include "window.h" + +typedef struct { + sint32 var_0; + uint8 category; +} rct_research_item; + +const int _researchRate[] = { 0, 160, 250, 400 }; + +// 0x00EE787C +uint8 gResearchUncompletedCategories; + +/** + * + * rct2: 0x00684BAE + */ +void research_update_uncompleted_types() +{ + int uncompletedResearchTypes = 0; + rct_research_item *researchItem = (rct_research_item*)0x001358844; + while (researchItem->var_0 != -1) + researchItem++; + researchItem++; + for (; researchItem->var_0 != -2; researchItem++) + uncompletedResearchTypes |= (1 << researchItem->category); + + gResearchUncompletedCategories = uncompletedResearchTypes; +} + +/** + * + * rct2: 0x00684D2A + */ +static void research_calculate_expected_date() +{ + int progress = RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16); + int progressStage = RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8); + int researchLevel = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8); + int currentDay = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16); + int currentMonth = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16); + int expectedDay, expectedMonth, dayQuotient, dayRemainder, progressRemaining, daysRemaining; + + if (progressStage == RESEARCH_STAGE_INITIAL_RESEARCH || researchLevel == RESEARCH_FUNDING_NONE) { + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY, uint8) = 255; + } else { + progressRemaining = progressStage == RESEARCH_STAGE_COMPLETING_DESIGN ? 0x10000 : 0x20000; + progressRemaining -= progress; + daysRemaining = (progressRemaining / _researchRate[researchLevel]) * 128; + + expectedDay = currentDay + (daysRemaining & 0xFFFF); + dayQuotient = expectedDay / 0x10000; + dayRemainder = expectedDay % 0x10000; + + expectedMonth = date_get_month(currentMonth + dayQuotient + (daysRemaining >> 16)); + expectedDay = (dayRemainder * days_in_month[expectedMonth]) >> 16; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY, uint8) = expectedDay; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_MONTH, uint8) = expectedMonth; + } +} + +/** + * + * rct2: 0x00684C7A + */ +void research_update() +{ + int editorScreenFlags, researchLevel, currentResearchProgress; + + editorScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR | SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & editorScreenFlags) + return; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) % 32 != 0) + return; + + researchLevel = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8); + + currentResearchProgress = RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16); + currentResearchProgress += _researchRate[researchLevel]; + if (currentResearchProgress <= 0xFFFF) { + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16) = currentResearchProgress; + } else { + switch (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8)) { + case RESEARCH_STAGE_INITIAL_RESEARCH: + RCT2_CALLPROC_EBPSAFE(0x00684BE5); + research_calculate_expected_date(); + break; + case RESEARCH_STAGE_DESIGNING: + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) = RESEARCH_STAGE_COMPLETING_DESIGN; + research_calculate_expected_date(); + window_invalidate_by_id(WC_CONSTRUCT_RIDE, 0); + window_invalidate_by_id(WC_RESEARCH, 0); + break; + case RESEARCH_STAGE_COMPLETING_DESIGN: + RCT2_CALLPROC_X(0x006848D4, RCT2_GLOBAL(0x013580E0, uint32), 0, 0, 0, 0, 0, 0); + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) = 0; + research_calculate_expected_date(); + research_update_uncompleted_types(); + window_invalidate_by_id(WC_CONSTRUCT_RIDE, 0); + window_invalidate_by_id(WC_RESEARCH, 0); + break; + } + } +} \ No newline at end of file diff --git a/src/research.h b/src/research.h new file mode 100644 index 0000000000..fbfb5c3f08 --- /dev/null +++ b/src/research.h @@ -0,0 +1,43 @@ +/***************************************************************************** + * 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 _RESEARCH_H_ +#define _RESEARCH_H_ + +enum { + RESEARCH_FUNDING_NONE, + RESEARCH_FUNDING_MINIMUM, + RESEARCH_FUNDING_NORMAL, + RESEARCH_FUNDING_MAXIMUM +}; + +enum { + RESEARCH_STAGE_INITIAL_RESEARCH, + RESEARCH_STAGE_DESIGNING, + RESEARCH_STAGE_COMPLETING_DESIGN, + RESEARCH_STAGE_UNKNOWN +}; + +extern uint8 gResearchUncompletedCategories; + +void research_update_uncompleted_types(); +void research_update(); + +#endif \ No newline at end of file diff --git a/src/window_finances.c b/src/window_finances.c index 56f7072898..b3ed322b4e 100644 --- a/src/window_finances.c +++ b/src/window_finances.c @@ -24,6 +24,7 @@ #include "game.h" #include "graph.h" #include "marketing.h" +#include "research.h" #include "ride.h" #include "scenario.h" #include "string_ids.h" @@ -535,7 +536,7 @@ void window_finances_open() w->colours[0] = 1; w->colours[1] = 19; w->colours[2] = 19; - RCT2_CALLPROC_EBPSAFE(0x00684BAE); + research_update_uncompleted_types(); } w->page = 0; @@ -1434,7 +1435,7 @@ static void window_finances_research_invalidate() // Checkboxes int activeResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES, uint16); - int uncompletedResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_UNCOMPLETED_RESEARCH_TYPES, uint16); + int uncompletedResearchTypes = gResearchUncompletedCategories; for (int i = 0; i < 7; i++) { int mask = 1 << i; int widgetMask = 1 << (i + WIDX_TRANSPORT_RIDES); diff --git a/src/window_research.c b/src/window_research.c index 5685c80da1..cd79abc2ca 100644 --- a/src/window_research.c +++ b/src/window_research.c @@ -22,6 +22,7 @@ #include "finance.h" #include "game.h" #include "news_item.h" +#include "research.h" #include "ride.h" #include "scenery.h" #include "string_ids.h" @@ -236,7 +237,7 @@ void window_research_open() w->colours[0] = 1; w->colours[1] = 19; w->colours[2] = 19; - RCT2_CALLPROC_EBPSAFE(0x00684BAE); + research_update_uncompleted_types(); } w->page = 0; @@ -339,9 +340,9 @@ static void window_research_development_paint() // Research type stringId = STR_RESEARCH_UNKNOWN; - if (RCT2_GLOBAL(0x01357CF3, uint8) != 0) { + if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != 0) { stringId = STR_TRANSPORT_RIDE + RCT2_GLOBAL(0x013580E6, uint8); - if (RCT2_GLOBAL(0x01357CF3, uint8) != 1) { + if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != 1) { uint32 typeId = RCT2_GLOBAL(0x013580E0, uint32); if (typeId >= 0x10000) { rct_ride_type *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, rct_ride_type*); @@ -357,13 +358,13 @@ static void window_research_development_paint() y += 25; // Progress - stringId = 2285 + RCT2_GLOBAL(0x01357CF3, uint8); + stringId = 2285 + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8); gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_PROGRESS_LABEL, 0); y += 15; // Expected RCT2_GLOBAL(0x013CE952, uint16) = STR_UNKNOWN; - if (RCT2_GLOBAL(0x01357CF3, uint8) != 0) { + if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != 0) { uint16 expectedDay = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY, uint8); if (expectedDay != 255) { RCT2_GLOBAL(0x013CE952 + 2, uint16) = STR_DATE_DAY_1 + expectedDay; @@ -529,13 +530,13 @@ static void window_research_funding_invalidate() // Checkboxes int activeResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES, uint16); - int uncompletedResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_UNCOMPLETED_RESEARCH_TYPES, uint16); + int uncompletedResearchTypes = gResearchUncompletedCategories; for (int i = 0; i < 7; i++) { int mask = 1 << i; int widgetMask = 1 << (i + WIDX_TRANSPORT_RIDES); // Set checkbox disabled if research type is complete - if (uncompletedResearchTypes & mask) { + if (gResearchUncompletedCategories & mask) { w->disabled_widgets &= ~widgetMask; // Set checkbox ticked if research type is active