khanat-opennel-code/code/ryzom/client/src/forage_source_cl.cpp

685 lines
18 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdpch.h"
#include "interface_v3/interface_manager.h"
#include "forage_source_cl.h"
#include "ingame_database_manager.h"
#include "debug_client.h"
#include "game_share/rm_family.h"
#include "client_sheets/forage_source_sheet.h"
#include "interface_v3/group_in_scene_user_info.h"
#include "fx_manager.h"
#include "string_manager_client.h"
#include "sheet_manager.h"
#include "entities.h"
#include "view.h"
#include "time_client.h"
#include "game_share/constants.h"
#include <nel/misc/i18n.h>
using namespace NL3D;
using namespace NLMISC;
extern class CView View;
extern UCamera MainCam;
const uint8 BarNotInit = 255;
CRGBA CForageSourceCL::SafeSourceColor(64, 192, 255);
/*
* Constructor
*/
CForageSourceCL::CForageSourceCL() :
CFxCL(),
_InSceneUserInterface( NULL ),
_IconFilename( NULL ),
_IsExtractionInProgress( false ),
_SafeSource( false ),
_KnowledgeLevel( 0 ),
_LastExplosionSwitch( 0 ),
_ProspectorSlot( 255 ),
_ExtraTime(0),
_InclBonusExtraTime(0),
_InitialQuantity(BarNotInit),
_CurrentQuantity(0)
{
for ( uint i=0; i!=NbFSBarIndices-1; ++i )
{
_BarDestValues[i] = BarNotInit;
_BarCurrentValues[i] = BarNotInit;
}
_BarDestValues[NbFSBarIndices-1] = BarNotInit;
// init to 0 per default (first frames...)
_TimeBar= 0;
_QuantityBar= 0;
_DBar= 0;
_EBar= 0;
}
/*
* Initialize properties of the entity (according to the class).
*/
void CForageSourceCL::initProperties()
{
CFxCL::initProperties();
properties().selectable( true );
}
/*
* Build the entity from a sheet.
*/
bool CForageSourceCL::build( const CEntitySheet *sheet )
{
//_CrtCheckMemory();
// Get FX filename and info from the sheet
const CForageSourceSheet *forageSourceSheet = dynamic_cast<const CForageSourceSheet*>(sheet);
if ( ! forageSourceSheet )
{
nlwarning( "Bad sheet %s for forage source", sheet->Id.toString().c_str() );
return false;
}
if ( ! setFx( forageSourceSheet->FxFilename ) )
return false;
_KnowledgeLevel = forageSourceSheet->Knowledge;
if ( _KnowledgeLevel != 0 )
_KnowledgeLevel |= 0x80; // we don't know the group or family yet (visual FX not received)
// Base class init
initialize();
Type = ForageSource;
if(IngameDbMngr.getNodePtr())
{
CCDBNodeBranch *nodeRoot = dynamic_cast<CCDBNodeBranch *>(IngameDbMngr.getNodePtr()->getNode(0));
if(nodeRoot)
{
_DBEntry = dynamic_cast<CCDBNodeBranch *>(nodeRoot->getNode(_Slot));
if(_DBEntry == 0)
pushDebugStr("Cannot get a pointer on the DB entry.");
}
}
// Set default name (with no knowledge)
_EntityName = CI18N::get( "mpSource" );
// Build hud interface
buildInSceneInterface();
// Init user params
UParticleSystemInstance fxInst;
fxInst.cast (_Instance);
nlassert(!fxInst.empty());
fxInst.setUserParam( 0, 0.0f ); // inversed opacity
fxInst.setUserParam( 1, 0.0f ); // glow
fxInst.setUserParam( 2, 0.0f ); // particle quantity
//_CrtCheckMemory();
return true;
}
void CForageSourceCL::resetVP()
{
// Init user params
UParticleSystemInstance fxInst;
fxInst.cast (_Instance);
nlassert(!fxInst.empty());
fxInst.setUserParam( 0, 0.0f ); // inversed opacity
fxInst.setUserParam( 1, 0.0f ); // glow
fxInst.setUserParam( 2, 0.0f ); // particle quantity
nlinfo( "FG: Source: %s FX: %s", _Position.asVector().asString().c_str(), fxInst.getPos().toString().c_str() );
}
/*
* Rebuild in scene interfaces
*/
void CForageSourceCL::buildInSceneInterface()
{
// Delete previous interface
releaseInSceneInterfaces();
_InSceneUserInterface = CGroupInSceneUserInfo::build( this );
_InSceneUserInterface->setUserScale( true );
// parent
CFxCL::buildInSceneInterface();
}
/*
* Destroy inscene interfaces
*/
void CForageSourceCL::releaseInSceneInterfaces()
{
if (_InSceneUserInterface)
{
CInterfaceManager::getInstance()->unMakeWindow(_InSceneUserInterface);
if (_InSceneUserInterface->getParent())
{
_InSceneUserInterface->getParent()->delGroup(_InSceneUserInterface);
}
else
{
delete _InSceneUserInterface;
}
_InSceneUserInterface = NULL;
}
}
/*
* Called when clipped out
*/
void CForageSourceCL::updateClipped (const NLMISC::TTime &currentTimeInMs, CEntityCL *target)
{
// hide the scene interface
if (_InSceneUserInterface)
{
if (_InSceneUserInterface->getActive())
_InSceneUserInterface->setActive (false);
}
// parent
CFxCL::updateClipped(currentTimeInMs, target);
}
/*
* Method called each frame to manage the entity after the clipping test if the primitive is visible.
*/
void CForageSourceCL::updateVisible(const NLMISC::TTime &time, CEntityCL *target)
{
// Update Modifiers
if(!_HPModifiers.empty())
{
HPMD mod;
mod.CHPModifier::operator= (*_HPModifiers.begin());
mod.Time = TimeInSec;
_HPDisplayed.push_back(mod);
_HPModifiers.erase(_HPModifiers.begin());
}
// parent
CFxCL::updateVisible(time, target);
}
/*
* Helper for updateVisualPropertyBars()
*/
inline void setBarValue( float& currentValue, uint8& displayedValue, uint8& newValue )
{
displayedValue = newValue;
currentValue = (float)displayedValue;
}
/*
* Helper for updateVisiblePostPos()
*/
inline void updateBarValueTime( uint8& destValue, float& currentValue, uint8& displayedValue )
{
sint8 diff = (sint8)(destValue - displayedValue);
if ( diff < 0 )
{
currentValue = std::max( (float)destValue, currentValue - DeltaTimeBarPerSec*DT );
displayedValue = (uint8)currentValue;
}
else if ( diff > 0 )
{
currentValue = (float)destValue;
displayedValue = destValue;
}
}
/*
* Helper for updateVisiblePostPos()
*/
inline void updateBarValue( uint8& destValue, float& currentValue, uint8& displayedValue )
{
sint8 diff = (sint8)(destValue - displayedValue);
if ( diff < 0 )
{
currentValue = std::max( (float)destValue, currentValue - DeltaMoveBarPerSec*DT );
displayedValue = (uint8)currentValue;
}
else if ( diff > 0 )
{
float speed = (destValue == 127) ? DeltaResetBarPerSec : DeltaMoveBarPerSec;
currentValue = std::min( (float)destValue, currentValue + speed*DT );
displayedValue = (uint8)currentValue;
}
}
/*
* Update the entity after all positions done.
*/
void CForageSourceCL::updateVisiblePostPos(const NLMISC::TTime &time, CEntityCL *target)
{
// Update in scene interface
if( _InSceneUserInterface )
{
float dist = (_Position.asVector() - View.currentViewPos()/*UserEntity->pos()*/).norm();
// Draw the interface is bars received
bool showIS = (dist < (CLFECOMMON::THRESHOLD_BARS/1000 - 5.0f) ); //mustShowInsceneInterface( true );
// Activate
if ( _InSceneUserInterface->getActive() != showIS )
_InSceneUserInterface->setActive( showIS );
if ( showIS )
{
// Scale it
const float ClampDist = 8.0f; // > 0
if ( dist < ClampDist )
_InSceneUserInterface->Scale = 1.0f;
else
_InSceneUserInterface->Scale = ClampDist / dist;
// Update dynamic data
_InSceneUserInterface->updateDynamicData();
// Update position
NLMISC::CVectorD pos;
pos = (box().getMin() + box().getMax())/2;
pos.z = box().getMax().z; // * 0.7f; // not as high as the top of the box
nlassert(isValidDouble(pos.x) && isValidDouble(pos.y) && isValidDouble(pos.z));
_InSceneUserInterface->Position = pos;
}
}
// Update bar delayed movement
updateBarValueTime( _BarDestValues[FSBTime], _BarCurrentValues[FSBTime], _TimeBar ); // Time (slower transition)
updateBarValue( _BarDestValues[FSBQuantiy], _BarCurrentValues[FSBQuantiy], _QuantityBar ); // Qtty
updateBarValue( _BarDestValues[FSBD], _BarCurrentValues[FSBD], _DBar ); // D
updateBarValue( _BarDestValues[FSBE], _BarCurrentValues[FSBE], _EBar ); // E
// Parent
CFxCL::updateVisiblePostPos(time, target);
}
void CForageSourceCL::displayInscenePos()
{
nlinfo( "FG: Source: %s Inscene: %s % slot: %u", _Position.asVector().asString().c_str(), _InSceneUserInterface->Position.asString().c_str(), (slot() == UserEntity->selection()) ? "SELECTED":"Unselected", slot() );
}
/*
* Update Entity Visual Property B
*/
/*void CForageSourceCL::updateVisualPropertyVpb(const NLMISC::TGameCycle &gameCycle, const sint64 &prop)
{
}*/
bool ForageSourceUseUP;
float ForageSourceUP0;
float ForageSourceUP1;
float ForageSourceUP2;
float ForageSourceUP3;
NLMISC_VARIABLE( bool, ForageSourceUseUP, "Use debug user param" );
NLMISC_VARIABLE( float, ForageSourceUP0, "" );
NLMISC_VARIABLE( float, ForageSourceUP1, "" );
NLMISC_VARIABLE( float, ForageSourceUP2, "" );
NLMISC_VARIABLE( float, ForageSourceUP3, "" );
/*
* Update Entity Bars
*/
void CForageSourceCL::updateVisualPropertyBars(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
// NB: forage don't use CBarManager for 2 reasons: useless (forage bars exist only through VP),
// and complicated since updated at each frame on client (because of smooth transition code below)
bool setBarsNow = (_BarDestValues[0] == BarNotInit);
_BarDestValues[FSBTime] = (uint8)(prop&0x7f); // Time to live
_BarDestValues[FSBD] = (uint8)((prop>>14)&0x7f); // D
_BarDestValues[FSBE] = (uint8)((prop>>21)&0x7f); // E
// Deal with safe sources
if (_BarDestValues[FSBE]==0) // Safe source
{
_BarDestValues[FSBE] = 127;
/* // This is disabled coz setFx don't work after entity creation (:TODO: try to see why)
if (!_SafeSource)
{
CEntitySheet *entitySheet = SheetMngr.get(sheetId());
const CForageSourceSheet *forageSourceSheet = dynamic_cast<const CForageSourceSheet*>(entitySheet);
if ( forageSourceSheet )
{
if ( ! setFx( forageSourceSheet->FxSafeFilename ) )
setFx( forageSourceSheet->FxFilename );
}
}
*/
_SafeSource = true;
}
else
{
/* // This is disabled coz setFx don't work after entity creation (:TODO: try to see why)
if (_SafeSource)
{
CEntitySheet *entitySheet = SheetMngr.get(sheetId());
const CForageSourceSheet *forageSourceSheet = dynamic_cast<const CForageSourceSheet*>(entitySheet);
if ( forageSourceSheet )
setFx( forageSourceSheet->FxFilename );
}
*/
_SafeSource = false;
}
if ( setBarsNow )
{
setBarValue( _BarCurrentValues[FSBTime], _TimeBar, _BarDestValues[FSBTime] );
_InitialQuantity = ((uint8)((prop>>7)&0x7f)); // Quantity
if ( _InitialQuantity != 0 )
{
_CurrentQuantity = _InitialQuantity;
_BarDestValues[FSBQuantiy] = 127;
}
else
{
_CurrentQuantity = 0;
_BarDestValues[FSBQuantiy] = 0;
}
setBarValue( _BarCurrentValues[FSBQuantiy], _QuantityBar, _BarDestValues[FSBQuantiy] );
setBarValue( _BarCurrentValues[FSBD], _DBar, _BarDestValues[FSBD] );
setBarValue( _BarCurrentValues[FSBE], _EBar, _BarDestValues[FSBE] );
}
else
{
_CurrentQuantity = (uint8)((prop>>7)&0x7f);
_BarDestValues[1] = (_InitialQuantity != 0) ? (_CurrentQuantity * 127 / _InitialQuantity) : 0; // Quantity
}
if ( ! _IsExtractionInProgress )
{
_IsExtractionInProgress = (bool)((prop>>28)&1);
if ( _IsExtractionInProgress )
buildInSceneInterface(); // Rebuild hud interface
}
if ( !_Instance.empty() )
{
UParticleSystemInstance fxInst;
fxInst.cast (_Instance);
nlassert(!fxInst.empty());
if ( ForageSourceUseUP )
{
fxInst.setUserParam( 0, ForageSourceUP0 );
fxInst.setUserParam( 1, ForageSourceUP1 );
fxInst.setUserParam( 2, ForageSourceUP2 );
fxInst.setUserParam( 3, ForageSourceUP3 );
}
else
{
// Link Time to live to user param 1 (127-> 0=bright; 0-> 0.9=dark&transparent)
fxInst.setUserParam( 0, 1.0f - (((float)_BarDestValues[0])*(0.9f / 127.0f) + 0.1f) );
// Link E to user param 1 (glow)
fxInst.setUserParam( 1, ((float)(127-_BarDestValues[3])) / 127.0f );
// :TODO: Find a way to change fx or fx color. setUserColor does a modulate, so it's not suitable.
// if (_SafeSource)
// fxInst.setUserColor(CRGBA(255,0,0));
// Link Quantity to user param 2 (particle quantity)
fxInst.setUserParam( 2, std::min( 1.0f, ((float)_CurrentQuantity) / 50.0f) ); // map 100% to quantity 50
}
}
}
/*
* Update Entity Orientation.
* Used to carry the kami anger bar (does not change often)
*/
void CForageSourceCL::updateVisualPropertyOrient(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
uint u = (uint)prop;
_BarDestValues[4] = (uint8)(u&0x7f);
_ExtraTime = (uint8)((u>>7)&0x7f);
_InclBonusExtraTime = (uint8)((u>>14)&0x7f);
}
/*
* Update Visual FX.
* Contains group or family (if knowledge is 1 or 2-3), and explosion state.
*/
void CForageSourceCL::updateVisualPropertyVisualFX(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
// Display explosion FX if the switch flag tells us to do it
uint8 receivedExplosionSwitch = (uint8)((prop & 0x400) >> 10);
if ( receivedExplosionSwitch && (receivedExplosionSwitch != _LastExplosionSwitch) ) // bit 10
{
UParticleSystemInstance fxNewInst = FXMngr.instantFX( "FOR_explosion.ps" );
if ( !fxNewInst.empty() )
fxNewInst.setPos( pos() );
}
_LastExplosionSwitch = receivedExplosionSwitch;
// Set family or group knowledge info
if ( (_KnowledgeLevel & 0x80) != 0 )
{
uint32 index = (uint32)(prop&0x3ff); // 10 bits
_KnowledgeLevel &= 0x7F;
switch ( _KnowledgeLevel )
{
//case 0: default name unchanged
case 1: _EntityName = RM_GROUP::toLocalString( (RM_GROUP::TRMGroup)index ); break; // display group as title
case 2: _EntityName = RM_FAMILY::toLocalString( (RM_FAMILY::TRMFamily)index ); break; // display family as title
// case 3: received by property Name (see below)
}
if ( (_KnowledgeLevel<=2) && (_ProspectorSlot != 255) )
{
CEntityCL *prospector = EntitiesMngr.entities()[_ProspectorSlot];
if (prospector != NULL)
{
ucstring prospectorName = prospector->getDisplayName();
if ( ! prospectorName.empty() )
_EntityName += ucstring(" [") + prospectorName + ucstring("]");
}
}
// Set icon (2 and 3: the family index is transmitted (for knowledge 3, used only as icon index))
CEntitySheet *sheet = SheetMngr.get( sheetId() );
const CForageSourceSheet *forageSourceSheet = dynamic_cast<const CForageSourceSheet*>(sheet);
if ( forageSourceSheet && (index < forageSourceSheet->Icons.size()) )
{
_IconFilename = &(forageSourceSheet->Icons[index]);
}
// Rebuild inscene interface
buildInSceneInterface();
}
}
/*
* Update Entity Name.
* Interpret the property Name as the sheet id (it's not the usual string id!) of
* the raw material, when the knowledge is 3.
*/
void CForageSourceCL::updateVisualPropertyName(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
CSheetId rmSheetId( (const uint32&)prop );
const ucchar *name = STRING_MANAGER::CStringManagerClient::getItemLocalizedName( rmSheetId );
if ( name )
{
_EntityName = name;
if ( _ProspectorSlot != 255 )
{
CEntityCL *prospector = EntitiesMngr.entities()[_ProspectorSlot];
if (prospector != NULL)
{
ucstring prospectorName = prospector->getDisplayName();
if ( ! prospectorName.empty() )
_EntityName += ucstring(" [") + prospectorName + ucstring("]");
}
}
// Rebuild inscene interface
buildInSceneInterface();
}
}
/*
* Update Entity Target.
*/
void CForageSourceCL::updateVisualPropertyTarget(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
sint slot = (sint)prop;
if ( slot != CLFECOMMON::INVALID_SLOT )
{
_ProspectorSlot = slot;
CEntityCL *prospector = EntitiesMngr.entities()[_ProspectorSlot]; // NULL if entity not received
if (prospector != NULL)
{
ucstring prospectorName = prospector->getDisplayName();
if ( ! prospectorName.empty() )
_EntityName = _EntityName + ucstring(" [") + prospectorName + ucstring("]");
}
// Rebuild inscene interface
buildInSceneInterface();
}
}
/*
* Display the modifiers
*/
void CForageSourceCL::displayModifiers()
{
// if none, no op
if( _HPDisplayed.empty())
return;
// **** get the name pos
NLMISC::CVector namePos = pos() + CVector(0.f, 0.f, 0.8f);
// **** compute the scale
float dist = (MainCam.getPos()-pos()).norm();
float scale= 1.f;
if(dist > ClientCfg.MaxNameDist)
return;
if ( dist < ClientCfg.ConstNameSizeDist )
scale = 1.0f;
else
scale = ClientCfg.ConstNameSizeDist / dist;
// **** Display HP modifiers.
CInterfaceManager *pIM= CInterfaceManager::getInstance();
std::list<HPMD>::iterator itTmp;
std::list<HPMD>::iterator it = _HPDisplayed.begin();
while(it != _HPDisplayed.end())
{
HPMD &mod = *it;
//
const float totalDuration= 3.f;
const float noFadeDuration= 1.f;
const float fadeDuration= totalDuration-noFadeDuration;
if(TimeInSec > (mod.Time+totalDuration))
{
itTmp = it;
++it;
_HPDisplayed.erase(itTmp);
}
else
{
uint16 qttyDelta = ((uint16)mod.Value) & 0xFF;
uint16 qlty = ((uint16)mod.Value) >> 8;
ucstring hpModifier = ucstring(toString("%u ", qttyDelta) + CI18N::get("uittQualityAbbrev") + toString(" %u", qlty));
double t = TimeInSec-mod.Time;
// Compute the position for the Modifier.
CVector pos= namePos + CVector(0.0f, 0.0f, 0.3f+(float)t*1.0f/totalDuration);
// get the color
CRGBA color;
if(mod.Value < 0)
color = CRGBA(220,0,0);
else
color = CRGBA(0,220,0);
// fade
if(t<noFadeDuration)
color.A= 255;
else
color.A= 255-(uint8)((t-noFadeDuration)*255.0/fadeDuration);
// Display the name
pIM->FlyingTextManager.addFlyingText(&mod, hpModifier, pos, color, scale);
// Next
++it;
}
}
}
/*
* Destructor
*/
CForageSourceCL::~CForageSourceCL()
{
releaseInSceneInterfaces();
}
/*NLMISC_COMMAND( resetSourceVP, "", "" )
{
CLFECOMMON::TCLEntityId slot = UserEntity->selection();
CEntityCL *selection = EntitiesMngr.entities()[slot];
if ( selection && selection->isForageSource() )
{
((CForageSourceCL*)selection)->resetVP();
}
return true;
}
CForageSourceCL *ViewedSource = NULL;
NLMISC_COMMAND( viewSourcePos, "", "" )
{
CLFECOMMON::TCLEntityId slot = UserEntity->selection();
CEntityCL *selection = EntitiesMngr.entities()[slot];
if ( selection && selection->isForageSource() )
{
ViewedSource = ((CForageSourceCL*)selection);
ViewedSource->displayInscenePos();
}
else
{
// Use with caution
ViewedSource->displayInscenePos();
}
return true;
}*/