mirror of
https://github.com/thug1src/thug.git
synced 2025-01-22 05:43:47 +00:00
2856 lines
87 KiB
C++
2856 lines
87 KiB
C++
/*****************************************************************************
|
|
** **
|
|
** Neversoft Entertainment. **
|
|
** **
|
|
** Copyright (C) 2000 - All Rights Reserved **
|
|
** **
|
|
******************************************************************************
|
|
** **
|
|
** Project: skate3 **
|
|
** **
|
|
** Module: **
|
|
** **
|
|
** File name: **
|
|
** **
|
|
** Created by: rjm **
|
|
** **
|
|
** Description: **
|
|
** **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Includes **
|
|
*****************************************************************************/
|
|
|
|
#include <sk/modules/skate/score.h>
|
|
|
|
#include <core/defines.h>
|
|
#include <core/string/stringutils.h>
|
|
|
|
#include <gel/net/server/netserv.h>
|
|
#include <gel/net/client/netclnt.h>
|
|
|
|
#include <gel/scripting/symboltable.h>
|
|
#include <gel/scripting/script.h>
|
|
#include <gel/scripting/array.h>
|
|
#include <gel/scripting/checksum.h>
|
|
#include <gel/components/trickcomponent.h>
|
|
#include <gel/components/statsmanagercomponent.h>
|
|
#include <gel/components/animationcomponent.h>
|
|
|
|
#include <gfx/nxviewman.h>
|
|
#include <gfx/2d/screenelemman.h>
|
|
#include <gfx/2d/textelement.h>
|
|
#include <gfx/2d/spriteelement.h>
|
|
|
|
#include <sk/gamenet/gamenet.h>
|
|
#include <sk/gamenet/gamemsg.h>
|
|
|
|
#include <sk/objects/skater.h> // for control and trick stuff
|
|
#include <sk/objects/skaterprofile.h>
|
|
#include <sk/objects/skatercareer.h>
|
|
|
|
#include <sk/components/skaterruntimercomponent.h>
|
|
#include <sk/components/skateradjustphysicscomponent.h>
|
|
|
|
#include <sk/modules/skate/skate.h>
|
|
#include <sk/modules/skate/gamemode.h>
|
|
#include <sk/modules/skate/goalmanager.h>
|
|
|
|
#include <sk/scripting/cfuncs.h>
|
|
|
|
#include <sys/replay/replay.h>
|
|
|
|
namespace Front
|
|
{
|
|
extern void SetScoreTHPS4(char* score_text, int skater_num);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
** DBG Information **
|
|
*****************************************************************************/
|
|
|
|
namespace Mdl
|
|
{
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
** Externals **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Defines **
|
|
*****************************************************************************/
|
|
|
|
#define NO_SCORE_DURING_UBER_FRIG
|
|
#define MAX_SCORE_DUE_TO_TWEAK (20000)
|
|
|
|
/*****************************************************************************
|
|
** Private Types **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Private Data **
|
|
*****************************************************************************/
|
|
|
|
static const int MAX_SPIN_VALUES = 6;
|
|
static const int SPIN_MULT_VALUES[MAX_SPIN_VALUES] = {2, 3, 4, 5, 6, 7};
|
|
static const int MAX_DEPREC = 5;
|
|
static const int DEPREC_VALUES[MAX_DEPREC] = {100, 75, 50, 25, 10};
|
|
|
|
|
|
/*****************************************************************************
|
|
** Public Data **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Private Prototypes **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Private Functions **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Public Functions **
|
|
*****************************************************************************/
|
|
|
|
// given a score increment, return a value by which it should be decremented
|
|
// basically return the closest multiple of 10 below score
|
|
int score_increment(int score)
|
|
{
|
|
if (score >1000000) return 1000000;
|
|
if (score >100000) return 100000;
|
|
if (score >10000) return 10000;
|
|
if (score >10000) return 1000;
|
|
if (score >1000) return 100;
|
|
if (score >100) return 100;
|
|
if (score >10) return 10;
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
|
|
Score::Score() :
|
|
m_historyTab(16),
|
|
m_infoTab(8)
|
|
{
|
|
m_skaterId = 0;
|
|
m_totalScore = 0;
|
|
m_scorePot = 0;
|
|
m_recentScorePot = 0;
|
|
m_recentSpecialScorePot = 0;
|
|
m_currentTrick = 0;
|
|
m_currentMult = 0;
|
|
m_currentBlockingTrick = -1;
|
|
m_currentSpinTrick = -1;
|
|
|
|
m_specialScore = 0;
|
|
set_special_is_active(false);
|
|
|
|
m_special_interpolator = 0.0f;
|
|
|
|
m_longestCombo = 0;
|
|
m_bestCombo = 0;
|
|
m_bestGameCombo = 0;
|
|
|
|
//mp_trickWindow = NULL;
|
|
|
|
m_debug = (bool) Script::GetInteger("print_trick_info");
|
|
|
|
setup_balance_meter_stuff();
|
|
}
|
|
|
|
|
|
|
|
|
|
Score::~Score()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
int Score::get_packed_score( int start, int end )
|
|
{
|
|
int packed_score = 0;
|
|
int current_spin_mult = 2; // n over 2
|
|
for (int i = start; i < end; i++)
|
|
{
|
|
// if a blocking trick, use default spin multiplier
|
|
if (m_infoTab[i].flags & vBLOCKING)
|
|
{
|
|
current_spin_mult = 2;
|
|
}
|
|
// if not a blocking trick, but the last trick was, then use the spin multiplier here
|
|
// to apply to subsequent tricks up to next blocking one
|
|
else if (i == 0 || (m_infoTab[i-1].flags & vBLOCKING))
|
|
{
|
|
current_spin_mult = spinMult(m_infoTab[i].spin_mult_index);
|
|
}
|
|
|
|
int deprec_mult = deprecMult(m_infoTab[i].mult_index);
|
|
|
|
// if (m_debug)
|
|
// printf(" base score %d, reduction mult %.2f, spin mult %.1f\n",
|
|
// m_infoTab[i].score, (float) deprec_mult / 100, (float) current_spin_mult / 2);
|
|
|
|
int score = (m_infoTab[i].score * deprec_mult * current_spin_mult) / 200;
|
|
if (m_infoTab[i].switch_mode)
|
|
{
|
|
score = score * 120 / 100;
|
|
}
|
|
|
|
packed_score += score;
|
|
}
|
|
return packed_score;
|
|
}
|
|
|
|
void Score::pack_trick_info_table()
|
|
{
|
|
TrickInfo theTrickInfo;
|
|
strcpy( theTrickInfo.trickNameText, "... + " );
|
|
strcpy( theTrickInfo.trickTextFormatted, "...\\_+\\_" );
|
|
theTrickInfo.score = 0;
|
|
theTrickInfo.id = 0;
|
|
theTrickInfo.switch_mode = 0;
|
|
theTrickInfo.flags = 0;
|
|
theTrickInfo.mult_index = 0;
|
|
theTrickInfo.spin_mult_index = 0;
|
|
theTrickInfo.spin_degrees = 0;
|
|
|
|
int firstBlockingTrick = m_infoTab.GetSize();
|
|
|
|
for ( int i = 0; i < m_infoTab.GetSize(); i++ )
|
|
{
|
|
// if ( ( i != 0 ) && ( m_infoTab[i].flags & vBLOCKING ) )
|
|
if ( ( i != 0 ) && ( m_infoTab[i].trickNameText[0] == 0 ) )
|
|
{
|
|
firstBlockingTrick = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// GJ: see note below
|
|
if ( ( firstBlockingTrick > m_currentSpinTrick )
|
|
|| ( firstBlockingTrick > m_currentBlockingTrick ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
theTrickInfo.score = get_packed_score( 0, firstBlockingTrick );
|
|
|
|
// shift them all...
|
|
for ( int i = 0; i < firstBlockingTrick; i++ )
|
|
{
|
|
m_infoTab.Remove( 1 );
|
|
|
|
m_currentTrick--;
|
|
m_currentSpinTrick--;
|
|
m_currentBlockingTrick--;
|
|
|
|
// GJ: these asserts will fire off if the trick list is filled
|
|
// with more non-blocking tricks than spin tricks... it rarely
|
|
// happens, except for those glitches that lets the player do
|
|
// infinite tricks. The if-test above will abort early,
|
|
// allowing the calling function ( Trigger() ) to gracefully
|
|
// handle it
|
|
Dbg_MsgAssert( m_currentTrick > -1, ( "m_currentTrick is negative (%d)", m_currentTrick ) );
|
|
Dbg_MsgAssert( m_currentSpinTrick > -1, ( "m_currentSpinTrick is negative (%d)", m_currentSpinTrick ) );
|
|
Dbg_MsgAssert( m_currentBlockingTrick > -1, ( "m_currentBlockingTrick is negative (%d)", m_currentBlockingTrick ) );
|
|
}
|
|
|
|
m_infoTab[0] = theTrickInfo;
|
|
|
|
// so that the packed score will be correct next time
|
|
m_infoTab[0].flags |= vBLOCKING;
|
|
|
|
#ifdef __USER_GARY__
|
|
Dbg_Message( "Info table has %d elements.", m_infoTab.GetSize() );
|
|
#endif
|
|
}
|
|
|
|
void Score::print_trick_info_table()
|
|
{
|
|
for ( int i = 0; i < m_infoTab.GetSize(); i++ )
|
|
{
|
|
printf( "info table %d\n", i );
|
|
printf( "\ttrickname = %s\n", m_infoTab[i].trickNameText);
|
|
printf( "\ttrickformatted = %s\n", m_infoTab[i].trickTextFormatted);
|
|
printf( "\tscore = %d\n", m_infoTab[i].score);
|
|
printf( "\tmult_index = %d\n", m_infoTab[i].mult_index);
|
|
printf( "\tspin_mult_index = %d\n", m_infoTab[i].spin_mult_index);
|
|
printf( "\tswitch_mode = %d\n", m_infoTab[i].switch_mode);
|
|
/*
|
|
m_infoTab[i].id,
|
|
m_infoTab[i].switch_mode,
|
|
m_infoTab[i].flags,
|
|
*/
|
|
printf( "-------------------------------------\n" );
|
|
}
|
|
}
|
|
|
|
void Score::Update()
|
|
{
|
|
if (m_specialScore)
|
|
{
|
|
// shrink special bar
|
|
if (m_specialIsActive)
|
|
m_specialScore = (int) ((float) m_specialScore - (float) Tmr::FrameLength() * 200.0f / Tmr::vRESOLUTION);
|
|
else
|
|
m_specialScore = (int) ((float) m_specialScore - (float) Tmr::FrameLength() * 50.0f / Tmr::vRESOLUTION);
|
|
if (m_specialScore <= 0)
|
|
{
|
|
set_special_is_active(false);
|
|
m_specialScore = 0;
|
|
}
|
|
}
|
|
|
|
if (m_scorePotState == WAITING_TO_COUNT_SCORE_POT)
|
|
{
|
|
m_scorePotCountdown--;
|
|
if (!m_scorePotCountdown)
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Obj::CSkater* pSkater = skate_mod->GetSkaterById( m_skaterId );
|
|
int index;
|
|
|
|
index = 0;
|
|
if( pSkater )
|
|
{
|
|
index = pSkater->GetHeapIndex();
|
|
}
|
|
TrickTextCountdown(index);
|
|
Replay::WriteTrickTextCountdown();
|
|
|
|
m_scorePotState = SHOW_COUNTED_SCORE_POT;
|
|
}
|
|
}
|
|
else if (m_scorePotState == SHOW_COUNTED_SCORE_POT)
|
|
{
|
|
dispatch_score_pot_value_to_screen(m_countedScorePot, 0);
|
|
m_countedScorePot -= score_increment(m_countedScorePot);
|
|
if (m_countedScorePot < 0)
|
|
{
|
|
m_countedScorePot = 0;
|
|
m_scorePotState = SHOW_ACTUAL_SCORE_POT;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
Image::RGBA m_special_rgba[3];
|
|
float m_special_interpolator;
|
|
float m_special_interpolator_rate;
|
|
#endif
|
|
|
|
Front::CScreenElementManager* p_manager = Front::CScreenElementManager::Instance();
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Front::CScreenElementPtr p_special_bar;
|
|
|
|
Obj::CSkater* pSkater = skate_mod->GetSkaterById( m_skaterId );
|
|
if( pSkater )
|
|
{
|
|
p_special_bar = p_manager->GetElement(CRCD(0xfe1dc544,"the_special_bar_sprite") + pSkater->GetHeapIndex());
|
|
}
|
|
else
|
|
{
|
|
p_special_bar = p_manager->GetElement(CRCD(0xfe1dc544,"the_special_bar_sprite"));
|
|
}
|
|
// clamp scale of bar, so that it doesn't get all crazy
|
|
float special_mult = m_specialScore / 3000.0f;
|
|
if (special_mult > 1.0f)
|
|
special_mult = 1.0f;
|
|
else if (special_mult < 0.0f)
|
|
special_mult = 0.0f;
|
|
p_special_bar->SetScale(special_mult, p_special_bar->GetScaleY());
|
|
Image::RGBA special_rgba = m_special_rgba[REGULAR_SPECIAL];
|
|
if (m_specialIsActive)
|
|
{
|
|
float interpolate_mult = (cosf(m_special_interpolator) + 1.0f) / 2.0f;
|
|
m_special_interpolator += m_special_interpolator_rate;
|
|
|
|
special_rgba.r = (uint8) ((float) m_special_rgba[1].r + ((float) (m_special_rgba[2].r - m_special_rgba[1].r)) * interpolate_mult);
|
|
special_rgba.g = (uint8) ((float) m_special_rgba[1].g + ((float) (m_special_rgba[2].g - m_special_rgba[1].g)) * interpolate_mult);
|
|
special_rgba.b = (uint8) ((float) m_special_rgba[1].b + ((float) (m_special_rgba[2].b - m_special_rgba[1].b)) * interpolate_mult);
|
|
special_rgba.a = (uint8) ((float) m_special_rgba[1].a + ((float) (m_special_rgba[2].a - m_special_rgba[1].a)) * interpolate_mult);
|
|
}
|
|
p_special_bar->SetRGBA(special_rgba);
|
|
|
|
/*
|
|
HUD::PanelMgr* panel_mgr = HUD::PanelMgr::Instance();
|
|
HUD::Panel* panel;
|
|
|
|
if(( panel = panel_mgr->GetPanelBySkaterId(m_skaterId, false)))
|
|
{
|
|
panel->SetSpecialPercent((float) m_specialScore / 3000.0f, m_specialIsActive);
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Called from CSkater constructor
|
|
*/
|
|
void Score::SetSkaterId(short skater_id)
|
|
{
|
|
m_skaterId = skater_id;
|
|
//HUD::PanelMgr* panel_mgr = HUD::PanelMgr::Instance();
|
|
//mp_trickWindow = panel_mgr->GetTrickWindow(m_skaterId);
|
|
}
|
|
|
|
|
|
|
|
|
|
void Score::copy_trick_name_with_special_spaces(char *pOut, const char *pIn)
|
|
{
|
|
int count = 0;
|
|
while(*pIn != '\0')
|
|
{
|
|
Dbg_Assert(count < TrickInfo::TEXT_BUFFER_SIZE);
|
|
if (*pIn == ' ')
|
|
{
|
|
*pOut++ = '\\';
|
|
*pOut++ = '_';
|
|
count += 2;
|
|
}
|
|
else
|
|
{
|
|
*pOut++ = *pIn;
|
|
count++;
|
|
}
|
|
pIn++;
|
|
}
|
|
*pOut = '\0';
|
|
}
|
|
|
|
/*
|
|
Added by Ken. Returns the Id of the last trick added, or 0 if there are none.
|
|
Added for use by the skater Display commmand when the AddSpin flag is specified.
|
|
In that case, if the skater's current trick is the same as the last one in the score object,
|
|
then instead of adding the same trick again it will add spin to the last one instead.
|
|
Used by some flatland tricks.
|
|
(See skater.cpp for the above code, search for | Display |)
|
|
*/
|
|
uint32 Score::GetLastTrickId()
|
|
{
|
|
if (m_infoTab.GetSize())
|
|
{
|
|
return m_infoTab.Last().id;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
uint32 Score::GetTrickId( int trickIndex )
|
|
{
|
|
Dbg_MsgAssert( trickIndex >= 0 && trickIndex < m_currentTrick, ( "trickIndex out of range" ) );
|
|
return m_infoTab[trickIndex].id;
|
|
}
|
|
|
|
void Score::TrickTextPulse(int index)
|
|
{
|
|
Script::CStruct* pParams=new Script::CStruct;
|
|
pParams->AddChecksum( CRCD(0x33124d2e,"trick_text_container_id"), CRCD(0x1e55886e,"trick_text_container") + index);
|
|
pParams->AddChecksum( CRCD(0x6e7c7ba7,"the_trick_text_id"), CRCD(0x44727dae,"the_trick_text") + index);
|
|
pParams->AddChecksum( CRCD(0x6d02989c,"the_score_pot_text_id"), CRCD(0xf4d3a70e,"the_score_pot_text") + index);
|
|
Script::RunScript(CRCD(0x3bd51fe5,"trick_text_pulse"), pParams);
|
|
delete pParams;
|
|
}
|
|
|
|
void Score::TrickTextCountdown(int index)
|
|
{
|
|
Script::CStruct* pParams=new Script::CStruct;
|
|
pParams->AddChecksum( CRCD(0x33124d2e,"trick_text_container_id"), CRCD(0x1e55886e,"trick_text_container") + index );
|
|
pParams->AddChecksum( CRCD(0x6e7c7ba7,"the_trick_text_id"), ( CRCD(0x44727dae,"the_trick_text") ) + index );
|
|
pParams->AddChecksum( CRCD(0x6d02989c,"the_score_pot_text_id"), ( CRCD(0xf4d3a70e,"the_score_pot_text") ) + index );
|
|
Script::RunScript(CRCD(0xee9ce723,"trick_text_countdown"), pParams );
|
|
delete pParams;
|
|
}
|
|
|
|
void Score::TrickTextLanded(int index)
|
|
{
|
|
Script::CStruct* pParams=new Script::CStruct;
|
|
pParams->AddChecksum( CRCD(0x33124d2e,"trick_text_container_id"), ( CRCD(0x1e55886e,"trick_text_container") ) + index );
|
|
pParams->AddChecksum( CRCD(0x6e7c7ba7,"the_trick_text_id"), ( CRCD(0x44727dae,"the_trick_text") ) + index );
|
|
pParams->AddChecksum( CRCD(0x6d02989c,"the_score_pot_text_id"), ( CRCD(0xf4d3a70e,"the_score_pot_text") ) + index );
|
|
Script::RunScript(CRCD(0xc890e875,"trick_text_landed"), pParams);
|
|
delete pParams;
|
|
}
|
|
|
|
void Score::TrickTextBail(int index)
|
|
{
|
|
Script::CStruct* pParams=new Script::CStruct;
|
|
pParams->AddChecksum( CRCD(0x33124d2e,"trick_text_container_id"), ( CRCD(0x1e55886e,"trick_text_container") ) + index );
|
|
pParams->AddChecksum( CRCD(0x6e7c7ba7,"the_trick_text_id"), ( CRCD(0x44727dae,"the_trick_text") ) + index );
|
|
pParams->AddChecksum( CRCD(0x6d02989c,"the_score_pot_text_id"), ( CRCD(0xf4d3a70e,"the_score_pot_text") ) + index );
|
|
Script::RunScript(CRCD(0xaa7f404d,"trick_text_bail"), pParams );
|
|
delete pParams;
|
|
}
|
|
|
|
/*
|
|
Called when a trick is done, adding it to the trick sequence.
|
|
*/
|
|
const int TRICK_LIMIT = 250;
|
|
void Score::Trigger(char *trick_name, int base_score, Flags flags)
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
|
|
bool null_trick=false;
|
|
if (!trick_name[0])
|
|
{
|
|
null_trick=true;
|
|
}
|
|
|
|
// once some trick/score has appeared on-screen
|
|
// we know that the trick has started
|
|
Obj::CSkater* pSkater = skate_mod->GetSkaterById( m_skaterId );
|
|
Dbg_Assert( pSkater );
|
|
Obj::CTrickComponent* pTrickComponent = GetTrickComponentFromObject(pSkater);
|
|
Dbg_Assert( pTrickComponent );
|
|
Obj::CStatsManagerComponent* pStatsManagerComponent = GetStatsManagerComponentFromObject(pSkater);
|
|
Dbg_Assert( pStatsManagerComponent );
|
|
|
|
// Only flag a trick as having started if a real trick is being triggered
|
|
if( trick_name && trick_name[0] )
|
|
{
|
|
pTrickComponent->SetFirstTrickStarted( true );
|
|
}
|
|
|
|
bool is_switch = false; // need to make this grab the switch flag eventually!!!
|
|
pStatsManagerComponent->SetTrick( trick_name, base_score, is_switch );
|
|
|
|
// We place a high limit on tricks, so if they
|
|
// cheat with perfect baclance, and keep tricking
|
|
// then they will not run out of memory and crash
|
|
if (m_currentTrick > TRICK_LIMIT-1)
|
|
{
|
|
pack_trick_info_table();
|
|
|
|
if (m_currentTrick > TRICK_LIMIT-1)
|
|
{
|
|
// GJ: You should never be able to hit the trick limit any more
|
|
|
|
if ( !null_trick )
|
|
{
|
|
printf ("Trick Limit (%d) Reached\n",TRICK_LIMIT);
|
|
//tweak_last_valid_trick(base_score);
|
|
m_infoTab.Last().score += base_score; // give them the score, just stop recording tricks
|
|
m_currentMult++; // but still keep up the multipler
|
|
captureScore();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().FrontEndHeap());
|
|
|
|
// trick type is based on id + switch mode
|
|
uint32 id = Script::GenerateCRC(trick_name);
|
|
uint32 switch_mode = (flags & (vSWITCH | vNOLLIE)) >> 1;
|
|
|
|
if (m_infoTab.GetSize() < TRICK_LIMIT)
|
|
{
|
|
m_infoTab.Add(new TrickInfo);
|
|
m_infoTab.Last().score = 0;
|
|
}
|
|
// if we have filled up the trick limit, then we just use the last one we added
|
|
|
|
m_infoTab.Last().score += base_score;
|
|
//printf("triggering trick with id %s\n",trick_name);
|
|
m_infoTab.Last().id = id;
|
|
m_infoTab.Last().switch_mode = switch_mode;
|
|
m_infoTab.Last().flags = flags;
|
|
m_infoTab.Last().spin_mult_index = 0;
|
|
m_infoTab.Last().trickNameText[0] = 0;
|
|
m_infoTab.Last().trickTextFormatted[0] = 0;
|
|
m_infoTab.Last().spin_degrees = 0;
|
|
|
|
if (!null_trick)
|
|
{
|
|
copy_trick_name_with_special_spaces(m_infoTab.Last().trickNameText, trick_name);
|
|
|
|
if ( flags & Score::vCAT )
|
|
{
|
|
sprintf(m_infoTab.Last().trickTextFormatted, "\\c3%s\\c0 ", m_infoTab.Last().trickNameText);
|
|
}
|
|
else if ( flags & Score::vSPECIAL )
|
|
{
|
|
// K: If the 'special' flag is set, use color 2
|
|
sprintf(m_infoTab.Last().trickTextFormatted, "\\c2%s\\c0 ", m_infoTab.Last().trickNameText);
|
|
}
|
|
else
|
|
{
|
|
sprintf(m_infoTab.Last().trickTextFormatted, "%s ", m_infoTab.Last().trickNameText);
|
|
}
|
|
|
|
// toss the "+" onto the end of the previous trick
|
|
|
|
// K: This bit of code used to do a sprintf, but I changed it to use a strcat instead
|
|
// to preserve any color formatting added previously, such as the special-trick color
|
|
// added above.
|
|
|
|
// This is a loop so that null tricks (tricks with no name) get skipped over.
|
|
int index=m_infoTab.GetSize() - 2;
|
|
while (true)
|
|
{
|
|
if (index<0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
char *p_trick_text_formatted=m_infoTab[index].trickTextFormatted;
|
|
Dbg_MsgAssert(p_trick_text_formatted,("NULL p_trick_text_formatted"));
|
|
|
|
int len=strlen(p_trick_text_formatted);
|
|
if (*p_trick_text_formatted == '.')
|
|
{
|
|
// skip items that begin with "..."
|
|
// (or else you get things like
|
|
// "... + + blah blah")
|
|
}
|
|
else if (len)
|
|
{
|
|
// Remove any trailing space character
|
|
if (p_trick_text_formatted[len-1]==' ')
|
|
{
|
|
p_trick_text_formatted[len-1]=0;
|
|
}
|
|
|
|
// Wack on the +
|
|
strcat(p_trick_text_formatted,"\\_+ ");
|
|
break;
|
|
}
|
|
// Keep searching backwards until a named trick is found.
|
|
--index;
|
|
}
|
|
}
|
|
|
|
// if the last trick was a blocking trick, make this trick the spin trick
|
|
// (or if this is the first trick)
|
|
if (m_currentBlockingTrick == m_currentTrick - 1)
|
|
m_currentSpinTrick = m_currentTrick;
|
|
if (flags & vBLOCKING)
|
|
{
|
|
m_currentBlockingTrick = m_currentTrick;
|
|
}
|
|
|
|
// set depreciation stuff
|
|
//Game::CGameMode* pGameMode = skate_mod->GetGameMode();
|
|
if (!(flags & vGAP) && !(flags & vNODEGRADE) /*&& pGameMode->ShouldDegradeScore()*/)
|
|
{
|
|
// trick is not a gap, so figure out what its depreciation index will be
|
|
TrickHistory *pHistory = m_historyTab.GetItem(id);
|
|
if (!pHistory)
|
|
{
|
|
// if no history for this trick, create one
|
|
pHistory = new TrickHistory;
|
|
m_historyTab.PutItem(id, pHistory);
|
|
for (int s = 0; s < 4; s++)
|
|
{
|
|
pHistory->total_count[s] = 0;
|
|
pHistory->combo_count[s] = 0;
|
|
}
|
|
}
|
|
m_infoTab.Last().mult_index = pHistory->total_count[switch_mode] + (pHistory->combo_count[switch_mode]++);
|
|
}
|
|
else
|
|
{
|
|
// gaps don't depreciate
|
|
// no depreciation used in free skate
|
|
m_infoTab.Last().mult_index = 0;
|
|
}
|
|
|
|
m_currentTrick++;
|
|
if (!null_trick)
|
|
{
|
|
#ifdef NO_SCORE_DURING_UBER_FRIG
|
|
int previousMult = m_currentMult;
|
|
#endif
|
|
|
|
m_currentMult++;
|
|
if (m_currentMult == 1)
|
|
{
|
|
Obj::CSkaterRunTimerComponent* pSkaterRunTimerComponent = GetSkaterRunTimerComponentFromObject(pSkater);
|
|
Dbg_Assert(pSkaterRunTimerComponent);
|
|
pSkaterRunTimerComponent->ComboStarted();
|
|
|
|
pSkater->BroadcastEvent(CRCD(0x670fda8c, "SkaterEnterCombo"));
|
|
}
|
|
|
|
#if 1
|
|
// (Mick) check if this is the last of a long line of non-blocking tricks
|
|
// and if so, then decrement the multiplier (leaving it unchanged)
|
|
int non_block_count = 0;
|
|
for (int i = m_currentTrick-1; i >0; i--)
|
|
{
|
|
// if a blocking trick, use default spin multiplier
|
|
if (m_infoTab[i].flags & vBLOCKING)
|
|
{
|
|
break;
|
|
}
|
|
non_block_count++;
|
|
}
|
|
// printf ("%3d: ",non_block_count);
|
|
if (non_block_count > 10)
|
|
{
|
|
#ifdef __NOPT_ASSERT__
|
|
printf ("CHEAT PREVENTION: Limiting non blocking combo to 10\n");
|
|
#endif
|
|
m_infoTab.Last().score = 0;
|
|
m_currentMult--;
|
|
}
|
|
#endif
|
|
|
|
#ifdef NO_SCORE_DURING_UBER_FRIG
|
|
Obj::CSkaterAdjustPhysicsComponent* pSkaterAdjustPhysicsComponent = GetSkaterAdjustPhysicsComponentFromObject(pSkater);
|
|
if (pSkaterAdjustPhysicsComponent && pSkaterAdjustPhysicsComponent->UberFriggedThisFrame())
|
|
{
|
|
m_infoTab.Last().score = 0;
|
|
m_currentMult = previousMult;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (m_debug)
|
|
{
|
|
printf("Adding trick %s\n", trick_name);
|
|
}
|
|
|
|
captureScore();
|
|
|
|
dispatch_trick_sequence_to_screen();
|
|
|
|
TrickTextPulse(pSkater->GetHeapIndex());
|
|
Replay::WriteTrickTextPulse();
|
|
|
|
m_scorePotState = SHOW_ACTUAL_SCORE_POT;
|
|
dispatch_score_pot_value_to_screen(m_scorePot, m_currentMult);
|
|
|
|
/*
|
|
if (mp_trickWindow)
|
|
{
|
|
Dbg_MsgAssert(mp_trickWindow,( "no trick window defined"));
|
|
|
|
HUD::TrickWindow::TrickType trick_type = HUD::TrickWindow::vREGULAR;
|
|
if (flags & vGAP) trick_type = HUD::TrickWindow::vGAP;
|
|
if (flags & vSPECIAL) trick_type = HUD::TrickWindow::vSPECIAL;
|
|
|
|
mp_trickWindow->AddTrick(trick_name, m_currentTrick, trick_type);
|
|
}
|
|
*/
|
|
Mem::Manager::sHandle().PopContext();
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Called when spin changes. (From CSkater::HandleAirRotation()).
|
|
*/
|
|
void Score::UpdateSpin(int spin_degrees)
|
|
{
|
|
// if score pot was reset, m_currentSpinTrick is no longer valid
|
|
if (m_currentTrick == 0 || m_currentSpinTrick < 0)
|
|
return;
|
|
|
|
// If a trick is blocking, then we don't want to add any
|
|
// more spin to it after the initial spin
|
|
if (m_infoTab[m_currentSpinTrick].flags & vBLOCKING)
|
|
{
|
|
// printf ("Trick %d is blocing, %d degs\n",m_currentSpinTrick,spin_degrees);
|
|
return;
|
|
}
|
|
|
|
SetSpin(spin_degrees);
|
|
}
|
|
|
|
/*
|
|
Called right after call to Trigger(). Current spin trick might be trick just added. Also
|
|
called by Update() (above).
|
|
|
|
Updates the spin multiplier on the current spin trick. If the skater has increased his
|
|
spin over the highest spin last recorded (increments of 180), then save the new spin
|
|
multiplier.
|
|
*/
|
|
void Score::SetSpin(int spin_degrees)
|
|
{
|
|
// if score pot was reset, m_currentSpinTrick is no longer valid
|
|
if (m_currentTrick == 0 || m_currentSpinTrick < 0)
|
|
return;
|
|
|
|
int spin_position = spin_degrees;
|
|
const char *p_direction = "";
|
|
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Obj::CSkater* pSkater = skate_mod->GetSkaterById( m_skaterId );
|
|
Dbg_Assert( pSkater );
|
|
|
|
Obj::CAnimationComponent* pAnimationComponent = GetAnimationComponentFromObject( pSkater );
|
|
bool is_flipped = pAnimationComponent->IsFlipped();
|
|
|
|
// frontside or backside?
|
|
if (spin_position < 0)
|
|
{
|
|
spin_position = -spin_position;
|
|
if ( is_flipped )
|
|
{
|
|
p_direction = "BS";
|
|
}
|
|
else
|
|
{
|
|
p_direction = "FS";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( is_flipped )
|
|
{
|
|
p_direction = "FS";
|
|
}
|
|
else
|
|
{
|
|
p_direction = "BS";
|
|
}
|
|
}
|
|
|
|
// add a little fudge factor: doesn't need to fully rotate 180 to earn 180
|
|
spin_position += (int)Obj::GetPhysicsFloat(CRCD(0x50c5cc2f, "spin_count_slop"));
|
|
int spin_index = spin_position / 180;
|
|
|
|
// TT#3426 - Clamp spins if too high, to prevent cheaters getting stuck and doing a lot of tricks
|
|
// Not needed as spins only give you extra multiplier up to 900 anyway
|
|
#if 0
|
|
if (spin_index > 11)
|
|
{
|
|
#ifdef __NOPT_ASSERT__
|
|
printf ("CHEAT WARNING, clamping spins\n");
|
|
#endif
|
|
spin_index = 11;
|
|
}
|
|
#endif
|
|
|
|
// update the rotation amount of this trick
|
|
m_infoTab[m_currentSpinTrick].spin_degrees = spin_degrees;
|
|
|
|
// don't bother updating text if spin index isn't big enough
|
|
if (m_infoTab[m_currentSpinTrick].spin_mult_index < spin_index)
|
|
{
|
|
if (m_debug)
|
|
{
|
|
printf("New spin value %d:\n", spin_index * 180);
|
|
}
|
|
|
|
// Not sure why this is necessary, but Ollies w/o another trick
|
|
// have the wrong spin direction on half rotations. i.e. 180, 540, 900, etc.
|
|
if ( m_infoTab[m_currentSpinTrick].id == CRCD(0x9b65d7b8,"Ollie") )
|
|
{
|
|
if ( (spin_index%2) == 1 )
|
|
{
|
|
if ( p_direction == "FS")
|
|
{
|
|
p_direction = "BS";
|
|
}
|
|
else
|
|
{
|
|
p_direction = "FS";
|
|
}
|
|
}
|
|
}
|
|
|
|
int last_trick = m_infoTab.GetSize() - 1;
|
|
Dbg_Assert(last_trick >= 0);
|
|
int shown_spin = spin_index * 180;
|
|
|
|
const char *p_format="%d\\_%s";
|
|
if (last_trick > m_currentSpinTrick)
|
|
{
|
|
if (m_infoTab[m_currentSpinTrick].flags & Score::vCAT)
|
|
{
|
|
p_format="\\c3%s\\_%d\\_%s\\c0\\_+ ";
|
|
}
|
|
else
|
|
{
|
|
if (m_infoTab[m_currentSpinTrick].flags & Score::vSPECIAL)
|
|
{
|
|
p_format="\\c2%s\\_%d\\_%s\\c0\\_+ ";
|
|
}
|
|
else
|
|
{
|
|
p_format="%s\\_%d\\_%s\\_+ ";
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_infoTab[m_currentSpinTrick].flags & Score::vCAT)
|
|
{
|
|
p_format="\\c3%s\\_%d\\_%s\\c0";
|
|
}
|
|
else
|
|
{
|
|
if (m_infoTab[m_currentSpinTrick].flags & Score::vSPECIAL)
|
|
{
|
|
p_format="\\c2%s\\_%d\\_%s\\c0";
|
|
}
|
|
else
|
|
{
|
|
p_format="%s\\_%d\\_%s";
|
|
}
|
|
}
|
|
}
|
|
|
|
sprintf(m_infoTab[m_currentSpinTrick].trickTextFormatted, p_format, p_direction, shown_spin, m_infoTab[m_currentSpinTrick].trickNameText);
|
|
dispatch_trick_sequence_to_screen();
|
|
|
|
/*
|
|
if (mp_trickWindow)
|
|
{
|
|
mp_trickWindow->ChangeSpin(spin_index * 180, m_currentSpinTrick);
|
|
}
|
|
*/
|
|
m_infoTab[m_currentSpinTrick].spin_mult_index = spin_index;
|
|
captureScore();
|
|
|
|
Obj::CStatsManagerComponent* pStatsManagerComponent = GetStatsManagerComponentFromObject( pSkater );
|
|
Dbg_Assert( pStatsManagerComponent );
|
|
pStatsManagerComponent->SetSpin( (spin_index*180) );
|
|
|
|
m_scorePotState = SHOW_ACTUAL_SCORE_POT;
|
|
dispatch_score_pot_value_to_screen(m_scorePot, m_currentMult);
|
|
|
|
pSkater->BroadcastEvent(CRCD(0x68b887bb, "SkaterSpinDisplayed"));
|
|
}
|
|
}
|
|
|
|
void Score::TweakTrick(int tweak_value )
|
|
{
|
|
if (m_currentTrick <= 0) return;
|
|
// K: If the last trick was a 'Null' trick, then do not add the score.
|
|
// This is to fix TT5718, where it was possible to do a manual, then jump out of it
|
|
// really quickly whilst still getting some score appearing on screen, even though you
|
|
// did not really get those points because the non-null trick name had not been displayed yet.
|
|
// (At the start of the manual, a 'null' trick is done using SetTrickName "", simply in order
|
|
// to do a BlockSpin, but we don't want that null trick to enable the score counter)
|
|
if (m_infoTab[m_currentTrick-1].trickNameText[0]==0) return;
|
|
|
|
#if 1
|
|
// (Mick) check if this is the last of a long line of non-blocking tricks
|
|
// and if so, then decrement the multiplier (leaving it unchanged)
|
|
int non_block_count = 0;
|
|
for (int i = m_currentTrick-1; i >0; i--)
|
|
{
|
|
// if a blocking trick, use default spin multiplier
|
|
if (m_infoTab[i].flags & vBLOCKING)
|
|
{
|
|
break;
|
|
}
|
|
non_block_count++;
|
|
}
|
|
// printf ("%3d: ",non_block_count);
|
|
if (non_block_count > 10)
|
|
{
|
|
#ifdef __NOPT_ASSERT__
|
|
printf ("CHEAT PREVENTION: Limiting tweak after 10 nonblocking trick\n");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
if (!(m_infoTab[m_currentTrick-1].flags & vBLOCKING) && m_infoTab[m_currentTrick-1].score > MAX_SCORE_DUE_TO_TWEAK) return;
|
|
#endif
|
|
|
|
#ifdef NO_SCORE_DURING_UBER_FRIG
|
|
Mdl::Skate* skate_mod = Mdl::Skate::Instance();
|
|
Obj::CSkater* pSkater = skate_mod->GetSkaterById(m_skaterId);
|
|
Obj::CSkaterAdjustPhysicsComponent* pSkaterAdjustPhysicsComponent = GetSkaterAdjustPhysicsComponentFromObject(pSkater);
|
|
if (pSkaterAdjustPhysicsComponent && pSkaterAdjustPhysicsComponent->UberFriggedThisFrame()) return;
|
|
#endif
|
|
|
|
m_infoTab[m_currentTrick-1].score += tweak_value;
|
|
captureScore();
|
|
|
|
dispatch_trick_sequence_to_screen();
|
|
m_scorePotState = SHOW_ACTUAL_SCORE_POT;
|
|
dispatch_score_pot_value_to_screen(m_scorePot, m_currentMult);
|
|
}
|
|
|
|
void Score::Land( void )
|
|
{
|
|
GameNet::Manager * gamenet_man = GameNet::Manager::Instance();
|
|
Net::Client* client;
|
|
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Game::CGameMode* pGameMode = skate_mod->GetGameMode();
|
|
|
|
captureScore();
|
|
|
|
/*
|
|
if (mp_trickWindow)
|
|
{
|
|
Dbg_MsgAssert(mp_trickWindow,( "no trick window defined"));
|
|
mp_trickWindow->Count(true);
|
|
}
|
|
*/
|
|
|
|
// GLOOBY
|
|
int trick_score = m_scorePot * m_currentMult;
|
|
|
|
Obj::CSkater* pSkater = skate_mod->GetSkaterById( m_skaterId );
|
|
Dbg_Assert( pSkater );
|
|
Dbg_Assert( pSkater->IsLocalClient());
|
|
// if playing graffiti, then update the colors as appropriate
|
|
bool debug_graffiti = Script::GetInteger( "debug_graffiti" );
|
|
Game::CGoalManager* pGoalManager = Game::GetGoalManager();
|
|
pGoalManager->Land();
|
|
if ( debug_graffiti || ( pGameMode->IsTrue("should_modulate_color") ) && ( trick_score > 0 ) )
|
|
{
|
|
// update the server
|
|
LogTrickObjectRequest( trick_score );
|
|
}
|
|
|
|
// flushes the graffiti trick buffer
|
|
GetTrickComponentFromObject(pSkater)->SetGraffitiTrickStarted( false );
|
|
|
|
if (!Script::GetInteger("NewSpecial"))
|
|
{
|
|
// update special meter (when we land)
|
|
m_specialScore += m_scorePot * m_currentMult;
|
|
if (m_specialScore >= 3000)
|
|
{
|
|
set_special_is_active(true);
|
|
m_specialScore = 3000;
|
|
}
|
|
if (m_specialScore < 0)
|
|
{
|
|
m_specialScore = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_recentSpecialScorePot = 0; // ensure next trick is not infuenced by this trick
|
|
}
|
|
|
|
// update combo records
|
|
if ( m_currentMult > m_longestCombo )
|
|
{
|
|
// printf("length: old record - %i, new record - %i\n", m_longestCombo, m_currentMult);
|
|
m_longestCombo = m_currentMult;
|
|
}
|
|
if ( GetLastScoreLanded() > m_bestCombo )
|
|
{
|
|
m_bestCombo = GetLastScoreLanded();
|
|
// printf("points: old record - %i, new record - %i\n", m_bestCombo, GetLastScoreLanded());
|
|
}
|
|
|
|
if ( GetLastScoreLanded() > m_bestGameCombo )
|
|
{
|
|
if( gamenet_man->InNetGame() && ( pGameMode->GetNameChecksum() != CRCD(0x1c471c60,"netlobby")))
|
|
{
|
|
Net::MsgDesc msg_desc;
|
|
Net::Client* client;
|
|
GameNet::MsgScoreLanded msg;
|
|
|
|
msg.m_Score = GetLastScoreLanded();
|
|
msg.m_GameId = gamenet_man->GetNetworkGameId();
|
|
|
|
msg_desc.m_Id = GameNet::MSG_ID_COMBO_REPORT;
|
|
msg_desc.m_Data = &msg;
|
|
msg_desc.m_Length = sizeof( GameNet::MsgScoreLanded );
|
|
msg_desc.m_Queue = Net::QUEUE_SEQUENCED;
|
|
msg_desc.m_GroupId = GameNet::vSEQ_GROUP_PLAYER_MSGS;
|
|
|
|
client = gamenet_man->GetClient( pSkater->GetSkaterNumber());
|
|
Dbg_Assert( client );
|
|
|
|
client->EnqueueMessageToServer( &msg_desc );
|
|
}
|
|
m_bestGameCombo = GetLastScoreLanded();
|
|
}
|
|
|
|
|
|
// if not degrading score, we need to clear our history
|
|
if (!pGameMode->ShouldDegradeScore())
|
|
{
|
|
// clear combo history, and total history as well, althought that really should never ahve been set.
|
|
for (int i = 0; i < m_historyTab.getSize(); i++)
|
|
{
|
|
TrickHistory *pHistory = m_historyTab.GetItemByIndex(i);
|
|
for (int s = 0; s < 4; s++)
|
|
{
|
|
pHistory->total_count[s] = 0;
|
|
pHistory->combo_count[s] = 0;
|
|
}
|
|
}
|
|
// and reset the rail counters between combos
|
|
reset_robot_detection();
|
|
}
|
|
else
|
|
{
|
|
// update trick history -- all counts from trick sequence are added to counts from session
|
|
for (int i = 0; i < m_historyTab.getSize(); i++)
|
|
{
|
|
TrickHistory *pHistory = m_historyTab.GetItemByIndex(i);
|
|
for (int s = 0; s < 4; s++)
|
|
{
|
|
pHistory->total_count[s] += pHistory->combo_count[s];
|
|
pHistory->combo_count[s] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_currentTrick)
|
|
{
|
|
m_scorePotState = WAITING_TO_COUNT_SCORE_POT;
|
|
m_countedScorePot = m_scorePot * m_currentMult;
|
|
m_scorePotCountdown = 150; // about 3 seconds
|
|
dispatch_score_pot_value_to_screen(m_scorePot * m_currentMult, 0);
|
|
|
|
int index;
|
|
index = pSkater->GetHeapIndex();
|
|
TrickTextLanded(index);
|
|
Replay::WriteTrickTextLanded();
|
|
}
|
|
|
|
resetScorePot();
|
|
|
|
int old_score = GetTotalScore();
|
|
|
|
// if we're not in graffiti mode, then update the total score
|
|
// and panel (in graffiti mode, the client doesn't have the
|
|
// authority to set its own scores)
|
|
if ( !pGameMode->IsTrue(CRCD(0x11941568, "should_modulate_color")) )
|
|
{
|
|
if( pGameMode->ShouldTrackTrickScore())
|
|
{
|
|
if( ( pGameMode->ShouldAccumulateScore()) ||
|
|
( ( pGameMode->ShouldTrackBestCombo()) &&
|
|
( GetTotalScore() < trick_score )))
|
|
{
|
|
if( !gamenet_man->OnServer())
|
|
{
|
|
GameNet::MsgScoreLanded msg;
|
|
Net::MsgDesc msg_desc;
|
|
|
|
msg.m_GameId = gamenet_man->GetNetworkGameId();
|
|
msg.m_Score = trick_score;
|
|
|
|
msg_desc.m_Data = &msg;
|
|
msg_desc.m_Length = sizeof( GameNet::MsgScoreLanded );
|
|
msg_desc.m_Id = GameNet::MSG_ID_LANDED_TRICK;
|
|
msg_desc.m_Queue = Net::QUEUE_SEQUENCED;
|
|
msg_desc.m_GroupId = GameNet::vSEQ_GROUP_PLAYER_MSGS;
|
|
|
|
client = gamenet_man->GetClient( pSkater->GetSkaterNumber());
|
|
Dbg_Assert( client );
|
|
|
|
client->EnqueueMessageToServer( &msg_desc );
|
|
}
|
|
|
|
if( pGameMode->ShouldTrackBestCombo())
|
|
{
|
|
SetTotalScore( trick_score );
|
|
}
|
|
else
|
|
{
|
|
SetTotalScore( m_totalScore + trick_score );
|
|
}
|
|
}
|
|
else if( !pGameMode->ShouldTrackBestCombo())
|
|
{
|
|
// don't reset if the score is frozen
|
|
if ( !pGameMode->ScoreFrozen() )
|
|
SetTotalScore( trick_score );
|
|
}
|
|
}
|
|
}
|
|
|
|
int new_score = GetTotalScore();
|
|
check_high_score(old_score, new_score);
|
|
|
|
|
|
Obj::CSkaterRunTimerComponent* pSkaterRunTimerComponent = GetSkaterRunTimerComponentFromObject(pSkater);
|
|
Dbg_Assert(pSkaterRunTimerComponent);
|
|
pSkaterRunTimerComponent->ComboEnded();
|
|
|
|
// XXX
|
|
// printf("TRICK SCORE = %d\n", new_score);
|
|
}
|
|
|
|
|
|
void Score::ForceSpecial( void )
|
|
{
|
|
set_special_is_active(true);
|
|
m_specialScore = 3000;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Called whenever skater bails. Clears combo history, resets score pot, stops special
|
|
*/
|
|
void Score::Bail( bool clearScoreText )
|
|
{
|
|
// update trick history -- clear counts for this combo
|
|
for (int i = 0; i < m_historyTab.getSize(); i++)
|
|
{
|
|
TrickHistory *pHistory = m_historyTab.GetItemByIndex(i);
|
|
for (int s = 0; s < 4; s++)
|
|
pHistory->combo_count[s] = 0;
|
|
}
|
|
|
|
if (m_currentTrick)
|
|
{
|
|
m_scorePotState = SHOW_ACTUAL_SCORE_POT;
|
|
|
|
if (!clearScoreText)
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Obj::CSkater* pSkater = skate_mod->GetSkaterById( m_skaterId );
|
|
Dbg_Assert( pSkater );
|
|
|
|
dispatch_score_pot_value_to_screen(m_scorePot * m_currentMult, 0);
|
|
|
|
int index;
|
|
index = pSkater->GetHeapIndex();
|
|
TrickTextBail(index);
|
|
}
|
|
else
|
|
{
|
|
dispatch_trick_sequence_to_screen(true);
|
|
dispatch_score_pot_value_to_screen( 0, 0 );
|
|
}
|
|
|
|
// Replay::WriteTrickTextBail();
|
|
}
|
|
|
|
/*
|
|
if (mp_trickWindow)
|
|
{
|
|
Dbg_MsgAssert(mp_trickWindow,( "no trick window defined"));
|
|
mp_trickWindow->Collapse();
|
|
}
|
|
*/
|
|
|
|
resetScorePot();
|
|
|
|
m_specialScore = 0;
|
|
set_special_is_active(false);
|
|
|
|
Obj::CSkaterRunTimerComponent* pSkaterRunTimerComponent
|
|
= GetSkaterRunTimerComponentFromObject(Mdl::Skate::Instance()->GetSkaterById( m_skaterId ));
|
|
Dbg_Assert(pSkaterRunTimerComponent);
|
|
pSkaterRunTimerComponent->ComboEnded();
|
|
|
|
Game::CGoalManager* pGoalManager = Game::GetGoalManager();
|
|
pGoalManager->Bail();
|
|
}
|
|
|
|
|
|
|
|
// completely resets score object
|
|
void Score::Reset()
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Obj::CSkater* pSkater = skate_mod->GetSkaterById( m_skaterId );
|
|
//GameNet::Manager * gamenet_man = GameNet::Manager::Instance();
|
|
//Net::Server* server;
|
|
|
|
printf ("Score::RESET ...............\n");
|
|
|
|
reset_robot_detection();
|
|
|
|
resetScorePot();
|
|
|
|
Lst::LookupTableDestroyer<TrickHistory> destroyer(&m_historyTab);
|
|
destroyer.DeleteTableContents();
|
|
|
|
/*
|
|
if (mp_trickWindow)
|
|
{
|
|
mp_trickWindow->ResetWindow();
|
|
mp_trickWindow->ResetRecords();
|
|
}
|
|
*/
|
|
|
|
if( pSkater && pSkater->IsLocalClient())
|
|
{
|
|
dispatch_trick_sequence_to_screen();
|
|
dispatch_score_pot_value_to_screen( 0, 0 );
|
|
}
|
|
|
|
if( ( skate_mod->GetGameMode()->GetNameChecksum() == CRCD(0xbff33600,"netfirefight")) ||
|
|
( skate_mod->GetGameMode()->GetNameChecksum() == CRCD(0x3d6d444f,"firefight")))
|
|
{
|
|
m_totalScore = 100;
|
|
}
|
|
else
|
|
{
|
|
m_totalScore = 0;
|
|
}
|
|
|
|
m_scorePot = 0;
|
|
m_recentScorePot = 0;
|
|
m_recentSpecialScorePot = 0;
|
|
m_specialScore = 0;
|
|
m_bestGameCombo = 0;
|
|
|
|
set_special_is_active(false);
|
|
|
|
// Mick: The next two lines clear any pending "countdown" score that might show up again after
|
|
// we switch levels (or return to the skateshop)
|
|
m_countedScorePot = 0;
|
|
m_scorePotState = SHOW_ACTUAL_SCORE_POT;
|
|
|
|
setSpecialBarColors(); // Split into seperate function so that special bar colors could be updated for themes
|
|
|
|
Obj::CSkater* p_skater = Mdl::Skate::Instance()->GetSkaterById( m_skaterId );
|
|
if (p_skater && p_skater->IsLocalClient())
|
|
{
|
|
Obj::CSkaterRunTimerComponent* pSkaterRunTimerComponent = GetSkaterRunTimerComponentFromObject(p_skater);
|
|
Dbg_Assert(pSkaterRunTimerComponent);
|
|
pSkaterRunTimerComponent->ComboEnded();
|
|
}
|
|
|
|
/*
|
|
HUD::PanelMgr* panel_mgr = HUD::PanelMgr::Instance();
|
|
HUD::Panel* panel;
|
|
|
|
if(( panel = panel_mgr->GetPanelBySkaterId(m_skaterId, false)))
|
|
{
|
|
panel->SetScore(0, true);
|
|
}
|
|
*/
|
|
}
|
|
|
|
void Score::setSpecialBarColors()
|
|
{
|
|
Script::CArray *p_special_bar_colors = Script::GetArray("special_bar_colors", Script::ASSERT);
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
Script::CArray *p_rgba = p_special_bar_colors->GetArray(i);
|
|
|
|
m_special_rgba[i].r = p_rgba->GetInteger(0);
|
|
m_special_rgba[i].g = p_rgba->GetInteger(1);
|
|
m_special_rgba[i].b = p_rgba->GetInteger(2);
|
|
m_special_rgba[i].a = p_rgba->GetInteger(3);
|
|
}
|
|
m_special_interpolator_rate = Script::GetFloat("special_bar_iterpolator_rate", Script::ASSERT);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
Totals up score pot of present trick sequence, sends number to trick text window
|
|
*/
|
|
void Score::captureScore()
|
|
{
|
|
// if no tricks in list, then no score to capture
|
|
if (m_currentTrick == 0)
|
|
{
|
|
m_recentSpecialScorePot = 0;
|
|
m_recentScorePot = 0;
|
|
return;
|
|
}
|
|
|
|
if (m_debug)
|
|
printf("Score pot:\n");
|
|
|
|
// compute score pot
|
|
m_scorePot = 0;
|
|
int current_spin_mult = 2; // n over 2
|
|
for (int i = 0; i < m_currentTrick; i++)
|
|
{
|
|
// if a blocking trick, use default spin multiplier
|
|
if (m_infoTab[i].flags & vBLOCKING)
|
|
{
|
|
current_spin_mult = 2;
|
|
}
|
|
// if not a blocking trick, but the last trick was, then use the spin multiplier here
|
|
// to apply to subsequent tricks up to next blocking one
|
|
else
|
|
{
|
|
if (i == 0 || (m_infoTab[i-1].flags & vBLOCKING))
|
|
{
|
|
current_spin_mult = spinMult(m_infoTab[i].spin_mult_index);
|
|
}
|
|
}
|
|
|
|
int deprec_mult = deprecMult(m_infoTab[i].mult_index);
|
|
|
|
if (m_debug)
|
|
printf(" base score %d, reduction mult %.2f, spin mult %.1f\n",
|
|
m_infoTab[i].score, (float) deprec_mult / 100, (float) current_spin_mult / 2);
|
|
|
|
int score = (m_infoTab[i].score * deprec_mult * current_spin_mult) / 200;
|
|
if (m_infoTab[i].switch_mode)
|
|
{
|
|
score = score * 120 / 100;
|
|
}
|
|
|
|
m_scorePot += score;
|
|
}
|
|
if (m_debug)
|
|
printf(" total %d\n", m_scorePot);
|
|
|
|
/*
|
|
if( mp_trickWindow )
|
|
{
|
|
mp_trickWindow->SetScore(m_scorePot);
|
|
}
|
|
*/
|
|
|
|
if (Script::GetInteger("NewSpecial"))
|
|
{
|
|
// printf ("Score = %d, Recent = %d\n",m_scorePot * m_currentTrick , m_recentScorePot);
|
|
if (m_scorePot * m_currentMult > m_recentSpecialScorePot)
|
|
{
|
|
// update special meter (constantly, as we score)
|
|
m_specialScore += m_scorePot * m_currentMult - m_recentSpecialScorePot;
|
|
if (m_specialScore <0)
|
|
{
|
|
set_special_is_active(false);
|
|
m_specialScore = 0;
|
|
}
|
|
if (m_specialScore >= 3000)
|
|
{
|
|
set_special_is_active(true);
|
|
m_specialScore = 3000;
|
|
}
|
|
}
|
|
}
|
|
m_recentScorePot = m_scorePot * m_currentMult;
|
|
m_recentSpecialScorePot = m_scorePot * m_currentMult;
|
|
}
|
|
|
|
|
|
|
|
void Score::resetScorePot()
|
|
{
|
|
m_scorePot = 0;
|
|
Lst::DynamicTableDestroyer<TrickInfo> destroyer(&m_infoTab);
|
|
destroyer.DeleteTableContents();
|
|
m_currentTrick = 0;
|
|
m_currentMult = 0;
|
|
m_currentBlockingTrick = -1;
|
|
m_currentSpinTrick = -1;
|
|
reset_robot_detection_combo();
|
|
//m_recentScorePot = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
void Score::dispatch_trick_sequence_to_screen ( bool clear_text )
|
|
{
|
|
Front::CScreenElementManager* p_manager = Front::CScreenElementManager::Instance();
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Obj::CSkater* pSkater = skate_mod->GetSkaterById( m_skaterId );
|
|
int index = 0;
|
|
|
|
if( pSkater )
|
|
{
|
|
index = pSkater->GetHeapIndex();
|
|
}
|
|
Front::CTextBlockElement *p_text_block = (Front::CTextBlockElement *) p_manager->GetElement(Script::GenerateCRC("the_trick_text") + index ).Convert();
|
|
if (!p_text_block) return;
|
|
|
|
const char *pp_string_tab[TRICK_LIMIT];
|
|
|
|
if (!clear_text)
|
|
{
|
|
Dbg_Assert(m_infoTab.GetSize() <= TRICK_LIMIT);
|
|
for (int i = 0; i < m_infoTab.GetSize(); i++)
|
|
{
|
|
pp_string_tab[i] = m_infoTab[i].trickTextFormatted;
|
|
}
|
|
|
|
p_text_block->SetText(pp_string_tab, m_infoTab.GetSize());
|
|
// Replay::WriteTrickText(pp_string_tab, m_infoTab.GetSize());
|
|
}
|
|
else
|
|
{
|
|
p_text_block->SetText(pp_string_tab, 0);
|
|
}
|
|
|
|
Script::RunScript("UpdateTrickText");
|
|
}
|
|
|
|
|
|
|
|
|
|
int Score::spinMult(int x)
|
|
{
|
|
// defines how the multiplier for spins ramps up. .5 and 1 for 180 and 360, then 2,3,4,5,... for 540,720,900,1080,... etc.
|
|
//return (((x)<MAX_SPIN_VALUES) ? (SPIN_MULT_VALUES[x]) : SPIN_MULT_VALUES[MAX_SPIN_VALUES-1]+4+4*((x)-MAX_SPIN_VALUES));
|
|
// Ken: Made spin multiplier have a max value so that it doesn't get huge for flatland tricks.
|
|
return (((x)<MAX_SPIN_VALUES) ? (SPIN_MULT_VALUES[x]) : SPIN_MULT_VALUES[MAX_SPIN_VALUES-1]);
|
|
}
|
|
|
|
|
|
|
|
|
|
int Score::deprecMult(int x)
|
|
{
|
|
return ((x < MAX_DEPREC) ? DEPREC_VALUES[x] : DEPREC_VALUES[MAX_DEPREC-1]);
|
|
}
|
|
|
|
|
|
|
|
|
|
void Score::setup_balance_meter_stuff()
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Script::CStruct *p_balance_meter_struct = Script::GetStructure("balance_meter_info");
|
|
Dbg_Assert(p_balance_meter_struct);
|
|
|
|
// fetch arrow position table
|
|
Script::CArray *p_arrow_array = NULL;
|
|
p_balance_meter_struct->GetArray("arrow_positions", &p_arrow_array);
|
|
Dbg_Assert(p_arrow_array);
|
|
m_numArrowPositions = p_arrow_array->GetSize();
|
|
for (int i = 0; i < m_numArrowPositions; i++)
|
|
{
|
|
m_arrowPosTab[i] = *p_arrow_array->GetPair(i);
|
|
}
|
|
// for good measure
|
|
m_arrowPosTab[m_numArrowPositions] = m_arrowPosTab[m_numArrowPositions-1];
|
|
m_arrowInterval = 1.0f / ((float) m_numArrowPositions);
|
|
|
|
Script::CArray *p_bar_pos_array = NULL;
|
|
if( ( CFuncs::ScriptInSplitScreenGame( NULL, NULL )) &&
|
|
( skate_mod->GetGameMode()->GetNameChecksum() != Script::GenerateCRC( "horse" )) &&
|
|
( skate_mod->GetGameMode()->GetNameChecksum() != Script::GenerateCRC( "nethorse" )))
|
|
{
|
|
if( Nx::CViewportManager::sGetScreenMode() == Nx::vSPLIT_V )
|
|
{
|
|
p_balance_meter_struct->GetArray("bar_positions_mp_v", &p_bar_pos_array);
|
|
}
|
|
else
|
|
{
|
|
p_balance_meter_struct->GetArray("bar_positions_mp_h", &p_bar_pos_array);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
p_balance_meter_struct->GetArray("bar_positions", &p_bar_pos_array);
|
|
}
|
|
|
|
Dbg_Assert(p_bar_pos_array);
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
m_meterPos[i] = *p_bar_pos_array->GetPair(i);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void Score::position_balance_meter(bool state, float value, bool isVertical)
|
|
{
|
|
Front::CScreenElementManager* p_manager = Front::CScreenElementManager::Instance();
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Obj::CSkater* pSkater = skate_mod->GetSkaterById( m_skaterId );
|
|
|
|
Front::CSpriteElement *p_balance_meter = (Front::CSpriteElement *) p_manager->GetElement(0xa4db8a4b + pSkater->GetHeapIndex()).Convert(); // "the_balance_meter"
|
|
Dbg_Assert(p_balance_meter);
|
|
|
|
int is_shown = 0;
|
|
p_balance_meter->GetIntegerTag(0xc22eb9a0, &is_shown); // "tag_turned_on"
|
|
if (state != (bool) is_shown)
|
|
{
|
|
Script::CStruct* pParams;
|
|
pParams = new Script::CStruct;
|
|
pParams->AddChecksum( "id", 0xa4db8a4b + pSkater->GetHeapIndex());
|
|
if (state)
|
|
{
|
|
Script::RunScript(CRCD(0xba95da16, "show_balance_meter"), pParams );
|
|
}
|
|
else
|
|
{
|
|
Script::RunScript(CRCD(0x58783b40, "hide_balance_meter"), pParams );
|
|
}
|
|
|
|
delete pParams;
|
|
}
|
|
|
|
if (isVertical)
|
|
p_balance_meter->SetChecksumTag(0x863a07e2, 0xef24413b); // "tag_mode", "manual"
|
|
else
|
|
p_balance_meter->SetChecksumTag(0x863a07e2, 0x530be001); // "tag_mode", "balance"
|
|
|
|
// figure out position of arrow
|
|
float abs_value = Mth::Abs(value);
|
|
int index = (int) ( abs_value / m_arrowInterval);
|
|
float mix = abs_value - ((float) index) * m_arrowInterval;
|
|
m_arrowPos.mX = m_arrowPosTab[index].mX + (m_arrowPosTab[index+1].mX - m_arrowPosTab[index].mX) * mix / m_arrowInterval;
|
|
m_arrowPos.mY = m_arrowPosTab[index].mY + (m_arrowPosTab[index+1].mY - m_arrowPosTab[index].mY) * mix / m_arrowInterval;
|
|
//printf("arrow at %f, %f, index %d, mix %f\n", m_arrowPos.mX, m_arrowPos.mY, index, mix);
|
|
m_arrowRot = -value * 45.0f;
|
|
|
|
Front::CSpriteElement *p_balance_arrow = (Front::CSpriteElement *) p_balance_meter->GetFirstChild();//.Convert();
|
|
Dbg_Assert(p_balance_arrow);
|
|
|
|
if (isVertical)
|
|
{
|
|
p_balance_meter->SetPos(m_meterPos[1].mX, m_meterPos[1].mY, Front::CScreenElement::FORCE_INSTANT);
|
|
p_balance_meter->SetRotate(-90.0f);
|
|
if (value >= 0.0f)
|
|
p_balance_arrow->SetPos(p_balance_meter->GetBaseW() / 2.0f + m_arrowPos.mY, p_balance_meter->GetBaseH() / 2.0f - m_arrowPos.mX, Front::CScreenElement::FORCE_INSTANT);
|
|
else
|
|
p_balance_arrow->SetPos(p_balance_meter->GetBaseW() / 2.0f + m_arrowPos.mY, p_balance_meter->GetBaseH() / 2.0f + m_arrowPos.mX, Front::CScreenElement::FORCE_INSTANT);
|
|
p_balance_arrow->SetRotate(-m_arrowRot - 90.0f);
|
|
}
|
|
else
|
|
{
|
|
p_balance_meter->SetPos(m_meterPos[0].mX, m_meterPos[0].mY, Front::CScreenElement::FORCE_INSTANT);
|
|
p_balance_meter->SetRotate(0);
|
|
if (value >= 0.0f)
|
|
p_balance_arrow->SetPos(p_balance_meter->GetBaseW() / 2.0f + m_arrowPos.mX, p_balance_meter->GetBaseH() / 2.0f + m_arrowPos.mY, Front::CScreenElement::FORCE_INSTANT);
|
|
else
|
|
p_balance_arrow->SetPos(p_balance_meter->GetBaseW() / 2.0f - m_arrowPos.mX, p_balance_meter->GetBaseH() / 2.0f + m_arrowPos.mY, Front::CScreenElement::FORCE_INSTANT);
|
|
p_balance_arrow->SetRotate(-m_arrowRot);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void Score::dispatch_score_pot_value_to_screen(int score, int multiplier)
|
|
{
|
|
Front::CScreenElementManager* p_manager = Front::CScreenElementManager::Instance();
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
|
|
Obj::CSkater* pSkater = skate_mod->GetSkaterById( m_skaterId );
|
|
int index = 0;
|
|
|
|
if( pSkater )
|
|
{
|
|
index = pSkater->GetHeapIndex();
|
|
}
|
|
Front::CTextElement *p_score_pot_text = (Front::CTextElement *) p_manager->GetElement(0xf4d3a70e + index ).Convert(); // "the_score_pot_text"
|
|
Dbg_Assert(p_score_pot_text);
|
|
|
|
char p_string[128];
|
|
if (!score)
|
|
strcpy(p_string, " ");
|
|
else if (multiplier)
|
|
sprintf(p_string, "%s X %d", Str::PrintThousands(score), multiplier);
|
|
else
|
|
sprintf(p_string, "%s", Str::PrintThousands(score));
|
|
|
|
|
|
p_score_pot_text->SetText(p_string);
|
|
|
|
Replay::WriteScorePotText(p_string);
|
|
Script::RunScript("UpdateScorepot");
|
|
}
|
|
|
|
// Check for a high score goals being achieved
|
|
// for each goal that is actieved, then run the script
|
|
// on the skater that got the score
|
|
void Score::check_high_score(int old_score, int new_score)
|
|
{
|
|
#ifdef DEBUG_HIGH_SCORE_GOALS
|
|
printf("Checking High Scores, score changed from %d to %d\n",old_score, new_score);
|
|
#endif
|
|
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
|
|
// if we are not in career mode, then do not check for high score
|
|
if (!skate_mod->GetGameMode()->IsTrue( CRCD(0x1ded1ea4, "is_career") ))
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int i=0;i < Mdl::Skate::vMAX_SCORE_GOALS;i++)
|
|
{
|
|
int score = skate_mod->GetScoreGoalScore(i);
|
|
int goal = skate_mod->GetScoreGoalGoal(i);
|
|
uint32 script = skate_mod->GetScoreGoalScript(i);
|
|
if (score)
|
|
{
|
|
#ifdef DEBUG_HIGH_SCORE_GOALS
|
|
printf("For goal %2d, score %7d, script %x\n",goal,score,script);
|
|
#endif
|
|
if (old_score < score && new_score >= score)
|
|
{
|
|
#ifdef DEBUG_HIGH_SCORE_GOALS
|
|
dodgy_test(); printf("Score change works\n");
|
|
#endif
|
|
if( !skate_mod->GetCareer()->GetGoal(goal))
|
|
{
|
|
#ifdef DEBUG_HIGH_SCORE_GOALS
|
|
printf("awarding this goal, and running script");
|
|
#endif
|
|
// not got this goal yet, so give it
|
|
skate_mod->GetCareer()->SetGoal(goal);
|
|
|
|
// and run the script
|
|
skate_mod->GetSkaterById( m_skaterId )->SpawnAndRunScript(script);
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_HIGH_SCORE_GOALS
|
|
printf("Already got this goal\n");
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_HIGH_SCORE_GOALS
|
|
printf("Score change did not straddel this score\n");
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Score::SetBalanceMeter(bool state, float value)
|
|
{
|
|
Replay::WriteBalanceMeter(state,value);
|
|
//Ryan("balance: %f\n", value);
|
|
position_balance_meter(state, value, false);
|
|
}
|
|
|
|
|
|
|
|
|
|
void Score::SetManualMeter(bool state, float value)
|
|
{
|
|
Replay::WriteManualMeter(state,value);
|
|
|
|
//Ryan("balance: %f\n", value);
|
|
position_balance_meter(state, value, true);
|
|
}
|
|
|
|
|
|
|
|
|
|
void Score::SetTotalScore( int score )
|
|
{
|
|
m_totalScore = score;
|
|
|
|
// update the panel
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
|
|
/*Game::CGameMode* pGameMode = */skate_mod->GetGameMode();
|
|
// bool can_zero_score = pGameMode->IsTrue("should_modulate_color");
|
|
|
|
// printf("Setting total score for %d: %d %d %s\n", m_skaterId, score, GetTotalScore(), Script::FindChecksumName(pGameMode->GetNameChecksum()) );
|
|
|
|
Obj::CSkater* pSkater = skate_mod->GetSkaterById( m_skaterId );
|
|
Dbg_Assert( pSkater );
|
|
if ( pSkater->IsLocalClient() )
|
|
{
|
|
//HUD::PanelMgr* panel_mgr = HUD::PanelMgr::Instance();
|
|
//HUD::Panel* panel;
|
|
char score_text[64];
|
|
|
|
if( ( skate_mod->GetGameMode()->GetNameChecksum() == Script::GenerateCRC( "netking" )) ||
|
|
( skate_mod->GetGameMode()->GetNameChecksum() == Script::GenerateCRC( "king" )))
|
|
{
|
|
sprintf( score_text, "%d:%.2d", Tmr::InSeconds( m_totalScore ) / 60, Tmr::InSeconds( m_totalScore ) % 60 );
|
|
}
|
|
else
|
|
{
|
|
sprintf( score_text, "%d", m_totalScore );
|
|
}
|
|
|
|
Front::SetScoreTHPS4( score_text, pSkater->GetHeapIndex());
|
|
|
|
/*
|
|
if(( panel = panel_mgr->GetPanelBySkaterId(m_skaterId, false)))
|
|
{
|
|
panel->SetScore( m_totalScore, can_zero_score );
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
int Score::GetTotalScore()
|
|
{
|
|
GameNet::Manager * gamenet_man = GameNet::Manager::Instance();
|
|
if( gamenet_man->OnServer())
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Game::CGameMode* pGameMode = skate_mod->GetGameMode();
|
|
|
|
// server is also responsible for calculating graffiti scores
|
|
bool debug_graffiti = Script::GetInteger( "debug_graffiti" );
|
|
if ( debug_graffiti || pGameMode->IsTrue("should_modulate_color") )
|
|
{
|
|
return skate_mod->GetTrickObjectManager()->GetScore( m_skaterId );
|
|
}
|
|
else
|
|
{
|
|
return m_totalScore;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// clients already knows their total scores
|
|
return m_totalScore;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Returns the network connection.
|
|
*/
|
|
Net::Conn* Score::GetAssociatedNetworkConnection( void )
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
GameNet::Manager * gamenet_man = GameNet::Manager::Instance();
|
|
Obj::CSkater* skater;
|
|
GameNet::PlayerInfo* player;
|
|
|
|
|
|
|
|
skater = skate_mod->GetSkaterById( m_skaterId );
|
|
if( skater )
|
|
{
|
|
player = gamenet_man->GetPlayerByObjectID( skater->GetID() );
|
|
if( player )
|
|
{
|
|
return player->m_Conn;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
void Score::LogTrickObjectRequest( int score )
|
|
{
|
|
GameNet::Manager * gamenet_man = GameNet::Manager::Instance();
|
|
GameNet::PlayerInfo* player;
|
|
GameNet::MsgScoreLogTrickObject msg;
|
|
Net::MsgDesc msg_desc;
|
|
Net::Client* client;
|
|
|
|
player = gamenet_man->GetPlayerByObjectID( m_skaterId );
|
|
Dbg_Assert( player );
|
|
|
|
client = gamenet_man->GetClient( player->m_Skater->GetSkaterNumber());
|
|
Dbg_MsgAssert( client, ( "Couldn't find client for skater %d", player->m_Skater->GetSkaterNumber() ) );
|
|
|
|
msg.m_SubMsgId = GameNet::SCORE_MSG_ID_LOG_TRICK_OBJECT;
|
|
msg.m_OwnerId = m_skaterId;
|
|
msg.m_Score = score;
|
|
msg.m_GameId = gamenet_man->GetNetworkGameId();
|
|
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Obj::CSkater* skater = skate_mod->GetSkaterById( m_skaterId );
|
|
Dbg_Assert( skater );
|
|
|
|
Obj::CTrickComponent* p_trick_component = GetTrickComponentFromObject(skater);
|
|
Dbg_Assert(p_trick_component);
|
|
|
|
// send out variable length data representing the trick chain
|
|
uint32 max_pending_trick_buffer_size = GameNet::MsgScoreLogTrickObject::vMAX_PENDING_TRICKS * sizeof(uint32);
|
|
uint32 actual_pending_trick_buffer_size = p_trick_component->WritePendingTricks( msg.m_PendingTrickBuffer, max_pending_trick_buffer_size );
|
|
msg.m_NumPendingTricks = actual_pending_trick_buffer_size / sizeof( uint32 );
|
|
|
|
printf( "Client -> server %d tricks\n", msg.m_NumPendingTricks );
|
|
|
|
msg_desc.m_Data = &msg;
|
|
msg_desc.m_Length = sizeof( GameNet::MsgScoreLogTrickObject ) - max_pending_trick_buffer_size + actual_pending_trick_buffer_size;
|
|
msg_desc.m_Id = GameNet::MSG_ID_SCORE;
|
|
msg_desc.m_Queue = Net::QUEUE_SEQUENCED;
|
|
msg_desc.m_GroupId = GameNet::vSEQ_GROUP_PLAYER_MSGS;
|
|
//client->EnqueueMessageToServer( &msg_desc );
|
|
|
|
client->StreamMessageToServer( msg_desc.m_Id, msg_desc.m_Length,
|
|
msg_desc.m_Data, "TrickObj Buffer", GameNet::vSEQ_GROUP_PLAYER_MSGS );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Score::LogTrickObject( int skater_id, int score, uint32 num_pending_tricks, uint32* p_pending_tricks, bool propagate )
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
GameNet::Manager * gamenet_man = GameNet::Manager::Instance();
|
|
GameNet::MsgScoreLogTrickObject msg;
|
|
GameNet::MsgObsScoreLogTrickObject obs_msg;
|
|
Net::Server* server;
|
|
Net::Conn* conn;
|
|
GameNet::PlayerInfo* player;
|
|
Lst::Search< GameNet::PlayerInfo > sh;
|
|
|
|
if( propagate )
|
|
{
|
|
bool send_steal_message;
|
|
|
|
server = gamenet_man->GetServer();
|
|
Dbg_Assert( server );
|
|
|
|
conn = GetAssociatedNetworkConnection();
|
|
|
|
// keep track of whom we need to send the steal message to
|
|
int i;
|
|
char previous_owner_flags[GameNet::vMAX_PLAYERS];
|
|
for ( i = 0; i < GameNet::vMAX_PLAYERS; i++ )
|
|
{
|
|
previous_owner_flags[i] = 0;
|
|
}
|
|
|
|
num_pending_tricks = skate_mod->GetTrickObjectManager()->RequestLogTrick( num_pending_tricks, p_pending_tricks, previous_owner_flags, skater_id, score );
|
|
|
|
if ( !num_pending_tricks )
|
|
{
|
|
return;
|
|
}
|
|
|
|
for ( i = 0; i < GameNet::vMAX_PLAYERS; i++ )
|
|
{
|
|
if ( previous_owner_flags[i] )
|
|
{
|
|
// GJ: This only sends the stolen message to the two parties involved
|
|
|
|
GameNet::PlayerInfo* new_owner, *old_owner;
|
|
GameNet::MsgStealMessage steal_msg;
|
|
|
|
steal_msg.m_NewOwner = skater_id;
|
|
steal_msg.m_OldOwner = i;
|
|
steal_msg.m_GameId = gamenet_man->GetNetworkGameId();
|
|
|
|
new_owner = gamenet_man->GetPlayerByObjectID(skater_id);
|
|
old_owner = gamenet_man->GetPlayerByObjectID( i );
|
|
Dbg_Assert( new_owner );
|
|
|
|
send_steal_message = true;
|
|
if( skate_mod->GetGameMode()->IsTeamGame())
|
|
{
|
|
if( old_owner && new_owner && ( old_owner->m_Team == new_owner->m_Team ))
|
|
{
|
|
send_steal_message = false;
|
|
}
|
|
}
|
|
|
|
if( send_steal_message )
|
|
{
|
|
Net::MsgDesc msg_desc;
|
|
|
|
msg_desc.m_Data = &steal_msg;
|
|
msg_desc.m_Length = sizeof( GameNet::MsgStealMessage );
|
|
msg_desc.m_Id = GameNet::MSG_ID_STEAL_MESSAGE;
|
|
server->EnqueueMessage( new_owner->GetConnHandle(), &msg_desc );
|
|
|
|
steal_msg.m_NewOwner = skater_id;
|
|
steal_msg.m_OldOwner = i;
|
|
steal_msg.m_GameId = gamenet_man->GetNetworkGameId();
|
|
|
|
//Dbg_Assert( pPlayerInfo );
|
|
|
|
// For now, don't assert if the player doesn't exist anymore. Just don't do anything.
|
|
// Eventually, Gary will fix this so that pieces of exiting players are reset
|
|
if( old_owner )
|
|
{
|
|
server->EnqueueMessage( old_owner->GetConnHandle(), &msg_desc );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef __USER_GARY__
|
|
printf( "Broadcasting %d tricks\n", num_pending_tricks );
|
|
#endif
|
|
|
|
msg.m_SubMsgId = GameNet::SCORE_MSG_ID_LOG_TRICK_OBJECT;
|
|
msg.m_OwnerId = skater_id;
|
|
msg.m_Score = score;
|
|
msg.m_NumPendingTricks = num_pending_tricks;
|
|
msg.m_GameId = gamenet_man->GetNetworkGameId();
|
|
|
|
uint32 max_pending_trick_buffer_size = GameNet::MsgScoreLogTrickObject::vMAX_PENDING_TRICKS * sizeof(uint32);
|
|
uint32 actual_pending_trick_buffer_size = msg.m_NumPendingTricks * sizeof(uint32);
|
|
memcpy( msg.m_PendingTrickBuffer, p_pending_tricks, actual_pending_trick_buffer_size );
|
|
|
|
Net::MsgDesc score_msg_desc;
|
|
|
|
score_msg_desc.m_Data = &msg;
|
|
score_msg_desc.m_Length = sizeof( GameNet::MsgScoreLogTrickObject ) - max_pending_trick_buffer_size + actual_pending_trick_buffer_size;
|
|
score_msg_desc.m_Id = GameNet::MSG_ID_SCORE;
|
|
score_msg_desc.m_Queue = Net::QUEUE_SEQUENCED;
|
|
score_msg_desc.m_GroupId = GameNet::vSEQ_GROUP_PLAYER_MSGS;
|
|
// tell players to change their colors
|
|
for( player = gamenet_man->FirstPlayerInfo( sh ); player;
|
|
player = gamenet_man->NextPlayerInfo( sh ))
|
|
{
|
|
server->StreamMessage( player->GetConnHandle(), score_msg_desc.m_Id, score_msg_desc.m_Length,
|
|
score_msg_desc.m_Data, "TrickObj Buffer", GameNet::vSEQ_GROUP_PLAYER_MSGS );
|
|
//server->EnqueueMessage( player->GetConnHandle(), &score_msg_desc );
|
|
}
|
|
|
|
obs_msg.m_OwnerId = skater_id;
|
|
obs_msg.m_NumPendingTricks = num_pending_tricks;
|
|
obs_msg.m_GameId = gamenet_man->GetNetworkGameId();
|
|
max_pending_trick_buffer_size = GameNet::MsgScoreLogTrickObject::vMAX_PENDING_TRICKS * sizeof(uint32);
|
|
actual_pending_trick_buffer_size = obs_msg.m_NumPendingTricks * sizeof(uint32);
|
|
memcpy( obs_msg.m_PendingTrickBuffer, p_pending_tricks, actual_pending_trick_buffer_size );
|
|
|
|
score_msg_desc.m_Data = &obs_msg;
|
|
score_msg_desc.m_Length = sizeof( GameNet::MsgObsScoreLogTrickObject ) - max_pending_trick_buffer_size + actual_pending_trick_buffer_size;
|
|
score_msg_desc.m_Id = GameNet::MSG_ID_OBSERVER_LOG_TRICK_OBJ;
|
|
// tell observers to change their colors
|
|
for( player = gamenet_man->FirstPlayerInfo( sh, true ); player;
|
|
player = gamenet_man->NextPlayerInfo( sh, true ))
|
|
{
|
|
if( player->IsObserving())
|
|
{
|
|
server->StreamMessage( player->GetConnHandle(), score_msg_desc.m_Id, score_msg_desc.m_Length,
|
|
score_msg_desc.m_Data, "TrickObj Buffer", GameNet::vSEQ_GROUP_PLAYER_MSGS );
|
|
//server->EnqueueMessage( player->GetConnHandle(), &score_msg_desc );
|
|
}
|
|
}
|
|
|
|
// send score updates, as something has changed
|
|
skate_mod->SendScoreUpdates( false );
|
|
|
|
// Let the server's client do the rest of the work
|
|
if( conn->IsLocal())
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
#ifdef __USER_GARY__
|
|
printf( "Client is receiving %d tricks\n", num_pending_tricks );
|
|
#endif
|
|
|
|
int seq;
|
|
|
|
if( skate_mod->GetGameMode()->IsTeamGame())
|
|
{
|
|
player = gamenet_man->GetPlayerByObjectID( skater_id );
|
|
seq = player->m_Team;
|
|
}
|
|
else
|
|
{
|
|
seq = skater_id;
|
|
}
|
|
|
|
// modulate the color here
|
|
for ( uint32 i = 0; i < num_pending_tricks; i++ )
|
|
{
|
|
|
|
skate_mod->GetTrickObjectManager()->ModulateTrickObjectColor( p_pending_tricks[i], seq );
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
// utilities used by the trick counting functions to resolve a key_combo
|
|
// or trick to its trick text checksum after taking into account the number
|
|
// of taps.
|
|
inline uint32 get_trickname_checksum_from_trick_and_taps( uint32 trick_checksum, int num_taps = 1 )
|
|
{
|
|
// get the trick text and associated checksum
|
|
Script::CStruct* p_trick = Script::GetStructure( trick_checksum, Script::ASSERT );
|
|
Script::CStruct* p_trick_params;
|
|
p_trick->GetStructure( CRCD( 0x7031f10c, "params" ), &p_trick_params, Script::ASSERT );
|
|
|
|
const char* p_trick_name;
|
|
|
|
// get any double or triple tap info
|
|
while ( num_taps > 1 )
|
|
{
|
|
num_taps--;
|
|
|
|
Script::CArray* p_extra_trick_array;
|
|
uint32 extra_trick;
|
|
|
|
if ( !p_trick_params->GetChecksum( CRCD( 0x6e855102, "ExtraTricks" ), &extra_trick, Script::NO_ASSERT ) )
|
|
Dbg_MsgAssert( 0, ( "Couldn't find ExtraTricks to get multiple tap version of trick" ) );
|
|
|
|
// printf("got extra trick %s\n", Script::FindChecksumName( extra_trick ) );
|
|
|
|
p_extra_trick_array = Script::GetArray( extra_trick, Script::ASSERT );
|
|
Dbg_MsgAssert( p_extra_trick_array->GetType() == ESYMBOLTYPE_STRUCTURE, ( "Extra trick array %s had wrong type", Script::FindChecksumName( extra_trick ) ) );
|
|
Script::CStruct* p_sub_struct = p_extra_trick_array->GetStructure( 0 );
|
|
p_sub_struct->GetStructure( CRCD( 0x7031f10c, "params" ), &p_trick_params, Script::ASSERT );
|
|
}
|
|
|
|
p_trick_params->GetLocalString( CRCD( 0xa1dc81f9, "name" ), &p_trick_name, Script::ASSERT );
|
|
// printf("found name %s\n", p_trick_name);
|
|
return Script::GenerateCRC( p_trick_name );
|
|
}
|
|
|
|
inline uint32 get_trickname_checksum_from_key_combo( uint32 key_combo, int num_taps = 1 )
|
|
{
|
|
// printf("\tget_trickname_checksum_from_key_combo( %s, %i )\n", Script::FindChecksumName( key_combo ), num_taps );
|
|
|
|
// get the key mapping and trick name
|
|
Mdl::Skate * pSkate = Mdl::Skate::Instance();
|
|
Obj::CSkaterProfile* pSkaterProfile = pSkate->GetCurrentProfile();
|
|
Script::CStruct* pTricks = pSkaterProfile->GetTrickMapping( CRCD(0xd544aa2d,"trick_mapping") );
|
|
uint32 trick_checksum = 0;
|
|
|
|
// see if this is a normal or special trick
|
|
if ( !pTricks->GetChecksum( key_combo, &trick_checksum, Script::NO_ASSERT ) )
|
|
{
|
|
Script::CStruct* pSpecialTricks = pSkaterProfile->GetSpecialTricksStructure();
|
|
Script::CArray* pSpecialTricksArray;
|
|
pSpecialTricks->GetArray( NONAME, &pSpecialTricksArray, Script::ASSERT );
|
|
int numSpecials = pSpecialTricksArray->GetSize();
|
|
for ( int i = 0; i < numSpecials; i++ )
|
|
{
|
|
Script::CStruct* pSpecial = pSpecialTricksArray->GetStructure( i );
|
|
uint32 trickSlot;
|
|
pSpecial->GetChecksum( CRCD( 0xa92a2280, "TrickSlot" ), &trickSlot, Script::ASSERT );
|
|
if ( trickSlot == key_combo )
|
|
{
|
|
pSpecial->GetChecksum( CRCD( 0x5b077ce1, "TrickName" ), &trick_checksum, Script::ASSERT );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( trick_checksum == 0 )
|
|
return 0;
|
|
|
|
return get_trickname_checksum_from_trick_and_taps( trick_checksum, num_taps );
|
|
}
|
|
|
|
|
|
inline uint32 get_cat_index_from_key_combo( uint32 key_combo )
|
|
{
|
|
// printf("\tget_trickname_checksum_from_key_combo( %s, %i )\n", Script::FindChecksumName( key_combo ), num_taps );
|
|
|
|
// get the key mapping and trick name
|
|
Mdl::Skate * pSkate = Mdl::Skate::Instance();
|
|
Obj::CSkaterProfile* pSkaterProfile = pSkate->GetCurrentProfile();
|
|
Script::CStruct* pTricks = pSkaterProfile->GetTrickMapping( CRCD(0xd544aa2d,"trick_mapping") );
|
|
int cat_trick = -1;
|
|
|
|
// see if this is a normal or special trick
|
|
|
|
if ( !pTricks->GetInteger( key_combo, &cat_trick, Script::NO_ASSERT ) )
|
|
{
|
|
Script::CStruct* pSpecialTricks = pSkaterProfile->GetSpecialTricksStructure();
|
|
Script::CArray* pSpecialTricksArray;
|
|
pSpecialTricks->GetArray( NONAME, &pSpecialTricksArray, Script::ASSERT );
|
|
int numSpecials = pSpecialTricksArray->GetSize();
|
|
for ( int i = 0; i < numSpecials; i++ )
|
|
{
|
|
Script::CStruct* pSpecial = pSpecialTricksArray->GetStructure( i );
|
|
int is_cat = 0;
|
|
pSpecial->GetInteger( CRCD(0xb56a8816,"isCat"), &is_cat, Script::NO_ASSERT );
|
|
if ( is_cat != 0 )
|
|
{
|
|
uint32 trickslot;
|
|
pSpecial->GetChecksum( CRCD(0xa92a2280,"trickSlot"), &trickslot, Script::ASSERT );
|
|
if ( trickslot == key_combo )
|
|
{
|
|
uint32 cat_trick_checksum;
|
|
pSpecial->GetChecksum( CRCD(0x5b077ce1,"trickName"), &cat_trick_checksum, Script::ASSERT );
|
|
cat_trick = (int)cat_trick_checksum;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return cat_trick;
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
bool Score::VerifyTrickMatch( int info_tab_index, uint32 trick_checksum, int spin_mult, bool require_perfect )
|
|
{
|
|
if ( info_tab_index >= m_currentTrick )
|
|
return false;
|
|
|
|
// printf("\tVerifyTrickMatch( %i, %s, %i, %i )\n", info_tab_index, Script::FindChecksumName( trick_checksum ), spin_mult, require_perfect );
|
|
// printf("m_infoTab[%i].id = %s\n", info_tab_index, Script::FindChecksumName( m_infoTab[info_tab_index].id ) );
|
|
if ( m_infoTab[info_tab_index].id == trick_checksum )
|
|
{
|
|
if ( spin_mult == 0 )
|
|
return true;
|
|
else
|
|
{
|
|
// printf("spin_degrees for this trick = %i\n", m_infoTab[i].spin_degrees);
|
|
if ( spin_mult == m_infoTab[info_tab_index].spin_mult_index )
|
|
{
|
|
if ( !require_perfect )
|
|
return true;
|
|
else if ( Mth::Abs( Mth::Abs(m_infoTab[info_tab_index].spin_degrees) - ( spin_mult * 180 ) ) < Script::GetInteger( CRCD( 0xfcfacab8, "perfect_landing_slop" ) ) )
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
int Score::CountTrickMatches( uint32 trick_checksum, int spin_mult, bool require_perfect )
|
|
{
|
|
// printf("CountTrickMatches( %s, %i, %i )\n", Script::FindChecksumName( trick_checksum ), spin_mult, require_perfect );
|
|
int current_spin = 1;
|
|
|
|
int total = 0;
|
|
|
|
for ( int i = 0; i < m_currentTrick; i++ )
|
|
{
|
|
if ( m_infoTab[i].flags & vBLOCKING )
|
|
{
|
|
current_spin = 1;
|
|
}
|
|
else if ( i == 0 || ( i >= 1 && m_infoTab[i-1].flags & vBLOCKING ) )
|
|
{
|
|
current_spin = m_infoTab[i].spin_mult_index;
|
|
}
|
|
// printf("current_spin = %i\n", current_spin );
|
|
|
|
if ( m_infoTab[i].id == trick_checksum )
|
|
{
|
|
if ( spin_mult == 0 )
|
|
total++;
|
|
else
|
|
{
|
|
// printf("spin_degrees for this trick = %i\n", m_infoTab[i].spin_degrees);
|
|
if ( spin_mult == current_spin )
|
|
{
|
|
if ( !require_perfect )
|
|
total++;
|
|
else if ( Mth::Abs( Mth::Abs(m_infoTab[i].spin_degrees) - ( spin_mult * 180 ) ) < Script::GetInteger( CRCD( 0xfcfacab8, "perfect_landing_slop" ) ) )
|
|
total++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return total;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
int Score::CountStringMatches( const char* string )
|
|
{
|
|
int total = 0;
|
|
|
|
for ( int i = 0; i < m_currentTrick; i++ )
|
|
{
|
|
if ( Str::StrStr( m_infoTab[i].trickNameText, string ) )
|
|
{
|
|
total++;
|
|
}
|
|
}
|
|
return total;
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
bool Score::IsLatestTrickByName( uint32 trick_text_checksum, int spin_mult, bool require_perfect, int num_taps )
|
|
{
|
|
int index = m_currentTrick;
|
|
do
|
|
{
|
|
if (index <= 0) return false;
|
|
index--;
|
|
}
|
|
while (m_infoTab[index].trickNameText[0] == 0);
|
|
|
|
// resolve multiple tap tricks
|
|
if (num_taps > 1)
|
|
{
|
|
trick_text_checksum = get_trickname_checksum_from_trick_and_taps(trick_text_checksum, num_taps);
|
|
}
|
|
|
|
return VerifyTrickMatch(index, trick_text_checksum, spin_mult, require_perfect);
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
bool Score::IsLatestTrick( uint32 key_combo, int spin_mult, bool require_perfect, int num_taps )
|
|
{
|
|
int index = m_currentTrick;
|
|
do
|
|
{
|
|
if (index <= 0) return false;
|
|
index--;
|
|
}
|
|
while (m_infoTab[index].trickNameText[0] == 0);
|
|
|
|
// get the key mapping and trick name
|
|
uint32 trick_name_checksum = get_trickname_checksum_from_key_combo( key_combo, num_taps );
|
|
if ( trick_name_checksum == 0 )
|
|
{
|
|
// check for cat trick
|
|
int cat_trick = get_cat_index_from_key_combo( key_combo );
|
|
if ( cat_trick != -1 )
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Dbg_Assert( skate_mod );
|
|
Obj::CSkater* pSkater = skate_mod->GetLocalSkater();
|
|
if ( pSkater )
|
|
{
|
|
Game::CCreateATrick* pCreatedTrick = pSkater->m_created_trick[cat_trick];
|
|
Dbg_Assert( pCreatedTrick );
|
|
const char* p_trick_name;
|
|
pCreatedTrick->mp_other_params->GetString( CRCD( 0xa1dc81f9, "name" ), &p_trick_name, Script::ASSERT );
|
|
trick_name_checksum = Script::GenerateCRC( p_trick_name );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return VerifyTrickMatch(index, trick_name_checksum, spin_mult, require_perfect);
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
int Score::GetNumberOfNonGapTricks()
|
|
{
|
|
int non_gap_trick_count = 0;
|
|
|
|
for ( int i = 0; i < m_currentTrick; i++ )
|
|
{
|
|
if (!TrickIsGap(i))
|
|
{
|
|
non_gap_trick_count++;
|
|
}
|
|
}
|
|
|
|
return non_gap_trick_count;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
// find a trick by name, rather than by key combo
|
|
int Score::GetCurrentNumberOfOccurrencesByName( uint32 trickTextChecksum, int spin_mult, bool require_perfect, int num_taps )
|
|
{
|
|
// resolve multiple tap tricks
|
|
if ( num_taps > 1 )
|
|
{
|
|
trickTextChecksum = get_trickname_checksum_from_trick_and_taps( trickTextChecksum, num_taps );
|
|
}
|
|
|
|
// uint32 trick_name_checksum = Script::GenerateCRC( trick_string );
|
|
int num = CountTrickMatches( trickTextChecksum, spin_mult, require_perfect );
|
|
/* for ( int i = 0; i < m_currentTrick; i++ )
|
|
{
|
|
if ( VerifyTrickMatch( i, trickTextChecksum, spin_mult, require_perfect ) )
|
|
num++;
|
|
}*/
|
|
return num;
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
// searches by key combo
|
|
int Score::GetCurrentNumberOfOccurrences( uint32 key_combo, int spin_mult, bool require_perfect, int num_taps )
|
|
{
|
|
// get the key mapping and trick name
|
|
uint32 trick_name_checksum = get_trickname_checksum_from_key_combo( key_combo, num_taps );
|
|
if ( trick_name_checksum == 0 )
|
|
{
|
|
// check for cat trick
|
|
int cat_trick = get_cat_index_from_key_combo( key_combo );
|
|
if ( cat_trick != -1 )
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Dbg_Assert( skate_mod );
|
|
Obj::CSkater* pSkater = skate_mod->GetLocalSkater();
|
|
if ( pSkater )
|
|
{
|
|
Game::CCreateATrick* pCreatedTrick = pSkater->m_created_trick[cat_trick];
|
|
Dbg_Assert( pCreatedTrick );
|
|
const char* p_trick_name;
|
|
pCreatedTrick->mp_other_params->GetString( CRCD( 0xa1dc81f9, "name" ), &p_trick_name, Script::ASSERT );
|
|
trick_name_checksum = Script::GenerateCRC( p_trick_name );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int num = this->CountTrickMatches( trick_name_checksum, spin_mult, require_perfect );
|
|
/* for ( int i = 0; i < m_currentTrick; i++ )
|
|
{
|
|
if ( this->VerifyTrickMatch( i, trick_name_checksum, spin_mult, require_perfect) )
|
|
num++;
|
|
}
|
|
*/
|
|
return num;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
int Score::GetPreviousNumberOfOccurrencesByName( uint32 trickTextChecksum, int spin_mult, int num_taps )
|
|
{
|
|
// resolve multiple tap tricks
|
|
if ( num_taps > 1 )
|
|
{
|
|
trickTextChecksum = get_trickname_checksum_from_trick_and_taps( trickTextChecksum, num_taps );
|
|
}
|
|
|
|
int num = 0;
|
|
bool justSawTrick = false;
|
|
for ( int i = 0; i < m_currentTrick; i++ )
|
|
{
|
|
// printf("checking %s\n", m_infoTab[i].trickNameText );
|
|
if ( m_infoTab[i].id == trickTextChecksum )
|
|
{
|
|
// printf("found trick\n");
|
|
if ( spin_mult == 0 )
|
|
{
|
|
num++;
|
|
justSawTrick = true;
|
|
}
|
|
else if ( spin_mult == m_infoTab[i].spin_mult_index )
|
|
{
|
|
num++;
|
|
justSawTrick = true;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if ( ( m_infoTab[i].flags & vGAP ) && justSawTrick )
|
|
{
|
|
// printf("found gap after trick\n");
|
|
}
|
|
else
|
|
{
|
|
// if ( justSawTrick ) printf("found a non-gap trick after the trick\n");
|
|
justSawTrick = false;
|
|
}
|
|
}
|
|
}
|
|
if ( justSawTrick )
|
|
{
|
|
// printf("followed by gaps\n");
|
|
num--;
|
|
}
|
|
// printf("found %i previous occurences\n", num );
|
|
return num;
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
int Score::GetPreviousNumberOfOccurrences( uint32 key_combo, int spin_mult, int num_taps )
|
|
{
|
|
// printf ( "GetPreviousNumberOfOccurrences( %s, %i, %i )\n", Script::FindChecksumName( key_combo ), spin_mult, num_taps );
|
|
uint32 trick_name_checksum = get_trickname_checksum_from_key_combo( key_combo, num_taps );
|
|
|
|
if ( trick_name_checksum == 0 )
|
|
{
|
|
// check for cat trick
|
|
int cat_trick = get_cat_index_from_key_combo( key_combo );
|
|
if ( cat_trick != -1 )
|
|
{
|
|
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
|
|
Dbg_Assert( skate_mod );
|
|
Obj::CSkater* pSkater = skate_mod->GetLocalSkater();
|
|
if ( pSkater )
|
|
{
|
|
Game::CCreateATrick* pCreatedTrick = pSkater->m_created_trick[cat_trick];
|
|
Dbg_Assert( pCreatedTrick );
|
|
const char* p_trick_name;
|
|
pCreatedTrick->mp_other_params->GetString( CRCD( 0xa1dc81f9, "name" ), &p_trick_name, Script::ASSERT );
|
|
trick_name_checksum = Script::GenerateCRC( p_trick_name );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int num = 0;
|
|
bool justSawTrick = false;
|
|
for ( int i = 0; i < m_currentTrick; i++ )
|
|
{
|
|
// printf("checking %s\n", m_infoTab[i].id );
|
|
if ( m_infoTab[i].id == trick_name_checksum )
|
|
{
|
|
// printf("found trick\n");
|
|
if ( spin_mult == 0 )
|
|
{
|
|
num++;
|
|
justSawTrick = true;
|
|
}
|
|
else if ( spin_mult == m_infoTab[i].spin_mult_index )
|
|
{
|
|
num++;
|
|
justSawTrick = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ( m_infoTab[i].flags & vGAP ) && justSawTrick )
|
|
{
|
|
// printf("found gap after trick\n");
|
|
}
|
|
else
|
|
{
|
|
// if ( justSawTrick ) printf("found a non-gap trick after the trick\n");
|
|
justSawTrick = false;
|
|
}
|
|
}
|
|
}
|
|
if ( justSawTrick )
|
|
{
|
|
// printf("followed by gaps\n");
|
|
num--;
|
|
}
|
|
// printf("found %i previous occurences\n", num );
|
|
return num;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
// utility used by GetCurrentNumberOfOccurrences( Script::CArray* )
|
|
inline void GetTrickInfoFromTrickArray( Script::CArray* pTricks, int trick_array_index, uint32 *p_trick_name_checksum, int *p_spin, bool *p_require_perfect, int *p_num_taps )
|
|
{
|
|
// reset spin and perfect first
|
|
*p_spin = 0;
|
|
*p_require_perfect = false;
|
|
|
|
int num_taps = 1;
|
|
uint32 key_combo;
|
|
|
|
if ( pTricks->GetType() == ESYMBOLTYPE_STRUCTURE )
|
|
{
|
|
// grab the key combo and any spin or perfect modifiers from the struct
|
|
Script::CStruct* pSubStruct = pTricks->GetStructure( trick_array_index );
|
|
pSubStruct->GetChecksum( CRCD( 0x95e16467, "KeyCombo" ), &key_combo, Script::ASSERT );
|
|
pSubStruct->GetInteger( CRCD( 0xa4bee6a1, "num_taps" ), &num_taps, Script::NO_ASSERT );
|
|
pSubStruct->GetInteger( CRCD(0xa4bee6a1,"num_taps"), &*p_num_taps, Script::NO_ASSERT );
|
|
*p_trick_name_checksum = get_trickname_checksum_from_key_combo( key_combo, num_taps );
|
|
if ( pSubStruct->GetInteger( CRCD( 0xedf5db70, "spin" ), &*p_spin, Script::NO_ASSERT ) )
|
|
{
|
|
Dbg_MsgAssert( *p_spin % 180 == 0, ( "Bad spin value %i in gap tricks structure", *p_spin ) );
|
|
*p_spin = *p_spin / 180;
|
|
*p_require_perfect = pSubStruct->ContainsFlag( CRCD( 0x1c39f1b9, "perfect" ) );
|
|
}
|
|
// printf("\tlooking for key_combo %s\n", Script::FindChecksumName( key_combo ) );
|
|
}
|
|
else
|
|
{
|
|
Dbg_MsgAssert( pTricks->GetType() == ESYMBOLTYPE_NAME, ( "Tricks array has wrong type" ) );
|
|
*p_trick_name_checksum = get_trickname_checksum_from_key_combo( pTricks->GetChecksum( trick_array_index ) );
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
int Score::GetCurrentNumberOfOccurrences( Script::CArray* pTricks, int start_trick_index )
|
|
{
|
|
Dbg_Message("DEPRECATED! Tell Brad if you need this.\n");
|
|
return 0;
|
|
|
|
|
|
/* Dbg_MsgAssert( start_trick_index <= m_currentTrick, ( "GetCurrentNumberOfOccurrences got bad start_trick_index of %i - m_currentTrick = %i", start_trick_index, m_currentTrick ) );
|
|
|
|
int trick_array_size = pTricks->GetSize();
|
|
int total = 0;
|
|
|
|
// parse through the current list of tricks
|
|
for ( int trick_array_index = 0; trick_array_index )
|
|
{
|
|
|
|
}
|
|
for ( int i = start_trick_index; i < m_currentTrick; i++ )
|
|
{
|
|
// printf("\tcurrent trick = %s\n", Script::FindChecksumName( m_infoTab[i].id ) );
|
|
int trick_array_index = 0;
|
|
uint32 trick_name_checksum;
|
|
int spin = 0;
|
|
bool require_perfect = false;
|
|
int num_taps = 0;
|
|
GetTrickInfoFromTrickArray( pTricks, trick_array_index, &trick_name_checksum, &spin, &require_perfect, &num_taps );
|
|
|
|
while ( VerifyTrickMatch( i + trick_array_index, trick_name_checksum, spin, require_perfect ) )
|
|
{
|
|
// printf("\tfound a match\n");
|
|
// if we've matched as many tricks as are in the list, we know we've
|
|
// found a complete match
|
|
if ( trick_array_index == trick_array_size - 1 )
|
|
{
|
|
total++;
|
|
break;
|
|
}
|
|
trick_array_index++;
|
|
GetTrickInfoFromTrickArray( pTricks, trick_array_index, &trick_name_checksum, &spin, &require_perfect, &num_taps );
|
|
}
|
|
}
|
|
*/
|
|
// printf("found %i occurrence(s)\n", total);
|
|
// return total;
|
|
}
|
|
|
|
void Score::RepositionMeters( void )
|
|
{
|
|
setup_balance_meter_stuff();
|
|
}
|
|
|
|
void Score::ResetComboRecords()
|
|
{
|
|
m_longestCombo = 0;
|
|
m_bestCombo = 0;
|
|
m_bestGameCombo = 0;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Handle network scoring messages */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
int Score::s_handle_score_message ( Net::MsgHandlerContext* context )
|
|
{
|
|
GameNet::MsgEmbedded* p_msg = (GameNet::MsgEmbedded*) ( context->m_Msg );
|
|
Mdl::Score* pScore = ((Obj::CSkater*) ( context->m_Data ))->GetScoreObject();
|
|
|
|
switch ( p_msg->m_SubMsgId )
|
|
{
|
|
case GameNet::SCORE_MSG_ID_LOG_TRICK_OBJECT:
|
|
{
|
|
GameNet::MsgScoreLogTrickObject* log_msg = (GameNet::MsgScoreLogTrickObject*) ( context->m_Msg );
|
|
GameNet::Manager* gamenet_man = GameNet::Manager::Instance();
|
|
|
|
if ( log_msg->m_GameId == gamenet_man->GetNetworkGameId())
|
|
{
|
|
pScore->LogTrickObject( log_msg->m_OwnerId, log_msg->m_Score, log_msg->m_NumPendingTricks, log_msg->m_PendingTrickBuffer, false );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return Net::HANDLER_CONTINUE;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
bool Score::TrickIsGap( int trickIndex )
|
|
{
|
|
Dbg_MsgAssert( trickIndex >= 0 && trickIndex < m_currentTrick, ( "trickIndex out of range" ) );
|
|
return ( m_infoTab[trickIndex].flags & vGAP );
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void Score::set_special_is_active ( bool is_active )
|
|
{
|
|
if (is_active != m_specialIsActive)
|
|
{
|
|
m_specialIsActive = is_active;
|
|
|
|
Obj::CSkater* pSkater = Mdl::Skate::Instance()->GetSkaterById(m_skaterId);
|
|
if( pSkater )
|
|
{
|
|
pSkater->BroadcastEvent(m_specialIsActive ? CRCD(0xd0cd8081, "SkaterEnterSpecial") : CRCD(0x7ccf5ee2, "SkaterExitSpecial"));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Score::reset_robot_detection()
|
|
{
|
|
m_num_robot_landed = 0;
|
|
m_num_robot_unique = 0;
|
|
for (int i=0;i<MAX_ROBOT_NODES;i++)
|
|
{
|
|
m_robot_detection_count[i] = 0;
|
|
}
|
|
reset_robot_detection_combo();
|
|
|
|
}
|
|
|
|
void Score::reset_robot_detection_combo()
|
|
{
|
|
m_num_robot_landed_combo = 0;
|
|
m_num_robot_unique_combo = 0;
|
|
m_num_robot_first_combo = 0;
|
|
for (int i=0;i<MAX_ROBOT_NODES;i++)
|
|
{
|
|
m_robot_detection_count_combo[i] = 0;
|
|
}
|
|
m_robot_rail_mult = 1.0f;
|
|
|
|
}
|
|
|
|
void Score::UpdateRobotDetection(int node)
|
|
{
|
|
|
|
// Mick: Most levels fit inside the curretn 2500 limit
|
|
// so,rather than mess with memory, I'm just going to ignore those nodes that do not fit
|
|
// this gives us a very small chance of there being some area that is slightly more
|
|
// exploitable than others. However, since the robot line detection does not have a very noticable effect
|
|
// there will basically be no impact on the overall game experience.
|
|
// Dbg_MsgAssert(node < MAX_ROBOT_NODES,("robot node %d too big, tell Mick",node));
|
|
if (node >= MAX_ROBOT_NODES)
|
|
{
|
|
m_robot_rail_mult = 1.0f;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
m_num_robot_landed++;
|
|
m_num_robot_landed_combo++;
|
|
if (m_robot_detection_count[node] == 0)
|
|
{
|
|
m_num_robot_unique++;
|
|
m_num_robot_first_combo++;
|
|
}
|
|
if (m_robot_detection_count[node] < 255)
|
|
{
|
|
m_robot_detection_count[node]++;
|
|
}
|
|
|
|
if (m_robot_detection_count_combo[node] == 0)
|
|
{
|
|
m_num_robot_unique_combo++;
|
|
}
|
|
if (m_robot_detection_count_combo[node] < 255)
|
|
{
|
|
m_robot_detection_count_combo[node]++;
|
|
}
|
|
|
|
// GetRobotMult();
|
|
|
|
|
|
int kick_in = Script::GetInteger(CRCD(0x6ee127b7,"robot_kick_in_count"));
|
|
|
|
if (m_robot_detection_count_combo[node] > kick_in)
|
|
{
|
|
int ramp = 20;
|
|
// The first time you go over robot_kick_count, we want 1/2, everything before that will be 1.0f
|
|
m_robot_rail_mult = 1.0f/(m_robot_detection_count_combo[node]-(kick_in)+1) * ( (float)(ramp + 1 - m_robot_detection_count[node])/(float)ramp);
|
|
// Might go small or negative after a really long time, so clamp it
|
|
m_robot_rail_mult = Mth::Max(0.1f, m_robot_rail_mult);
|
|
}
|
|
else
|
|
{
|
|
m_robot_rail_mult = 1.0f;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
float Score::GetRobotMult()
|
|
{
|
|
|
|
printf ("landed = %3d, unique = %3d .. ",m_num_robot_landed,m_num_robot_unique);
|
|
printf ("combo landed = %3d, unique = %3d, first = %d\n",m_num_robot_landed_combo,m_num_robot_unique_combo,m_num_robot_first_combo);
|
|
|
|
// float unique_ratio = (float)m_num_robot_unique_combo/(float)m_num_robot_landed_combo;
|
|
// float first_ratio = (float)m_num_robot_first_combo/(float)m_num_robot_landed_combo;
|
|
// float punish = 1.0f - 0.5f * logf(robot);
|
|
// float reward = logf(m_num_robot_unique_combo) - logf(robot);
|
|
// printf ("robot = %2.3f, punish = x%2.3f, reward = x%2.3f\n",robot, punish, reward);
|
|
|
|
int min_robot_effect = 3; // number of repetitions at which "robot" adjustment begins
|
|
|
|
float sub = 0.0f;
|
|
// Scale any effect by the size of the combo, beyond the minimun needed to take effect
|
|
// float robot_scale = 0.0f;
|
|
if ((m_num_robot_landed_combo - m_num_robot_unique_combo) > min_robot_effect && m_num_robot_unique_combo < m_num_robot_landed_combo)
|
|
{
|
|
# if !defined( __PLAT_NGC__ ) || ( defined( __PLAT_NGC__ ) && !defined( __NOPT_FINAL__ ) )
|
|
float landed = m_num_robot_landed_combo - min_robot_effect;
|
|
float dupes = m_num_robot_landed_combo - m_num_robot_unique_combo - min_robot_effect;
|
|
// float first = m_num_robot_first_combo;
|
|
|
|
// robot_scale = 0.1f * logf(landed); // with min of 10, 10=0, 50 =1.6, 100 = 1.95
|
|
// find an amount to subtract from a 1.0f multiplier, based on how repeditive this line is
|
|
// float dupe_sub = (dupes/landed);
|
|
// float first_sub = 0.0f; //0.05f * logf(landed - first);
|
|
// float sub = robot_scale * (dupe_sub + first_sub);
|
|
float sub = dupes/landed;
|
|
// printf ("(dupe = %2.3f + first = %2.3f) * scale %2.3f == sub %2.3f\n", dupe_sub, first_sub, robot_scale, sub);
|
|
printf ("sub = %2.3f\n",sub);
|
|
#endif // __NOPT_FINAL__
|
|
}
|
|
|
|
float mult = 1.0f - sub;
|
|
if (mult > 1.0f)
|
|
{
|
|
mult = 1.0f;
|
|
}
|
|
if (mult < 0.2f)
|
|
{
|
|
mult = 0.2f;
|
|
}
|
|
printf ("mult = %2.3f\n",mult);
|
|
return mult;
|
|
}
|
|
|
|
|
|
|
|
} // namespace HUD
|
|
|
|
|
|
|
|
|