2014-04-03 04:08:06 +02:00
|
|
|
/*****************************************************************************
|
2014-05-03 14:57:50 +02:00
|
|
|
* Copyright (c) 2014 Ted John, Peter Hill, Matthias Lanzinger
|
2014-04-03 04:08:06 +02:00
|
|
|
* 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"
|
2014-04-08 18:52:39 +02:00
|
|
|
#include "audio.h"
|
2014-05-02 16:09:07 +02:00
|
|
|
#include "date.h"
|
2014-04-03 04:08:06 +02:00
|
|
|
#include "news_item.h"
|
|
|
|
#include "rct2.h"
|
2014-04-11 21:02:20 +02:00
|
|
|
#include "ride.h"
|
2014-05-02 16:09:07 +02:00
|
|
|
#include "strings.h"
|
2014-04-11 21:02:20 +02:00
|
|
|
#include "sprite.h"
|
2014-04-04 22:46:26 +02:00
|
|
|
#include "window.h"
|
2014-04-03 04:08:06 +02:00
|
|
|
|
2014-04-11 04:58:17 +02:00
|
|
|
void window_game_bottom_toolbar_invalidate_news_item();
|
2014-04-08 18:52:39 +02:00
|
|
|
static int news_item_get_new_history_slot();
|
|
|
|
|
2014-04-03 04:08:06 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x0066DF32
|
|
|
|
*/
|
|
|
|
void news_item_init_queue()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
rct_news_item *newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item);
|
|
|
|
|
|
|
|
newsItems[0].type = NEWS_ITEM_NULL;
|
|
|
|
newsItems[11].type = NEWS_ITEM_NULL;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
RCT2_ADDRESS(0x01358750, uint8)[i] = 0;
|
|
|
|
|
2014-04-11 04:58:17 +02:00
|
|
|
window_game_bottom_toolbar_invalidate_news_item();
|
2014-04-04 22:46:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x0066E252
|
|
|
|
*/
|
|
|
|
void news_item_update_current()
|
|
|
|
{
|
|
|
|
short ax, bx, remove_time;
|
|
|
|
rct_news_item *newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item);
|
|
|
|
|
2014-04-08 18:52:39 +02:00
|
|
|
get_system_time();
|
2014-04-04 22:46:26 +02:00
|
|
|
|
|
|
|
ax = RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_DAY, sint16);
|
|
|
|
bx = RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_MONTH, sint16);
|
|
|
|
if (bx != RCT2_GLOBAL(0x009DEA6B, sint16)) {
|
|
|
|
bx--;
|
|
|
|
if (bx == 0)
|
|
|
|
bx = 12;
|
|
|
|
if (bx != RCT2_GLOBAL(0x009DEA6B, sint16) || ax == 1) {
|
|
|
|
// loc_66E2AE
|
|
|
|
RCT2_GLOBAL(0x013573DC, sint32) = 10000;
|
|
|
|
if (RCT2_GLOBAL(0x013573DC, sint32) >= 0)
|
|
|
|
RCT2_GLOBAL(0x013573DC, sint32) = -RCT2_GLOBAL(0x013573DC, sint32);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (ax != RCT2_GLOBAL(0x009DEA69, sint16)) {
|
|
|
|
ax--;
|
|
|
|
if (ax != RCT2_GLOBAL(0x009DEA69, sint16)) {
|
|
|
|
// loc_66E2AE
|
|
|
|
RCT2_GLOBAL(0x013573DC, sint32) = 10000;
|
|
|
|
if (RCT2_GLOBAL(0x013573DC, sint32) >= 0)
|
|
|
|
RCT2_GLOBAL(0x013573DC, sint32) = -RCT2_GLOBAL(0x013573DC, sint32);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT2_GLOBAL(0x009DEA69, sint16) = RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_DAY, sint16);
|
|
|
|
RCT2_GLOBAL(0x009DEA6B, sint16) = RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_MONTH, sint16);
|
|
|
|
|
|
|
|
// Check if there is a current news item
|
|
|
|
if (newsItems[0].type == 0)
|
|
|
|
return;
|
|
|
|
|
2014-04-11 04:58:17 +02:00
|
|
|
window_game_bottom_toolbar_invalidate_news_item();
|
2014-04-04 22:46:26 +02:00
|
|
|
|
|
|
|
// Update the current news item
|
|
|
|
newsItems[0].ticks++;
|
|
|
|
if (newsItems[0].ticks == 1 && !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 1)) {
|
|
|
|
// Play sound
|
|
|
|
sound_play_panned(39, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) / 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Removal of current news item
|
|
|
|
remove_time = 320;
|
|
|
|
if (newsItems[2].type != 0 &&
|
|
|
|
newsItems[3].type != 0 &&
|
|
|
|
newsItems[4].type != 0 &&
|
|
|
|
newsItems[5].type != 0)
|
|
|
|
remove_time = 256;
|
|
|
|
|
|
|
|
if (newsItems[0].ticks >= remove_time)
|
|
|
|
news_item_close_current();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x0066E377
|
|
|
|
*/
|
|
|
|
void news_item_close_current()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
rct_news_item *newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item);
|
|
|
|
|
|
|
|
// Check if there is a current message
|
|
|
|
if (newsItems[0].type == NEWS_ITEM_NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Find an available history news item slot for current message
|
|
|
|
i = news_item_get_new_history_slot();
|
|
|
|
|
|
|
|
// Set the history news item slot to the current news item
|
|
|
|
newsItems[i] = newsItems[0];
|
|
|
|
|
|
|
|
// Set the end of the end of the history list
|
|
|
|
if (i < 60)
|
|
|
|
newsItems[i + 1].type = NEWS_ITEM_NULL;
|
|
|
|
|
|
|
|
// Invalidate the news window
|
|
|
|
window_invalidate_by_id(WC_RECENT_NEWS, 0);
|
|
|
|
|
|
|
|
// Dequeue the current news item, shift news up
|
|
|
|
for (i = 0; i < 10; i++)
|
|
|
|
newsItems[i] = newsItems[i + 1];
|
|
|
|
newsItems[10].type = NEWS_ITEM_NULL;
|
|
|
|
|
|
|
|
// Invalidate current news item bar
|
2014-04-11 04:58:17 +02:00
|
|
|
window_game_bottom_toolbar_invalidate_news_item();
|
2014-04-04 22:46:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Finds a spare history slot or replaces an existing one if there are no spare
|
|
|
|
* slots available.
|
|
|
|
*/
|
2014-04-08 18:52:39 +02:00
|
|
|
static int news_item_get_new_history_slot()
|
2014-04-04 22:46:26 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
rct_news_item *newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item);
|
|
|
|
|
|
|
|
// Find an available history news item slot
|
|
|
|
for (i = 11; i < 61; i++)
|
|
|
|
if (newsItems[i].type == NEWS_ITEM_NULL)
|
|
|
|
return i;
|
|
|
|
|
|
|
|
// Dequeue the first history news item, shift history up
|
|
|
|
for (i = 11; i < 60; i++)
|
|
|
|
newsItems[i] = newsItems[i + 1];
|
|
|
|
return 60;
|
2014-04-11 21:02:20 +02:00
|
|
|
}
|
|
|
|
|
2014-04-12 03:14:31 +02:00
|
|
|
/**
|
2014-04-27 20:27:12 +02:00
|
|
|
* Get the (x,y,z) coordinates of the subject of a news item.
|
2014-04-29 18:40:06 +02:00
|
|
|
* If the new item is no longer valid, return SPRITE_LOCATION_NULL in the x-coordinate
|
2014-04-27 20:27:12 +02:00
|
|
|
*
|
2014-04-12 03:14:31 +02:00
|
|
|
* rct2: 0x0066BA74
|
|
|
|
*/
|
2014-04-11 21:02:20 +02:00
|
|
|
void news_item_get_subject_location(int type, int subject, int *x, int *y, int *z)
|
|
|
|
{
|
2014-04-12 03:14:31 +02:00
|
|
|
int i;
|
2014-04-11 21:02:20 +02:00
|
|
|
rct_ride *ride;
|
2014-05-01 14:02:28 +02:00
|
|
|
rct_peep *peep;
|
|
|
|
rct_car *car;
|
2014-04-11 21:02:20 +02:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case NEWS_ITEM_RIDE:
|
|
|
|
ride = &(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride)[subject]);
|
2014-05-05 19:34:24 +02:00
|
|
|
if (ride->overall_view == 0xFFFF) {
|
2014-04-29 18:40:06 +02:00
|
|
|
*x = SPRITE_LOCATION_NULL;
|
2014-04-11 21:02:20 +02:00
|
|
|
break;
|
|
|
|
}
|
2014-05-05 19:34:24 +02:00
|
|
|
*x = (ride->overall_view & 0xFF) * 32 + 16;
|
|
|
|
*y = (ride->overall_view >> 8) * 32 + 16;
|
2014-05-02 21:25:42 +02:00
|
|
|
*z = map_element_height(*x, *y);
|
2014-04-11 21:02:20 +02:00
|
|
|
break;
|
2014-05-01 13:23:18 +02:00
|
|
|
case NEWS_ITEM_PEEP_ON_RIDE:
|
2014-05-01 14:02:28 +02:00
|
|
|
peep = &(RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LIST, rct_sprite)[subject]);
|
|
|
|
*x = peep->x;
|
|
|
|
*y = peep->y;
|
|
|
|
*z = peep->z;
|
2014-05-01 13:16:41 +02:00
|
|
|
if (*((uint16*)x) != SPRITE_LOCATION_NULL)
|
2014-04-12 03:14:31 +02:00
|
|
|
break;
|
|
|
|
|
2014-05-01 14:02:28 +02:00
|
|
|
if (peep->state != 3 && peep->state != 7) {
|
2014-04-29 18:40:06 +02:00
|
|
|
*x = SPRITE_LOCATION_NULL;
|
2014-04-12 03:14:31 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-05-01 13:16:41 +02:00
|
|
|
// Find which ride peep is on
|
2014-05-01 14:02:28 +02:00
|
|
|
ride = &(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride)[peep->current_ride]);
|
2014-05-01 13:16:41 +02:00
|
|
|
// Check if there are trains on the track (first bit of var_1D0)
|
|
|
|
if (!(ride->var_1D0 & 1)) {
|
2014-04-29 18:40:06 +02:00
|
|
|
*x = SPRITE_LOCATION_NULL;
|
2014-04-12 03:14:31 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-05-01 14:12:30 +02:00
|
|
|
// Find the first car of the train peep is on
|
2014-05-01 14:02:28 +02:00
|
|
|
car = &(RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LIST, rct_sprite)[ride->train_car_map[peep->current_train]]);
|
2014-05-01 14:12:30 +02:00
|
|
|
// Find the actual car peep is on
|
2014-05-01 14:02:28 +02:00
|
|
|
for (i = 0; i < peep->current_car; i++)
|
|
|
|
car = &(RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LIST, rct_sprite)[car->next_car]);
|
|
|
|
*x = car->x;
|
|
|
|
*y = car->y;
|
|
|
|
*z = car->z;
|
2014-04-11 21:02:20 +02:00
|
|
|
break;
|
2014-05-01 13:23:18 +02:00
|
|
|
case NEWS_ITEM_PEEP:
|
2014-05-01 14:02:28 +02:00
|
|
|
peep = &(RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LIST, rct_sprite)[subject]);
|
|
|
|
*x = peep->x;
|
|
|
|
*y = peep->y;
|
|
|
|
*z = peep->z;
|
2014-04-11 21:02:20 +02:00
|
|
|
break;
|
|
|
|
case NEWS_ITEM_BLANK:
|
2014-05-03 10:24:25 +02:00
|
|
|
*x = subject;
|
|
|
|
*y = subject >> 16;
|
|
|
|
*z = map_element_height(*x, *y);
|
|
|
|
break;
|
2014-04-11 21:02:20 +02:00
|
|
|
default:
|
2014-04-29 18:40:06 +02:00
|
|
|
*x = SPRITE_LOCATION_NULL;
|
2014-04-11 21:02:20 +02:00
|
|
|
break;
|
|
|
|
}
|
2014-04-21 11:27:48 +02:00
|
|
|
}
|
2014-05-02 16:09:07 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* rct2: 0x0066DF55
|
|
|
|
*
|
|
|
|
* @param a (al)
|
|
|
|
* @param string_id (ebx)
|
|
|
|
* @param c (ecx)
|
|
|
|
**/
|
|
|
|
void news_item_add_to_queue(uint8 type, rct_string_id string_id, uint32 assoc)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
rct_news_item *newsItem = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item);
|
|
|
|
|
|
|
|
// find first open slot
|
|
|
|
while (newsItem->type != NEWS_ITEM_NULL) {
|
|
|
|
if (newsItem + sizeof(newsItem) >= 0x13CB1CC)
|
|
|
|
news_item_close_current();
|
|
|
|
else
|
|
|
|
newsItem++;
|
|
|
|
}
|
|
|
|
|
|
|
|
//now we have found an item slot to place the new news in
|
|
|
|
newsItem->type = type;
|
|
|
|
newsItem->flags = 0;
|
|
|
|
newsItem->assoc = assoc;
|
|
|
|
newsItem->ticks = 0;
|
|
|
|
newsItem->month = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16);
|
|
|
|
newsItem->day = (days_in_month[(newsItem->month & 7)] * RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16)) >> 16;
|
|
|
|
|
|
|
|
format_string(0x0141EF68, string_id, 0x013CE952); // overflows possible?
|
|
|
|
newsItem->colour = ((char*)0x0141EF68)[0];
|
|
|
|
strncpy(newsItem->text, 0x0141EF68, 255);
|
|
|
|
newsItem->text[254] = 0;
|
|
|
|
|
|
|
|
// blatant disregard for what happens on the last element.
|
|
|
|
// Change this when we implement the queue ourselves.
|
|
|
|
newsItem++;
|
|
|
|
newsItem->type = 0;
|
|
|
|
}
|