// Ryzom - MMORPG Framework
// 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 .
#ifndef RY_DEPOSIT_H
#define RY_DEPOSIT_H
#include "nel/ligo/primitive.h"
#include "egs_sheets/egs_static_deposit.h"
#include "game_share/time_weather_season/time_and_season.h"
#include "game_share/ecosystem.h"
#include "game_share/rm_family.h"
#include "harvest_info.h"
#include "mission_manager/ai_alias_translator.h"
#include "egs_variables.h"
#include "nel/misc/random.h"
#include "nel/misc/variable.h"
class CDeposit;
const uint16 MaxNbActiveSources = std::numeric_limits::max();
/**
* A recent forage site prevents from extracting too much material from the same place in a short time.
* When an extraction is succesful, a timer is launched. If no more extraction is done then, the site
* is destroyed after the time is elapsed. If an extraction fails (no more stock available), the site
* will be blocked for extraction (isDepleted() will be true) during the specified time, then freed.
* Note: the timer resolution is abstract. The actual time in ticks will depend on the rate of update.
*/
class CRecentForageSite
{
public:
/// Create forage site. Precondition: dep not NULL.
CRecentForageSite( CDeposit *dep, const NLMISC::CVector& pos ) : _Deposit(dep), _Pos(pos), _TimeToLive(ForageSiteNbUpdatesToLive.get()), _LowScopeStock(ForageSiteStock.get()), _NbActiveSources(0) {}
/// Add a source
bool addActiveSource() { if ( _NbActiveSources == MaxNbActiveSources ) return false; ++_NbActiveSources; return true; }
/// Remove a source
void removeActiveSource() { nlassert(_NbActiveSources!=0); --_NbActiveSources; } // TEMP: assert
/// Return the quantity available in the deposit (or FLT_MAX if there is no quantity constraint)
float getQuantityInDeposit();
/**
* Consume 1 unit of forage site stock by a source in the (independant on the quantity extracted).
* Reset life time of forage site if successful.
* Additionally, consume n units of deposit stock (dependant on the quantity extracted).
* Return the actual quantity that is extracted (can be less that requested if the deposit is (nearly or fully) empty.
*/
float consume( float n );
/// Consume all stock at once
void depleteAll() { _LowScopeStock = 0; _TimeToLive = ForageSiteNbUpdatesToLive.get(); }
/** Update forage site. Return false if the forage site lifetime is ended and the object must be destroyed (which won't occur while there are active sources)
* This method does not need to be called every tick, but at the rate of CDeposit::lowFreqUpdate().
*/
bool lowFreqUpdate() { if ( _TimeToLive != 0 ) { --_TimeToLive; return true; } else return hasActiveSources(); }
/// Return deposit (never NULL).
const CDeposit *deposit() const { return _Deposit; }
/// Return center position
const NLMISC::CVector& pos() const { return _Pos; }
/// Test if site is depleted
bool isDepleted() const { return _LowScopeStock == 0; }
/// Test if site contains a position
bool contains( const NLMISC::CVector& pos ) const;
/// Display debug or stat info
void display( NLMISC::CLog& log ) const;
/// True if the owned deposit allo depletion risk
bool allowDepletionRisk() const;
protected:
/// Test if site has sources
bool hasActiveSources() const { return _NbActiveSources!=0; }
private:
/// Pointer to deposit (deposits don't move in memory). Never NULL.
CDeposit *_Deposit;
/// Center of site area
NLMISC::CVector _Pos;
///
uint16 _TimeToLive;
///
uint16 _LowScopeStock;
///
uint16 _NbActiveSources;
};
typedef std::list CRecentForageSites;
/**
* Type of ecosystem or terrain.
* CEcotype ojects are loaded from primitives, are used to build CDeposit objects, then erased.
*/
class CEcotypeZone : public NLLIGO::CPrimZone
{
public:
/// Init
bool build( const NLLIGO::CPrimZone* zone );
/// Return ecotype
TEcotype ecotype() const { return _Ecotype; }
private:
///
TEcotype _Ecotype;
};
typedef std::vector< CEcotypeZone* > CEcotypeZones;
/**
* Properties of auto-spawn sources of a deposit
*/
struct CAutoSpawnProperties
{
NL_INSTANCE_COUNTER_DECL(CAutoSpawnProperties);
public:
/// In game cycles, but depends of the update frequency of the deposits
uint32 SpawnPeriodGc;
/// Time before disappearance when no extraction has started (game cycles)
uint32 LifeTimeGc;
/// Time remaining since the beginning of the first extraction
uint32 ExtractionTimeGc;
/// Minimium Number of Auto-Spawned Sources that must always exist
uint32 MinimumSpawnedSources;
};
/**
* Quantity constraints
*/
struct CQuantityConstraints
{
NL_INSTANCE_COUNTER_DECL(CQuantityConstraints);
public:
/// Current quantity (shared by all materials in the deposit)
float CurrentQuantity;
/// Day of the next respawn (valid if CurrentQuantity is 0)
uint32 NextRespawnDay;
/// Initial quantity
uint16 InitialQuantity;
/// Time before the initial quantity becomes available backs, in Ryzom Days (note: 30 days for a whole season)
uint16 RespawnTimeRyzomDays;
/// Return the current quantity. If 0 and the respawn time is elapsed, unlock.
float getCurrentQuantity();
/// Consume. If the current quantity falls to 0, lock. Return the actual consumed quantity.
float consumeQuantity( float consumed );
};
namespace NLMISC
{
class IVariable;
class CWordsDictionary;
}
/**
* \author Nicolas Brigand, Alain Saffray, Olivier Cado
* \author Nevrax France
* \date 2003
*/
class CDeposit : public NLLIGO::CPrimZone, public NLMISC::CRefCount
{
public:
/// Constructor
CDeposit() : _AutoSpawnSourcePt(NULL), _QuantityConstraintsPt(NULL), _Ecotype(ECOSYSTEM::common_ecosystem), _FilterPhase(0), _KamiAnger(0.0f), _MinQuality(-1), _MaxQuality(-1), _SourceFXIndex(0), _CanProspect(false), _Enabled(false), _CurrentNbAutoSpawnedSources(0), _AllowDepletionRisk(true) {}
/// Destructor
~CDeposit();
/// Add an ecotype information
static void addEcotype( CEcotypeZone *ecotypeZone ) { _EcotypeZones.push_back( ecotypeZone ); }
/// Init deposit
bool build( const NLLIGO::CPrimZone* zone );
/// Clear all ecotype information, after having built the deposits
static void clearEcotypes();
// Update deposit (especially recent forage sites).
void lowFreqUpdate();
// Update deposit that need to auto spawn because number of harvest sources is too low
void autoSpawnUpdate();
// fill CHarvestInfos with deposit founded
///void harvestInfo( const NLMISC::CEntityId& charId, HARVEST_INFOS::CHarvestInfos& infos );
// character take MP, kami eat this fool character ?
//void characterTakeRM( const NLMISC::CEntityId& charId, uint32 depositIndexContent, uint16 quantity );
// Display deposit content
void displayContent( NLMISC::CLog * log = NLMISC::InfoLog, bool extendedInfo=false, NLMISC::CWordsDictionary *itemDictionary=NULL );
const std::string& name() const { return _Name; }
/// Return the number of MPS in the deposit
uint getContentSize() const { return (uint)_RawMaterials.size(); }
/// Return the MPS
const std::vector& getContents() const { return _RawMaterials; }
/// Return the terrain type
TEcotype ecotype() const { return _Ecotype; }
/// Return the MinQuality
sint16 minQuality() const { return _MinQuality; }
/// Return the MaxQuality or -1 if it has to be taken from the raw material information
sint16 maxQuality() const { return _MaxQuality; }
/// Return the index of the visual shape/FX of the sources from this deposit
uint16 sourceFXIndex() const { return _SourceFXIndex; }
/// Return true if the deposit is currently enabled
bool enabled() const { return _Enabled; }
/// Enable(true)/Disable(false) the deposit
void enable(bool bEnable) { _Enabled = bEnable; }
/// Return true if the deposit can be prospected
bool canProspect() const { return _CanProspect; }
/// Return true if the submitted terrain matches the deposit
bool matchEcotype( TEcotype t ) const
{ return t==_Ecotype; }
/// Return true if the submitted season matches the deposit
bool matchSeason( CRyzomTime::ESeason s ) const
{ return _SeasonFilter.empty() || (std::find( _SeasonFilter.begin(), _SeasonFilter.end(), s ) != _SeasonFilter.end()); }
/// Return true if the submitted weather matches the deposit
bool matchWeather( CRyzomTime::EWeather w ) const
{ return _WeatherFilter.empty() || (std::find( _WeatherFilter.begin(), _WeatherFilter.end(), w ) != _WeatherFilter.end()); }
/// Return true if the submitted time of day matches the deposit
bool matchTimeOfDay( CRyzomTime::ETimeOfDay t ) const
{ return _TimeOfDayFilter.empty() || (std::find( _TimeOfDayFilter.begin(), _TimeOfDayFilter.end(), t ) != _TimeOfDayFilter.end()); }
/// Return true if the deposit contains at least one RM of the specified family
bool hasFamily( RM_FAMILY::TRMFamily family ) const;
/// Return true if the deposit contains at least one RM of the specified group
bool hasGroup( RM_GROUP::TRMGroup group ) const;
/// Return true if the deposit contains at least one RM than can craft the specified item part
bool hasRMForItemPart( uint itemPartIndex ) const;
/// Return true if the deposit contains at least one RM with energy lower_eq than the specified value
bool hasLowerStatEnergy( uint8 maxStatEnergy ) const;
/// Return true if the deposit contains at least one RM with energy equalling the specifing value
bool hasExactStatEnergy( uint8 statEnergy ) const;
/// Return the kami anger level (or -1 if disabled)
float kamiAnger() const { return _KamiAnger; }
/// Set the kami anger level
void setKamiAnger( float newKamiAnger ) { _KamiAnger = newKamiAnger; }
/// Increment the kami anger level. React if a threshold is reached. Return the kami anger level (see kamiAnger())
float incKamiAnger( float delta, const std::vector& foragers );
/// Decrement the kami anger level (result clamped to 0)
float decKamiAnger( float delta ) { if ( _KamiAnger != -1.0f ) { _KamiAnger -= delta; if ( _KamiAnger < 0 ) _KamiAnger = 0; } return _KamiAnger; }
/// True if the deposit allow depletion risk for recent forage site
bool allowDepletionRisk() const {return _AllowDepletionRisk;}
/// Return the auto spawn properties (if auto-spawn is on, otherwise return NULL)
const CAutoSpawnProperties *getAutoSpawnProperties() const { return _AutoSpawnSourcePt; }
/// Return the quantuty constraints (if any, otherwise return NULL)
const CQuantityConstraints *getQuantityConstraints() const { return _QuantityConstraintsPt; }
/// Return the quantity available in the deposit (or FLT_MAX if there is no quantity constraint)
float getMaxQuantity() { return _QuantityConstraintsPt ? _QuantityConstraintsPt->getCurrentQuantity() : FLT_MAX; }
/// Consume. Return the actual consumed quantity (may be lower if there is no more to get)
float consumeQuantity( float requested ) { if ( _QuantityConstraintsPt ) return _QuantityConstraintsPt->consumeQuantity( requested ); else return requested; }
/**
* Get a random RM from the neighbourhood of the specified position.
* OptFastFloorBegin()/OptFastFloorEnd() must enclose one or more calls to this method.
*/
const CStaticDepositRawMaterial *getRandomRMAtPos( const NLMISC::CVector& pos, bool testIfSiteDepleted, bool& isDepleted );
/**
* Get the RM at the specified position (no random for map generation).
* OptFastFloorBegin()/OptFastFloorEnd() must enclose one or more calls to this method.
* \param testIfSiteDepleted Set it to false for map generation.
*/
const CStaticDepositRawMaterial *getRMAtPos( const NLMISC::CVector& pos, bool testIfSiteDepleted, bool& isDepleted );
/// Return always a forage site
CRecentForageSite *findOrCreateForageSite( const NLMISC::CVector& pos );
/// Display forage sites info
void displayRecentForageSites( NLMISC::CLog& log ) const;
/// Empty all forage sites
void depleteAllRecentForageSites();
// For auto-spawn source minimum number. Internaly used by CHarvestSource only
void decreaseAutoSpawnedSources();
void increaseAutoSpawnedSources();
protected:
/// Select the raw materials, using the specified filters and _Ecotype
void selectRMsByFilters( std::vector& exactRMCodesS, const std::vector& rmFamilyFilterS, const std::vector& itemPartsFilterS, const std::vector& craftCivS, uint minEnergy, uint maxEnergy );
std::string getSeasonStr() const;
std::string getTimeOfDayStr() const;
std::string getWeatherStr() const;
/**
* Get the ecotype zone under the position.
* This information is valid only at init time. After the deposits are built, this information
* can be found only in deposits.
* If not found, a NULL pointer is returned.
*/
static CEcotypeZone *getEcotypeZone( const NLMISC::CVector& pos );
/// auto spawn a source in the deposit, in the given bbox
void autoSpawnSource(const NLMISC::CVector &cornerMin, const NLMISC::CVector &cornerMax);
private:
/// The ecotype zones (only valid at init, cleared after deposit built)
static CEcotypeZones _EcotypeZones;
/// List of raw materials (const)
std::vector< CStaticDepositRawMaterial > _RawMaterials;
/// Type of terrain (const)
TEcotype _Ecotype;
/// Season filter (const)
std::vector _SeasonFilter;
/// Weather filter (const)
std::vector _WeatherFilter;
/// Time of day filter (const)
std::vector _TimeOfDayFilter;
/// Phase for noise value generator (deduced from season, weather, time... filters)
uint _FilterPhase;
/// Recent forage site list (per deposit, which means forage won't affect another overlapped deposit)
CRecentForageSites _RecentForageSites;
/// Deposit name
std::string _Name;
/// Not null if the deposit can spawn sources without foraging action
CAutoSpawnProperties *_AutoSpawnSourcePt;
/// From 0 to KAMI_ANGER_THRESHOLD 1 & 2, or -1 for N/A; will be persistant some day...
float _KamiAnger;
/// Min quality or -1 if there is no inferior limit
sint16 _MinQuality;
/// Max quality or -1 if it has to be taken from the raw material information
sint16 _MaxQuality;
/// Not null if the deposit has main quantity constraints
CQuantityConstraints *_QuantityConstraintsPt;
/// Index of the visual shape/FX of the sources from this deposit
uint16 _SourceFXIndex;
/// Can a player prospect on this deposit
bool _CanProspect;
/// Is this deposit enabled or disabled (for deposits that are not permanent)
bool _Enabled;
/// Is this deposit allows depletion risk. True by default
bool _AllowDepletionRisk;
// deposit id
//uint _Id;
/// Current Number of AutoSpawned Sources in this deposit
uint32 _CurrentNbAutoSpawnedSources;
};
/**
* Predicate to compare two pointed deposits using their kami anger level.
* If a value is -1, it is not considered as lower.
*/
struct CHasLowerKamiAngerPred : std::binary_function< CDeposit*, CDeposit*, bool >
{
bool operator() ( CDeposit *d1, CDeposit *d2 )
{
return (d1->kamiAnger() >= 0) && (d1->kamiAnger() < d2->kamiAnger());
}
};
/*
* Return the quantity available in the deposit (or FLT_MAX if there is no quantity constraint)
*/
inline float CRecentForageSite::getQuantityInDeposit()
{
return _Deposit->getMaxQuantity();
}
/*
* Consume 1 unit of forage site stock by a source in the (independant on the quantity extracted).
* Reset life time of forage site if successful.
* Additionally, consume n units of deposit stock (dependant on the quantity extracted).
* Return the actual quantity that is extracted (can be less that requested if the deposit is (nearly or fully) empty.
*/
inline float CRecentForageSite::consume( float n )
{
if ( _LowScopeStock != 0 )
{
--_LowScopeStock;
_TimeToLive = ForageSiteNbUpdatesToLive.get();
}
return _Deposit->consumeQuantity( n );
}
/*
* Return true if the deposit allows depletion risk
*/
inline bool CRecentForageSite::allowDepletionRisk() const
{
return _Deposit && _Deposit->allowDepletionRisk();
}
#endif // RY_DEPOSIT_H
/* End of deposit.h */