2018-04-16 12:52:13 +02:00
# include "global.h"
# include "dewford_trend.h"
# include "easy_chat.h"
# include "event_data.h"
# include "link.h"
2019-09-09 03:07:54 +02:00
# include "malloc.h"
2018-04-16 12:52:13 +02:00
# include "random.h"
# include "text.h"
# include "tv.h"
2018-11-21 21:58:35 +01:00
# include "string_util.h"
2018-04-16 12:52:13 +02:00
2021-03-31 21:53:01 +02:00
/*
# # Overview ##
This file handles the " Dewford Trend " , a pair of Easy Chat words
repeated by NPCs around Dewford Hall .
The NPC outside Dewford Hall will ask what the player thinks of the
current trendy phrase , and the player may submit a new pair of words .
If the NPC thinks the submitted phrase is " trendier " than the
current one ( see TrySetTrendyPhrase ) , it becomes the new phrase .
# # struct DewfordTrend ##
Information about a Dewford trend is stored in a struct DewfordTrend .
In addition to the two easy chat words that make up the trend ' s phrase ,
each trend has a few randomly generated values associated with it .
2021-08-25 00:59:32 +02:00
- rand :
2021-03-31 21:53:01 +02:00
This is a 16 bit value generated once when the phrase is created .
It ' s used in calculations for Feebas tiles , Slot Machines , and Match Call .
2021-08-25 00:59:32 +02:00
- trendiness / maxTrendiness :
2021-03-31 21:53:01 +02:00
Initialized as a random value between 30 - 127 inclusive . This is used to
compare how trendy one phrase is vs another . If a submitted phrase is
less trendy than the current one it won ' t be accepted . If the trend is
2021-08-25 00:59:32 +02:00
" boring " ( see below ) it will lose trendiness over time until it reaches 0 ,
2021-03-31 21:53:01 +02:00
at which point it will stop being boring and gain trendiness until it
reaches maxTrendiness ( then it becomes boring again and the cycle repeats ) .
2021-08-25 00:59:32 +02:00
- gainingTrendiness :
2021-03-31 21:53:01 +02:00
This is a flag that determines whether a phrase should be gaining or losing
trendiness . An NPC in Dewford Hall will comment on whether the current phrase
is " boring " or not , and if it is gaining trendiness ( or if it is still trendier
2021-08-25 00:59:32 +02:00
than the last phrase ) it is not boring . This field will always be TRUE for any
2021-03-31 21:53:01 +02:00
new phrase submitted after the 1 st submission .
# # Saving trends ##
2021-08-25 00:59:32 +02:00
Each time a potential trendy phrase is submitted , it is saved in gSaveBlock1Ptr - > dewfordTrends [ ] .
Up to SAVED_TRENDS_COUNT ( 5 ) trends may be saved at one time . The trends in this array are kept
in sorted order from most trendy to least trendy . The current trendy phrase is always at
gSaveBlock1Ptr - > dewfordTrends [ 0 ] . If the player mixes records with another player , their own
trends are replaced with their mixing partner ' s , unless the phrase is the same , in which case
2021-03-31 22:29:42 +02:00
the version with a higher trendiness value is used ( see ReceiveDewfordTrendData ) .
# # TV Show ##
If a submitted phrase is only trendier than 1 or none of the saved trends , it may trigger a
TV Show called Trend Watcher ( see TryPutTrendWatcherOnAir ) that , ironically , spends the
show talking about how the submitted phrase was not trendy .
2021-03-31 21:53:01 +02:00
*/
enum {
SORT_MODE_NORMAL ,
SORT_MODE_MAX_FIRST ,
SORT_MODE_FULL ,
} ;
static void SortTrends ( struct DewfordTrend * , u16 , u8 ) ;
static bool8 CompareTrends ( struct DewfordTrend * , struct DewfordTrend * , u8 ) ;
static void SeedTrendRng ( struct DewfordTrend * ) ;
static bool8 IsPhraseInSavedTrends ( u16 * ) ;
static bool8 IsEasyChatPairEqual ( u16 * , u16 * ) ;
static s16 GetSavedTrendIndex ( struct DewfordTrend * , struct DewfordTrend * , u16 ) ;
2018-04-16 12:52:13 +02:00
void InitDewfordTrend ( void )
{
u16 i ;
2021-03-31 21:53:01 +02:00
for ( i = 0 ; i < SAVED_TRENDS_COUNT ; i + + )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
gSaveBlock1Ptr - > dewfordTrends [ i ] . words [ 0 ] = GetRandomEasyChatWordFromGroup ( EC_GROUP_CONDITIONS ) ;
2018-04-16 12:52:13 +02:00
if ( Random ( ) & 1 )
2021-03-31 21:53:01 +02:00
gSaveBlock1Ptr - > dewfordTrends [ i ] . words [ 1 ] = GetRandomEasyChatWordFromGroup ( EC_GROUP_LIFESTYLE ) ;
2018-04-16 12:52:13 +02:00
else
2021-03-31 21:53:01 +02:00
gSaveBlock1Ptr - > dewfordTrends [ i ] . words [ 1 ] = GetRandomEasyChatWordFromGroup ( EC_GROUP_HOBBIES ) ;
2018-04-16 12:52:13 +02:00
2021-03-31 21:53:01 +02:00
gSaveBlock1Ptr - > dewfordTrends [ i ] . gainingTrendiness = Random ( ) & 1 ;
SeedTrendRng ( & ( gSaveBlock1Ptr - > dewfordTrends [ i ] ) ) ;
2018-04-16 12:52:13 +02:00
}
2021-03-31 21:53:01 +02:00
SortTrends ( gSaveBlock1Ptr - > dewfordTrends , SAVED_TRENDS_COUNT , SORT_MODE_NORMAL ) ;
2018-04-16 12:52:13 +02:00
}
2021-03-31 21:53:01 +02:00
void UpdateDewfordTrendPerDay ( u16 days )
2018-04-16 12:52:13 +02:00
{
u16 i ;
2021-03-31 21:53:01 +02:00
if ( days ! = 0 )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
u32 clockRand = days * 5 ;
2018-04-16 12:52:13 +02:00
2021-03-31 21:53:01 +02:00
for ( i = 0 ; i < SAVED_TRENDS_COUNT ; i + + )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
u32 trendiness ;
u32 rand = clockRand ;
struct DewfordTrend * trend = & gSaveBlock1Ptr - > dewfordTrends [ i ] ;
2018-04-16 12:52:13 +02:00
2021-03-31 21:53:01 +02:00
if ( ! trend - > gainingTrendiness )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
// This trend is "boring"
// Lose trendiness until it becomes 0
if ( trend - > trendiness > = ( u16 ) rand )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
trend - > trendiness - = rand ;
if ( trend - > trendiness = = 0 )
trend - > gainingTrendiness = TRUE ;
2018-04-16 12:52:13 +02:00
continue ;
}
2021-03-31 21:53:01 +02:00
rand - = trend - > trendiness ;
trend - > trendiness = 0 ;
trend - > gainingTrendiness = TRUE ;
2018-04-16 12:52:13 +02:00
}
2021-03-31 21:53:01 +02:00
trendiness = trend - > trendiness + rand ;
if ( ( u16 ) trendiness > trend - > maxTrendiness )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
// Reached limit, reset trendiness
u32 newTrendiness = trendiness % trend - > maxTrendiness ;
trendiness = trendiness / trend - > maxTrendiness ;
2018-04-16 12:52:13 +02:00
2021-03-31 21:53:01 +02:00
trend - > gainingTrendiness = trendiness ^ 1 ;
if ( trend - > gainingTrendiness )
trend - > trendiness = newTrendiness ;
2018-04-16 12:52:13 +02:00
else
2021-03-31 21:53:01 +02:00
trend - > trendiness = trend - > maxTrendiness - newTrendiness ;
2018-04-16 12:52:13 +02:00
}
else
{
2021-03-31 21:53:01 +02:00
// Increase trendiness
trend - > trendiness = trendiness ;
2018-04-16 12:52:13 +02:00
2021-03-31 21:53:01 +02:00
// Trend has reached its max, becoming "boring" and start losing trendiness
if ( trend - > trendiness = = trend - > maxTrendiness )
trend - > gainingTrendiness = FALSE ;
2018-04-16 12:52:13 +02:00
}
}
2021-03-31 21:53:01 +02:00
SortTrends ( gSaveBlock1Ptr - > dewfordTrends , SAVED_TRENDS_COUNT , SORT_MODE_NORMAL ) ;
2018-04-16 12:52:13 +02:00
}
}
2021-03-31 21:53:01 +02:00
// Returns TRUE if the current trendy phrase was successfully changed to the given phrase
// Returns FALSE otherwise
2021-03-31 22:29:42 +02:00
// Regardless of whether or not the current trendy phrase was changed, the submitted
// phrase is always saved in gSaveBlock1Ptr->dewfordTrends
2021-03-31 21:53:01 +02:00
bool8 TrySetTrendyPhrase ( u16 * phrase )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
struct DewfordTrend trend = { 0 } ;
2018-04-16 12:52:13 +02:00
u16 i ;
2021-03-31 21:53:01 +02:00
if ( ! IsPhraseInSavedTrends ( phrase ) )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
if ( ! FlagGet ( FLAG_SYS_CHANGED_DEWFORD_TREND ) )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
FlagSet ( FLAG_SYS_CHANGED_DEWFORD_TREND ) ;
// Make sure player couldn't have received this phrase by mixing records
2018-04-16 12:52:13 +02:00
if ( ! FlagGet ( FLAG_SYS_MIX_RECORD ) )
{
2021-03-31 21:53:01 +02:00
// This is the first time submitting a phrase
// No need to check saved phrases or reset rng, just set the new words
gSaveBlock1Ptr - > dewfordTrends [ 0 ] . words [ 0 ] = phrase [ 0 ] ;
gSaveBlock1Ptr - > dewfordTrends [ 0 ] . words [ 1 ] = phrase [ 1 ] ;
2018-04-16 12:52:13 +02:00
return TRUE ;
}
}
2021-03-31 21:53:01 +02:00
// Initialize DewfordTrend using given phrase
trend . words [ 0 ] = phrase [ 0 ] ;
trend . words [ 1 ] = phrase [ 1 ] ;
trend . gainingTrendiness = TRUE ;
SeedTrendRng ( & trend ) ;
2018-04-16 12:52:13 +02:00
2021-03-31 21:53:01 +02:00
for ( i = 0 ; i < SAVED_TRENDS_COUNT ; i + + )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
if ( CompareTrends ( & trend , & ( gSaveBlock1Ptr - > dewfordTrends [ i ] ) , SORT_MODE_NORMAL ) )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
// New trend is "trendier" than dewfordTrend[i]
// Shift other trends back to insert new trend
u16 j = SAVED_TRENDS_COUNT - 1 ;
while ( j > i )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
gSaveBlock1Ptr - > dewfordTrends [ j ] = gSaveBlock1Ptr - > dewfordTrends [ j - 1 ] ;
j - - ;
2018-04-16 12:52:13 +02:00
}
2021-03-31 21:53:01 +02:00
gSaveBlock1Ptr - > dewfordTrends [ i ] = trend ;
if ( i = = SAVED_TRENDS_COUNT - 1 )
TryPutTrendWatcherOnAir ( phrase ) ;
// If i is 0, the given phrase is the new current phrase
2018-04-16 12:52:13 +02:00
return ( i = = 0 ) ;
}
}
2021-03-31 21:53:01 +02:00
// New trend is less "trendy" than all other saved trends, put it in last
gSaveBlock1Ptr - > dewfordTrends [ SAVED_TRENDS_COUNT - 1 ] = trend ;
TryPutTrendWatcherOnAir ( phrase ) ;
2018-04-16 12:52:13 +02:00
}
return FALSE ;
}
2021-03-31 21:53:01 +02:00
static void SortTrends ( struct DewfordTrend * trends , u16 numTrends , u8 mode )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
u16 i ;
for ( i = 0 ; i < numTrends ; i + + )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
u16 j ;
for ( j = i + 1 ; j < numTrends ; j + + )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
if ( CompareTrends ( & trends [ j ] , & trends [ i ] , mode ) )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
struct DewfordTrend temp ;
SWAP ( trends [ j ] , trends [ i ] , temp ) ;
2018-04-16 12:52:13 +02:00
}
}
}
}
2021-03-31 21:53:01 +02:00
# define SAVED_TRENDS_SIZE (sizeof(struct DewfordTrend) * SAVED_TRENDS_COUNT)
# define BUFFER_SIZE (SAVED_TRENDS_SIZE * MAX_LINK_PLAYERS > 0x100 ? SAVED_TRENDS_SIZE * MAX_LINK_PLAYERS : 0x100) // More space was allocated than needed
void ReceiveDewfordTrendData ( struct DewfordTrend * linkedTrends , size_t size , u8 unused )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
u16 i , j , numTrends , players ;
struct DewfordTrend * linkedTrendsBuffer , * savedTrendsBuffer , * src , * dst , * temp ;
2018-04-16 12:52:13 +02:00
2021-03-31 21:53:01 +02:00
// Exit if alloc fails
if ( ! ( linkedTrendsBuffer = Alloc ( BUFFER_SIZE ) ) )
return ;
// Exit if alloc fails
if ( ! ( savedTrendsBuffer = Alloc ( BUFFER_SIZE ) ) )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
Free ( linkedTrendsBuffer ) ;
return ;
}
// Buffer the new trends being received via Record Mixing
players = GetLinkPlayerCount ( ) ;
for ( i = 0 ; i < players ; i + + )
memcpy ( & linkedTrendsBuffer [ i * SAVED_TRENDS_COUNT ] , ( u8 * ) linkedTrends + i * size , SAVED_TRENDS_SIZE ) ;
2021-08-25 00:59:32 +02:00
2021-03-31 21:53:01 +02:00
// Determine which of the received trends should be saved.
// savedTrendsBuffer starts empty, and when finished will contain
// which of the linked trends to save in the saveblock.
src = linkedTrendsBuffer ;
dst = savedTrendsBuffer ;
numTrends = 0 ;
for ( i = 0 ; i < players ; i + + )
{
for ( j = 0 ; j < SAVED_TRENDS_COUNT ; j + + )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
s16 idx = GetSavedTrendIndex ( savedTrendsBuffer , src , numTrends ) ;
if ( idx < 0 )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
// This phrase is not a currently saved trend, save it
* ( dst + + ) = * src ;
numTrends + + ;
}
else
{
// This phrase already exists as a saved phrase
// Only overwrrite it if it's "trendier"
temp = & savedTrendsBuffer [ idx ] ;
if ( temp - > trendiness < src - > trendiness )
* temp = * src ;
2018-04-16 12:52:13 +02:00
}
2021-03-31 21:53:01 +02:00
src + + ;
2018-04-16 12:52:13 +02:00
}
}
2021-03-31 21:53:01 +02:00
SortTrends ( savedTrendsBuffer , numTrends , SORT_MODE_FULL ) ;
2021-08-25 00:59:32 +02:00
2021-03-31 21:53:01 +02:00
// Overwrite current saved trends with new saved trends
src = savedTrendsBuffer ;
dst = gSaveBlock1Ptr - > dewfordTrends ;
for ( i = 0 ; i < SAVED_TRENDS_COUNT ; i + + )
* ( dst + + ) = * ( src + + ) ;
Free ( linkedTrendsBuffer ) ;
Free ( savedTrendsBuffer ) ;
2018-04-16 12:52:13 +02:00
}
void BufferTrendyPhraseString ( void )
{
2021-03-31 21:53:01 +02:00
struct DewfordTrend * trend = & gSaveBlock1Ptr - > dewfordTrends [ gSpecialVar_0x8004 ] ;
ConvertEasyChatWordsToString ( gStringVar1 , trend - > words , 2 , 1 ) ;
2018-04-16 12:52:13 +02:00
}
2021-03-31 21:53:01 +02:00
// Returns TRUE if the current trendy phrase is "boring", FALSE otherwise
// This only influences the comment of an NPC inside the Dewford Town Hall
void IsTrendyPhraseBoring ( void )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
bool16 result = FALSE ;
2021-08-25 00:59:32 +02:00
2020-10-26 05:29:55 +01:00
do
2020-09-09 23:02:52 +02:00
{
2021-03-31 21:53:01 +02:00
if ( gSaveBlock1Ptr - > dewfordTrends [ 0 ] . trendiness - gSaveBlock1Ptr - > dewfordTrends [ 1 ] . trendiness > 1 )
2020-10-26 05:29:55 +01:00
break ;
2021-03-31 21:53:01 +02:00
if ( gSaveBlock1Ptr - > dewfordTrends [ 0 ] . gainingTrendiness )
2020-10-26 05:29:55 +01:00
break ;
2021-03-31 21:53:01 +02:00
if ( ! gSaveBlock1Ptr - > dewfordTrends [ 1 ] . gainingTrendiness )
2020-10-26 05:29:55 +01:00
break ;
2021-03-31 21:53:01 +02:00
result = TRUE ;
2020-10-26 05:29:55 +01:00
} while ( 0 ) ;
2021-08-25 00:59:32 +02:00
2020-09-09 23:02:52 +02:00
gSpecialVar_Result = result ;
}
2018-04-16 12:52:13 +02:00
2021-03-31 21:53:01 +02:00
// A painting hangs on the wall of the Dewford Hall
// When interacted with it says "{trendy phrase}'S {name} is the title"
// {name} is one of 8 pre-set words, depending on the current phrase
// See DewfordTown_Hall_EventScript_Painting
2018-04-16 12:52:13 +02:00
void GetDewfordHallPaintingNameIndex ( void )
{
2021-03-31 21:53:01 +02:00
gSpecialVar_Result = ( gSaveBlock1Ptr - > dewfordTrends [ 0 ] . words [ 0 ] + gSaveBlock1Ptr - > dewfordTrends [ 0 ] . words [ 1 ] ) & 7 ;
2018-04-16 12:52:13 +02:00
}
2021-03-31 21:53:01 +02:00
// Returns TRUE if a > b (a is "trendier" than b), FALSE if a < b (b is "trendier" than a)
// How one trend is compared to the other depends on the mode
// In SORT_MODE_FULL if the trends are equal then TRUE is always returned, otherwise TRUE or FALSE is returned randomly
static bool8 CompareTrends ( struct DewfordTrend * a , struct DewfordTrend * b , u8 mode )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
switch ( mode )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
case SORT_MODE_NORMAL :
if ( a - > trendiness > b - > trendiness ) return TRUE ;
if ( a - > trendiness < b - > trendiness ) return FALSE ;
if ( a - > maxTrendiness > b - > maxTrendiness ) return TRUE ;
if ( a - > maxTrendiness < b - > maxTrendiness ) return FALSE ;
2018-04-16 12:52:13 +02:00
break ;
2021-03-31 21:53:01 +02:00
case SORT_MODE_MAX_FIRST : // Unused
if ( a - > maxTrendiness > b - > maxTrendiness ) return TRUE ;
if ( a - > maxTrendiness < b - > maxTrendiness ) return FALSE ;
if ( a - > trendiness > b - > trendiness ) return TRUE ;
if ( a - > trendiness < b - > trendiness ) return FALSE ;
2018-04-16 12:52:13 +02:00
break ;
2021-03-31 21:53:01 +02:00
case SORT_MODE_FULL :
if ( a - > trendiness > b - > trendiness ) return TRUE ;
if ( a - > trendiness < b - > trendiness ) return FALSE ;
if ( a - > maxTrendiness > b - > maxTrendiness ) return TRUE ;
if ( a - > maxTrendiness < b - > maxTrendiness ) return FALSE ;
if ( a - > rand > b - > rand ) return TRUE ;
if ( a - > rand < b - > rand ) return FALSE ;
if ( a - > words [ 0 ] > b - > words [ 0 ] ) return TRUE ;
if ( a - > words [ 0 ] < b - > words [ 0 ] ) return FALSE ;
if ( a - > words [ 1 ] > b - > words [ 1 ] ) return TRUE ;
if ( a - > words [ 1 ] < b - > words [ 1 ] ) return FALSE ;
return TRUE ;
2018-04-16 12:52:13 +02:00
}
2021-03-31 21:53:01 +02:00
// Invalid mode given, or trends are equal in SORT_MODE_NORMAL or SORT_MODE_MAX_FIRST
// Randomly pick one of the phrases
2018-04-16 12:52:13 +02:00
return Random ( ) & 1 ;
}
2021-03-31 21:53:01 +02:00
static void SeedTrendRng ( struct DewfordTrend * trend )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
u16 rand ;
2018-04-16 12:52:13 +02:00
2021-03-31 21:53:01 +02:00
rand = Random ( ) % 98 ;
if ( rand > 50 )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
rand = Random ( ) % 98 ;
if ( rand > 80 )
rand = Random ( ) % 98 ;
2018-04-16 12:52:13 +02:00
}
2021-03-31 21:53:01 +02:00
trend - > maxTrendiness = rand + 30 ;
trend - > trendiness = ( Random ( ) % ( rand + 1 ) ) + 30 ;
trend - > rand = Random ( ) ;
2018-04-16 12:52:13 +02:00
}
2021-03-31 21:53:01 +02:00
static bool8 IsPhraseInSavedTrends ( u16 * phrase )
2018-04-16 12:52:13 +02:00
{
u16 i ;
2021-03-31 21:53:01 +02:00
for ( i = 0 ; i < SAVED_TRENDS_COUNT ; i + + )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
if ( IsEasyChatPairEqual ( phrase , gSaveBlock1Ptr - > dewfordTrends [ i ] . words ) )
2018-04-16 12:52:13 +02:00
return TRUE ;
}
return FALSE ;
}
static bool8 IsEasyChatPairEqual ( u16 * words1 , u16 * words2 )
{
u16 i ;
for ( i = 0 ; i < 2 ; i + + )
{
if ( * ( words1 + + ) ! = * ( words2 + + ) )
return FALSE ;
}
return TRUE ;
}
2021-03-31 21:53:01 +02:00
static s16 GetSavedTrendIndex ( struct DewfordTrend * savedTrends , struct DewfordTrend * trend , u16 numSaved )
2018-04-16 12:52:13 +02:00
{
s16 i ;
2021-03-31 21:53:01 +02:00
for ( i = 0 ; i < numSaved ; i + + )
2018-04-16 12:52:13 +02:00
{
2021-03-31 21:53:01 +02:00
if ( IsEasyChatPairEqual ( trend - > words , savedTrends - > words ) )
2018-04-16 12:52:13 +02:00
return i ;
2021-03-31 21:53:01 +02:00
savedTrends + + ;
2018-04-16 12:52:13 +02:00
}
return - 1 ;
}