2012-05-29 13:31:11 +00:00
// 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 "harvest_source.h"
# include "deposit.h"
# include "egs_globals.h"
# include "phrase_manager/phrase_utilities_functions.h"
# include "entity_manager/entity_base.h"
# include "player_manager/player_manager.h"
# include "player_manager/player.h"
# include "player_manager/character.h"
# include "forage_progress.h"
# include "range_selector.h"
# include "egs_sheets/egs_sheets.h"
# include "nel/misc/variable.h"
# include "phrase_manager/s_effect.h"
# include "server_share/r2_vision.h"
using namespace NLMISC ;
using namespace NLNET ;
using namespace std ;
NL_INSTANCE_COUNTER_IMPL ( CHarvestSource ) ;
NL_INSTANCE_COUNTER_IMPL ( CHarvestSourceManager ) ;
NL_ISO_TEMPLATE_SPEC CSimpleEntityManager < CHarvestSource > * CSimpleEntityManager < CHarvestSource > : : _Instance = NULL ;
uint NbAutoSpawnedForageSources = 0 ;
const NLMISC : : TGameCycle MaxT = 1200 ; // 2 min for prospected sources (TODO: external data)
const float CommonRiskThreshold = 127.0f ;
const float ThresholdD1 = CommonRiskThreshold ;
const float ThresholdD2 = CommonRiskThreshold * 1.20f ;
const float ThresholdE = CommonRiskThreshold ;
const float ThresholdC = CommonRiskThreshold ;
const float DeltaMoveBarPerTick = ( DeltaMoveBarPerSec / 10.0f ) ;
const float DeltaResetBarPerTick = ( DeltaResetBarPerSec / 10.0f ) ;
sint32 ForageSourceDisplay = - 1 ;
static const NLMISC : : TGameCycle Locked = ~ 0 ;
static const NLMISC : : TGameCycle IniTime = ( ~ 0 ) - 1 ; // highest positive integer (suitable for unsigned)
// Minimum extraction session:
// 6 extractions = 24 seconds with 4 seconds per extraction
// Maximum extraction session:
// 80 extractions = 120 seconds with 1.5 second per extraction
// MaxA: 3.5
// MaxS: 1/15
// nlctassert(MaxAS>0);
const float MaxAS = ( 3.5f / 15.0f ) ;
// MaxRequiredQ: 250; InitResultQ: 1 => MaxDeltaQ: 26
// nlctassert(MaxDeltaQ>0);
const float MaxQ = 250.0f ;
const float MaxDeltaQ = 26.0f ;
// { D, E, C } impacted by (0=Qtty, 1=Qlty, 2=Both)
uint ImpactSchemes [ 6 ] [ 3 ] = { { 0 , 1 , 2 } , { 0 , 2 , 1 } , { 1 , 0 , 2 } , { 1 , 2 , 0 } , { 2 , 0 , 1 } , { 2 , 1 , 0 } } ;
// Observed impact on D (/10): 1 3 6 10 3 1
// Observed impact on E (/10): 6 3 1 1 3 10
// Note: if modifying this schemes, please change FORAGE_SOURCE_IMPACT_MODE in phrase_en.txt.
uint SpecialNewbieImpactSchemeD = 10 ;
uint16 LowDangerMappings [ 2 ] = { SpecialNewbieImpactSchemeD + 1 , SpecialNewbieImpactSchemeD + 4 } ;
sint8 ExplosionResetPeriod = 50 ; // 5 s
CHarvestSource AutoSpawnSourceIniProperties ;
/*
* Access to singleton
*/
CHarvestSourceManager * CHarvestSourceManager : : getInstance ( )
{
return ( CHarvestSourceManager * ) _Instance ;
}
/*
* Initialization of source manager
*/
void CHarvestSourceManager : : init ( TDataSetIndex baseRowIndex , TDataSetIndex size )
{
CSimpleEntityManager < CHarvestSource > : : init ( baseRowIndex , size ) ;
// Note: Now, most of these values are overridden by deposit settings (see CFgProspectionPhrase::autoSpawnSource())
AutoSpawnSourceIniProperties . setLifetime ( 6000 ) ; // 10 min
AutoSpawnSourceIniProperties . setProspectionExtraExtractionTime ( 0 ) ; // no extra time
//AutoSpawnSourceIniProperties.setDistVis( 100 );
}
void CHarvestSourceManager : : release ( )
{
delete ( CHarvestSourceManager * ) _Instance ;
}
/*
* HarvestSource constructor
*/
CHarvestSource : : CHarvestSource ( )
{
_NbExtractions = 0 ;
_ForageSite = NULL ;
_DepositForK = NULL ;
// Set default values (TODO: external data)
_LifeTime = 200 ; // 20 s
_ExtractionTime = 250 ; // 25 s for initial extraction time (now, recalculated using quality of material)
_ExtraExtractionTime = 25 ; // 2.5 s
_IncludedBonusExtractionTime = 0 ;
_T = Locked ; // until spawn is completed
_S = 0.025f ; // 4 s per delivery (initial value may be not used by the extraction action)
_A = 0.1f ;
_Q = 1.0f ;
_D = 0 ;
_E = 0 ;
_TargetRTProps [ TargetD ] = 0 ;
_TargetRTProps [ TargetE ] = 0 ;
//_C = 0;
_MaxQuality = ~ 0 ;
_IImpactMappingScheme = 0 ;
_N = 0 ;
_IsInNewbieMode = false ;
_BonusForAPct = 0 ;
//_DistanceVisibility = 80;
//_StealthVisibility = VISIBILITY_RIGHTS::All;
_IsExtractionInProgress = false ;
_ExplosionResetCounter = - 1 ;
_IsAutoSpawned = false ;
_SafeSource = false ;
_NbEventTriggered = 0 ;
}
/*
* HarvestSource destructor
*/
CHarvestSource : : ~ CHarvestSource ( )
{
// unregister the deposit auto spawn if any
setDepositAutoSpawn ( NULL ) ;
}
/*
* setDepositAutoSpawn
*/
void CHarvestSource : : setDepositAutoSpawn ( CDeposit * deposit )
{
// unregister the current deposit, if any
if ( _DepositAutoSpawn )
{
_DepositAutoSpawn - > decreaseAutoSpawnedSources ( ) ;
_DepositAutoSpawn = NULL ;
}
// register the new one if any
if ( deposit )
{
_DepositAutoSpawn = deposit ;
_DepositAutoSpawn - > increaseAutoSpawnedSources ( ) ;
}
}
/*
* Init the source . All pointers must be valid ( but forageSite may be NULL ) .
* Return false if the current quantity in the deposit is 0.
*/
bool CHarvestSource : : init ( const CHarvestSource & ini , const NLMISC : : CVector2f & pos ,
CRecentForageSite * forageSite ,
CDeposit * depositForK ,
const CStaticDepositRawMaterial * rmInfo , float quantityRatio )
{
initFrom ( ini ) ;
setPos ( pos ) ;
setForageSite ( forageSite ) ;
bool isNonEmpty = setRawMaterial ( rmInfo , quantityRatio ) ;
// Set link to deposit for kami anger level
_DepositForK = depositForK ;
return isNonEmpty ;
}
/*
* Set the raw material , the initial amount and the max quality , or return false if the current quantity in the deposit is 0.
*/
bool CHarvestSource : : setRawMaterial ( const CStaticDepositRawMaterial * rmInfo , float quantityRatio )
{
H_AUTO ( CHarvestSource_setRawMaterial ) ;
_MaterialSheet = rmInfo - > MaterialSheet ;
// Get corresponding initial quantity & max quality
const CStaticItem * staticItem = CSheets : : getForm ( _MaterialSheet ) ;
if ( staticItem & & staticItem - > Mp )
{
/// The quantity is a fraction of the 'Stackable' property (but it is limited by the constraints of the deposit)
_N = min ( max ( ( ( ( float ) staticItem - > Stackable ) * quantityRatio ) , 1.0f ) , _ForageSite - > getQuantityInDeposit ( ) ) ;
// Select either the MaxQuality in the deposit primitive or in the RM sheet (if -1 in the deposit, or no deposit)
sint16 depositMaxQuality = _ForageSite ? _ForageSite - > deposit ( ) - > maxQuality ( ) : - 1 ;
if ( depositMaxQuality ! = - 1 )
_MaxQuality = ( uint16 ) depositMaxQuality ;
else
_MaxQuality = staticItem - > Mp - > MaxQuality ;
//nldebug( "Quality limited by source to %hu", _MaxQuality );
if ( _N = = 0 )
return false ;
}
else
{
nlwarning ( " %s is not a valid raw material sheet " , _MaterialSheet . toString ( ) . c_str ( ) ) ;
return false ;
}
return true ;
}
/*
* Recalculate the remaining extraction time depending on the requested quality .
* Does nothing if the source is in " extra extraction time " .
* _ExtraExtractionTime is included in _ExtraExtractionTime .
*
* Precondition : _ExtractionTime ! = 0
*/
void CHarvestSource : : recalcExtractionTime ( float requestedQuality )
{
if ( _T > _ExtraExtractionTime )
{
nlassert ( _ExtractionTime > _ExtraExtractionTime ) ;
float timeRatio = ( ( float ) _T ) / ( ( float ) _ExtractionTime ) ;
//float fExtractionTime = requestedQuality*(0.3092f*10.0f) + (22.0f*10.0f); // Q10 -> 25 s; Q250 -> 1'40 s
float fExtractionTime = requestedQuality * ForageExtractionTimeSlopeGC . get ( ) + ForageExtractionTimeMinGC . get ( ) + ( float ) _ExtraExtractionTime ;
_ExtractionTime = ( NLMISC : : TGameCycle ) fExtractionTime ;
_T = ( NLMISC : : TGameCycle ) ( fExtractionTime * timeRatio ) ;
}
}
/*
* Prepare the source as an unpublished entity in mirror . Return false in case of failure .
* Must be called * after * init ( ) .
* prospectorDataSetRow must be either null ( isNull ( ) ) or an accessible row ( isAccessible ( ) ) .
*/
bool CHarvestSource : : spawnBegin ( uint8 knowledgePrecision , const TDataSetRow & prospectorDataSetRow , bool isAutoSpawned )
{
H_AUTO ( CHarvestSource_spawn ) ;
// Add into mirror (but unpublished)
CEntityId entityId = CEntityId : : getNewEntityId ( RYZOMID : : forageSource ) ;
if ( ! Mirror . createEntity ( entityId ) )
return false ;
_DataSetRow = TheDataset . getDataSetRow ( entityId ) ;
_IsAutoSpawned = isAutoSpawned ;
// Set the sheet id (including knowledge information)
uint sourceFXIndex = _ForageSite ? ( uint ) _ForageSite - > deposit ( ) - > sourceFXIndex ( ) : 0 ;
CMirrorPropValue < TYPE_SHEET > sheet ( TheDataset , _DataSetRow , DSPropertySHEET ) ;
sheet = CSheetId ( toString ( " %u_%u.forage_source " , sourceFXIndex , knowledgePrecision ) ) . asInt ( ) ;
// For knowledge 3, fit the sheet id of the RM sitem into NAME_STRING_ID (instead of a string id) !
CMirrorPropValue < TYPE_NAME_STRING_ID > nameId ( TheDataset , _DataSetRow , DSPropertyNAME_STRING_ID ) ;
nameId = ( knowledgePrecision = = 3 ) ? _MaterialSheet . asInt ( ) : 0 ;
if ( knowledgePrecision ! = 0 )
{
const CStaticItem * staticItem = CSheets : : getForm ( materialSheet ( ) ) ;
if ( staticItem & & staticItem - > Mp )
{
// Set additional knowledge info into VISUAL_FX
CMirrorPropValue < TYPE_VISUAL_FX > visualFx ( TheDataset , _DataSetRow , DSPropertyVISUAL_FX ) ;
switch ( knowledgePrecision )
{
case 1 : visualFx = ( TYPE_VISUAL_FX ) staticItem - > Mp - > getGroup ( ) ; break ; // initializes the prop, but only 10 bits allowed
case 2 : // family sent for 2 & 3 (for knowledge 3, used only as icon index)
case 3 : visualFx = ( TYPE_VISUAL_FX ) staticItem - > Mp - > Family ; break ; // initializes the prop, but only 10 bits allowed
default : ; // default value is 0
}
if ( ( visualFx ( ) & 0x400 ) ! = 0 )
{
nlwarning ( " FG: Family or group index exceeding max! " ) ; // bit 10 is reserved for explosion FX
visualFx = 0 ;
}
}
}
// Set the target (the prospector, or a nul datasetrow if auto-spawned)
CMirrorPropValue < TYPE_TARGET_ID > targetRow ( TheDataset , _DataSetRow , DSPropertyTARGET_ID ) ;
targetRow = prospectorDataSetRow ;
// Add to manager so that update() will be called at each game cycle
CHarvestSourceManager : : getInstance ( ) - > addEntity ( this ) ; // we don't do it in spawnEnd(), because the source would remain unpublished forever if the AIS quit before replying to the transport class message
return true ;
}
/*
* Complete the source spawn : publish the entity in mirror or delete it .
* Caution : if authorized , the source object is deleted !
*/
void CHarvestSource : : spawnEnd ( bool authorized )
{
if ( ! authorized )
{
despawn ( ) ;
CHarvestSourceManager : : getInstance ( ) - > destroyEntity ( _DataSetRow ) ;
return ;
}
// Unlock update
_ExtractionTime = IniTime ; // will trigger calculation in recalcExtractionTime() because _T > _ExtraExtractionTime
_T = _ExtractionTime ; // ratio 1.0 => beginning of extraction time
if ( _IsAutoSpawned )
+ + NbAutoSpawnedForageSources ;
// Set the initial position
CMirrorPropValue < TYPE_POSX > posX ( TheDataset , _DataSetRow , DSPropertyPOSX ) ;
CMirrorPropValue < TYPE_POSY > posY ( TheDataset , _DataSetRow , DSPropertyPOSY ) ;
posX = ( TYPE_POSX ) ( _Pos . x * 1000.0f ) ;
posY = ( TYPE_POSY ) ( _Pos . y * 1000.0f ) ;
// Set the WhoSeesMe bitfield (distance of visibility by players (0-31) and creatures (32-63)) (now constant)
uint32 nbBitsOn = /*_DistanceVisibility*/ 80 * 32 / 250 ; // (250 m is the max, corresponding to 32 bits on
const uint64 distanceBitfield = IsRingShard ? R2_VISION : : buildWhoSeesMe ( R2_VISION : : WHOSEESME_VISIBLE_MOB , false ) : ( ( uint64 ) 1 < < ( uint64 ) nbBitsOn ) - 1 ; // (hide to creatures)
CMirrorPropValue < TYPE_WHO_SEES_ME > whoSeesMe ( TheDataset , _DataSetRow , DSPropertyWHO_SEES_ME ) ;
whoSeesMe = distanceBitfield ;
// Set selectable property to true
CMirrorPropValue < TYPE_CONTEXTUAL > contextualProperties ( TheDataset , _DataSetRow , DSPropertyCONTEXTUAL ) ;
CProperties prop ( 0 ) ;
prop . selectable ( true ) ;
contextualProperties = prop ;
// Update bars and other variable properties
updateVisuals ( ) ;
// Publish in mirror
TheDataset . declareEntity ( _DataSetRow ) ;
}
/*
* Return the prospector or a null datasetrow if there was no prospection ( auto - spawn )
* The accessibility of this datasetrow must be checked before use .
*/
const TDataSetRow & CHarvestSource : : getProspectorDataSetRow ( ) const
{
CMirrorPropValueRO < TYPE_TARGET_ID > targetRow ( TheDataset , _DataSetRow , DSPropertyTARGET_ID ) ;
return targetRow ( ) ;
}
/*
* Despawn the source in mirror , and exit from forage site
*/
void CHarvestSource : : despawn ( )
{
H_AUTO ( CHarvestSource_despawn ) ;
// Remove from mirror
CEntityId entityId = TheDataset . getEntityId ( _DataSetRow ) ;
Mirror . removeEntity ( entityId ) ;
//nldebug( "--- %p from %p", this, _ForageSite );
// Exit from forage site (the entering is done outside class, because a failure may prevent to create the source)
if ( _ForageSite )
_ForageSite - > removeActiveSource ( ) ;
if ( _IsAutoSpawned )
- - NbAutoSpawnedForageSources ;
// End forage sessions and calculate XP and give result
if ( ! _Foragers . empty ( ) )
{
// The first forager is the only one who can extract. Give result & dispatch XP
CForagers : : const_iterator it = _Foragers . begin ( ) ;
CCharacter * player = PlayerManager . getChar ( * it ) ;
if ( player & & player - > forageProgress ( ) )
{
if ( player - > forageProgress ( ) - > sourceRowId ( ) = = _DataSetRow ) // check if he has not changed his target
{
player - > giveForageSessionResult ( this ) ;
}
}
// End sessions of care takers (all excluding the first element)
for ( + + it ; it ! = _Foragers . end ( ) ; + + it )
{
player = PlayerManager . getChar ( * it ) ;
if ( player & & player - > forageProgress ( ) )
{
if ( player - > forageProgress ( ) - > sourceRowId ( ) = = _DataSetRow ) // check if he has not changed his target
{
player - > endForageSession ( ) ;
}
}
}
}
}
/*
* Helper for updateVisiblePostPos ( )
*/
inline void updateBarValueAtTick ( float & destValue , float & currentValue )
{
float diff = destValue - currentValue ;
if ( diff > 0 )
{
currentValue = std : : min ( destValue , currentValue + DeltaMoveBarPerTick ) ;
}
else if ( diff < 0 )
{
float delta = ( currentValue = = 0 ) ? DeltaResetBarPerTick : DeltaMoveBarPerTick ;
currentValue = std : : max ( destValue , currentValue - delta ) ;
}
}
/*
* Update
*/
bool CHarvestSource : : update ( )
{
H_AUTO ( CHarvestSource_update ) ;
if ( _IsExtractionInProgress )
{
// Make the bar transitions smooth (needs to be done on server to match timing on client)
updateBarValueAtTick ( _TargetRTProps [ TargetD ] , _D ) ;
updateBarValueAtTick ( _TargetRTProps [ TargetE ] , _E ) ;
// Test damaging event risk
if ( _E > ThresholdE )
{
makeDamagingEvent ( ) ;
setEventTriggered ( ) ;
impactRTProp ( TargetE , 0 ) ;
}
// Test spawn risk
/*if ( _C > ThresholdC )
{
//sendMessageToExtractors( "CREATURE_SPAWN" );
// TODO
//setEventTriggered();
_C = 0 ;
} */
// Test depletion risk (if the bar transition is still in progress, wait)
if ( ( _D > ThresholdD1 ) )
{
// if high risk value, deplete all the forage site (if exist and allow depletion)
if ( _ForageSite & & _ForageSite - > allowDepletionRisk ( ) & & _TargetRTProps [ TargetD ] > ThresholdD2 )
{
sendMessageToExtractors ( " FORAGE_SOURCE_SITE_DEPLETED " ) ;
_ForageSite - > depleteAll ( ) ;
}
// else will just kill the current source (send appropriate message)
else
sendMessageToExtractors ( " FORAGE_SOURCE_DEPLETED " ) ;
// in all case kill the current source, and add bad event
setEventTriggered ( ) ;
despawn ( ) ;
return false ;
}
// Test remaining time
else if ( _T = = 0 )
{
despawn ( ) ;
return false ;
}
else
{
- - _T ;
float naturalMoveThreshold = CommonRiskThreshold - 2.0f ;
if ( _TargetRTProps [ TargetD ] + ForageExtractionNaturalDDeltaPerTick . get ( ) < naturalMoveThreshold ) // don't auto-move if it makes it trigger the event
impactRTProp ( TargetD , _TargetRTProps [ TargetD ] + ForageExtractionNaturalDDeltaPerTick . get ( ) ) ;
if ( ! _SafeSource )
{
if ( _TargetRTProps [ TargetE ] + ForageExtractionNaturalEDeltaPerTick . get ( ) < naturalMoveThreshold )
impactRTProp ( TargetE , _TargetRTProps [ TargetE ] + ForageExtractionNaturalEDeltaPerTick . get ( ) ) ;
}
if ( _DataSetRow . getIndex ( ) = = ( TDataSetIndex ) ForageSourceDisplay )
nldebug ( " T: %u " , _T ) ;
updateVisuals ( ) ;
return true ;
}
}
else
{
// Remain locked if the source is not fully spanwed yet
if ( _T = = Locked )
return true ;
// Test end of lifetime
if ( _LifeTime = = 0 )
{
despawn ( ) ;
return false ;
}
else
{
- - _LifeTime ;
if ( _DataSetRow . getIndex ( ) = = ( TDataSetIndex ) ForageSourceDisplay )
nldebug ( " _LifeTime: %u " , _LifeTime ) ;
return true ;
}
}
}
/*
* Update visual properties & related stuff
*/
void CHarvestSource : : updateVisuals ( )
{
H_AUTO ( CHarvestSource_updateVisuals ) ;
// Set the bars on the entity
TYPE_BARS statusBar ;
float d = ( _TargetRTProps [ TargetD ] > ForageCareBeginZone . get ( ) ) ? _TargetRTProps [ TargetD ] : 0 ;
if ( d > CommonRiskThreshold )
d = CommonRiskThreshold ;
float e = ( _TargetRTProps [ TargetE ] > ForageCareBeginZone . get ( ) ) ? _TargetRTProps [ TargetE ] : 0 ;
if ( e > CommonRiskThreshold )
e = CommonRiskThreshold ;
statusBar = ( _T = = IniTime ) ? 127 : uint32 ( ( _T * 127 / _ExtractionTime / 2 ) * 2 ) ; // time progression (round off to 2 to reduce flooding by 30% (taking D & E into account))
if ( _N ! = 0 )
statusBar = statusBar | ( ( uint32 ( _N ) + 1 ) < < 7 ) ; // round off to next integer (TODO: ratio qtty/initial_qtty)
statusBar = statusBar | ( uint32 ( ( 127.0f - d ) /**127.0f*/ ) < < 14 ) ;
if ( ! _SafeSource ) // If source is safe let 0 (client will display it full and with a special color)
statusBar = statusBar | ( uint32 ( ( 127.0f - e ) /**127.0f*/ ) < < 21 ) ;
statusBar = statusBar | ( ( ( uint32 ) ( _IsExtractionInProgress ) ) < < 28 ) ;
//statusBar = statusBar | (uint32(_C/**127.0f*/) << 28);
CMirrorPropValue < TYPE_BARS > statusBarProp ( TheDataset , _DataSetRow , DSPropertyBARS ) ;
statusBarProp = statusBar ;
/*if ( (_N < 0) || (_N > 127) )
nlwarning ( " FG: N = %g " , _N ) ;
if ( ( _D < 0 ) | | ( _D > 127 ) )
nlwarning ( " FG: N = %g " , _D ) ;
if ( ( _E < 0 ) | | ( _E > 127 ) )
nlwarning ( " FG: N = %g " , _E ) ; */
// Set kami angry level information & extra time state (store in orientation!)
float angryLevel7 = 127.0f - ( 127.0f * _DepositForK - > kamiAnger ( ) / ForageKamiAngerThreshold2 . get ( ) ) ;
uint extraTime7 = _ExtraExtractionTime * 127 / _ExtractionTime ;
uint inclBonusExtraTime7 = _IncludedBonusExtractionTime * 127 / _ExtractionTime ;
CMirrorPropValue < TYPE_ORIENTATION > angryLevelExtraTimeProp ( TheDataset , _DataSetRow , DSPropertyORIENTATION ) ;
TYPE_ORIENTATION angryLevelExtraTimePropV = angryLevel7 ;
if ( _IsExtractionInProgress )
angryLevelExtraTimePropV + = ( ( ( ( float ) inclBonusExtraTime7 ) * 128.0f + ( float ) extraTime7 ) * 128.0f ) ;
angryLevelExtraTimeProp = angryLevelExtraTimePropV ; // stored as float, should be converted to 21b uint by FS
// Reset explosion visual fx if needed
if ( _ExplosionResetCounter = = 0 )
{
CMirrorPropValue < TYPE_VISUAL_FX > visualFx ( TheDataset , _DataSetRow , DSPropertyVISUAL_FX ) ;
visualFx = ( visualFx ( ) & 0x3FF ) ; // unset bit 10
_ExplosionResetCounter = - 1 ;
}
else if ( _ExplosionResetCounter > 0 )
{
- - _ExplosionResetCounter ;
}
}
/*
*
*/
void CHarvestSource : : sendMessageToExtractors ( const char * msg )
{
H_AUTO ( CHarvestSource_sendMessageToExtractors ) ;
CForagers : : const_iterator it ;
for ( it = _Foragers . begin ( ) ; it ! = _Foragers . end ( ) ; + + it )
{
const TDataSetRow & extRowId = ( * it ) ;
PHRASE_UTILITIES : : sendDynamicSystemMessage ( extRowId , msg ) ;
}
}
/*
*
*/
void CHarvestSource : : sendMessageToExtractors ( const char * msg , sint32 param )
{
H_AUTO ( CHarvestSource_sendMessageToExtractors ) ;
CForagers : : const_iterator it ;
for ( it = _Foragers . begin ( ) ; it ! = _Foragers . end ( ) ; + + it )
{
const TDataSetRow & extRowId = ( * it ) ;
SM_STATIC_PARAMS_1 ( params , STRING_MANAGER : : integer ) ;
params [ 0 ] . Int = param ;
PHRASE_UTILITIES : : sendDynamicSystemMessage ( extRowId , msg , params ) ;
}
}
CVariable < sint32 > ForageForceImpactScheme ( " egs " , " ForageForceImpactScheme " , " " , - 1 ) ;
/*
* Begin an extraction action . Once the extraction process is started , the source remains in
* extraction mode until the extraction time is elapsed ( even if players stop / restart
* extracting ) .
* Return true if the forager is the extractor ( the first one on the source )
*/
bool CHarvestSource : : beginExtraction ( const TDataSetRow & forager , bool isNewbie )
{
H_AUTO ( CHarvestSource_beginExtraction ) ;
bool foragerIsFirstExtractor = false ;
if ( ! _IsExtractionInProgress )
{
_IsExtractionInProgress = true ;
foragerIsFirstExtractor = true ;
_IsInNewbieMode = isNewbie ; // only the first one sets the mode
// Tell him the max quality
SM_STATIC_PARAMS_1 ( params , STRING_MANAGER : : integer ) ;
params [ 0 ] . Int = ( sint32 ) _MaxQuality ;
PHRASE_UTILITIES : : sendDynamicSystemMessage ( forager , " FORAGE_SOURCE_MAXLEVEL " , params ) ;
// Set the impact scheme
setNewImpactScheme ( ) ; // at this time, _Foragers is empty so nobody is told yet
}
// Add player to extractor to list (if new)
CForagers : : iterator it = find ( _Foragers . begin ( ) , _Foragers . end ( ) , forager ) ;
if ( it = = _Foragers . end ( ) )
{
_Foragers . push_back ( forager ) ;
// Tell him the impact mode
SM_STATIC_PARAMS_1 ( params , STRING_MANAGER : : integer ) ;
params [ 0 ] . Int = ( sint32 ) _IImpactMappingScheme ;
PHRASE_UTILITIES : : sendDynamicSystemMessage ( forager , " FORAGE_SOURCE_IMPACT_MODE " , params ) ;
}
else if ( it = = _Foragers . begin ( ) )
{
foragerIsFirstExtractor = true ;
}
return foragerIsFirstExtractor ;
}
/*
* Set a new mapping scheme of property impact
*/
void CHarvestSource : : setNewImpactScheme ( )
{
H_AUTO ( CHarvestSource_setNewImpactScheme ) ;
// Set mapping scheme of property impact
if ( _IsInNewbieMode )
{
// Force "low dangers" for 1 newbie extractor
_IImpactMappingScheme = ( uint16 ) LowDangerMappings [ RandomGenerator . rand ( 1 ) ] ;
}
else
{
// Normal dangers
if ( ForageForceImpactScheme . get ( ) = = - 1 )
_IImpactMappingScheme = ( uint16 ) RandomGenerator . rand ( 5 ) ;
else
_IImpactMappingScheme = ( uint16 ) ForageForceImpactScheme . get ( ) ;
}
sendMessageToExtractors ( " FORAGE_SOURCE_IMPACT_MODE " , ( sint32 ) _IImpactMappingScheme ) ;
# ifdef NL_DEBUG
nldebug ( " FG: map scheme: %u " , _IImpactMappingScheme ) ;
# endif
}
bool ForceDropProp = false ;
NLMISC_VARIABLE ( bool , ForceDropProp , " " ) ;
CVariable < float > ForceAbsorption ( " egs " , " ForceAbsorption " , " " , 0 ) ;
/*
* Update the source state with an extraction ( see doc in . h ) .
*/
void CHarvestSource : : extractMaterial ( float * reqPosProps , float * absPosProps , float qualityCeilingFactor , float qualitySlowFactor , float * results , float successFactor , uint8 lifeAbsorberRatio , const TDataSetRow & extractingEntityRow , CHarvestSource : : TRealTimeProp & propDrop )
{
H_AUTO ( CHarvestSource_extractMaterial ) ;
CCharacter * player = PlayerManager . getChar ( extractingEntityRow ) ;
+ + _NbExtractions ; // it's 1 at the first call, so that the initial value is used
float nbe = ( float ) _NbExtractions ;
if ( ( successFactor < 0.1f ) | | ForceDropProp )
{
if ( _NbExtractions < 6 )
propDrop = Q ; // don't drop A at the beginning (wait to reach 1 (cumulated) would be better)
else
propDrop = ( TRealTimeProp ) ( RandomGenerator . rand ( 1 ) + 1 ) ;
nldebug ( " Prop drop %u " , propDrop ) ;
}
// Aperture: converges towards the requested value, except when a drop occurs (0 at this step)
// if ( reqPosProps[A] > 0 )
{
float obtainedQuantity = ( propDrop = = A ) ? 0.0f : ( results [ A ] * ForageQuantitySlowFactor . get ( ) + reqPosProps [ A ] ) / ( ForageQuantitySlowFactor . get ( ) + 1 ) ;
// Apply possible aperture bonus
if ( _BonusForAPct ! = 0 )
{
obtainedQuantity + = obtainedQuantity * ( float ) ( ( uint ) _BonusForAPct ) * 0.01f ;
}
// Extract material
if ( _ForageSite )
obtainedQuantity = _ForageSite - > consume ( obtainedQuantity ) ; // consume (and limit) in forage site & deposit
if ( obtainedQuantity > _N ) // should not occur because _N uses the deposit quantity
obtainedQuantity = _N ;
_N - = obtainedQuantity ;
_A = ( _A * nbe + obtainedQuantity ) / ( nbe + 1.0f ) ; // average per source
_DepositForK - > incKamiAnger ( obtainedQuantity , _Foragers ) ;
if ( ( obtainedQuantity = = 0 ) & & ( results [ A ] ! = 0 ) & & ( ! ( propDrop = = A ) ) )
PHRASE_UTILITIES : : sendDynamicSystemMessage ( _Foragers [ 0 ] , " FORAGE_DEPOSIT_IS_EMPTY " ) ;
results [ A ] = obtainedQuantity ;
// add spire effect ( quantity )
if ( player )
{
const CSEffect * pEffect = player - > lookForActiveEffect ( EFFECT_FAMILIES : : TotemHarvestQty ) ;
if ( pEffect ! = NULL )
{
results [ A ] * = ( 1.0f + pEffect - > getParamValue ( ) / 100.0f ) ;
}
}
// add item special effect
if ( player )
{
std : : vector < SItemSpecialEffect > effects = player - > lookForSpecialItemEffects ( ITEM_SPECIAL_EFFECT : : ISE_FORAGE_ADD_RM ) ;
std : : vector < SItemSpecialEffect > : : const_iterator it , itEnd ;
double addedQty = 0. ;
for ( it = effects . begin ( ) , itEnd = effects . end ( ) ; it ! = itEnd ; + + it )
{
float rnd = RandomGenerator . frand ( ) ;
if ( rnd < it - > EffectArgFloat [ 0 ] )
{
addedQty + = it - > EffectArgFloat [ 1 ] ;
PHRASE_UTILITIES : : sendItemSpecialEffectProcMessage ( ITEM_SPECIAL_EFFECT : : ISE_FORAGE_ADD_RM , player , NULL , ( sint32 ) ( it - > EffectArgFloat [ 1 ] * 100. ) ) ;
}
}
results [ A ] * = 1.0f + ( float ) addedQty ;
}
}
// else
// {
// results[A] = 0;
// }
// Speed: always the requested speed (otherwise, looks like a bug for the player when it's the speed of the action)
results [ S ] = reqPosProps [ S ] ;
_S = ( _S * nbe + results [ S ] ) / ( nbe + 1.0f ) ; // average per source
// Quality: converges towards the requested value, except when a drop occurs (0 at this step)
float usedReqQ = ( propDrop = = Q ) ? 0.0f : reqPosProps [ Q ] * qualityCeilingFactor ;
float resQ = ( results [ Q ] * qualitySlowFactor + usedReqQ ) / ( qualitySlowFactor + 1 ) ;
float maxQOfSource = ( float ) _MaxQuality ;
if ( resQ > maxQOfSource )
{
resQ = maxQOfSource ;
//if ( results[Q] < (float)_MaxQuality )
// nldebug( "Quality limited by source to %hu", _MaxQuality ); // TODO: tell the player(s)
}
if ( ( resQ < _Q ) | | ( resQ < reqPosProps [ Q ] ) | | ( ! ForageQualityCeilingClamp . get ( ) ) )
{
// Set Q only if not increasing and exceeding requested quality
results [ Q ] = resQ ;
}
else
{
// Clamp Q to the max required by the player
results [ Q ] = reqPosProps [ Q ] ;
}
float prevQ = _Q ;
_Q = results [ Q ] ; // now there is only one extractor => the Q of the source is the resulting Q
if ( ( ( prevQ < reqPosProps [ Q ] ) & & ( _Q = = reqPosProps [ Q ] ) ) | | ( ( prevQ < maxQOfSource ) & & ( _Q = = maxQOfSource ) ) )
{
setNewImpactScheme ( ) ; // we just reached the max quality
}
// Calc impact of the new average values
// Previously, the impact depended on the level of the extraction:
// float quantityBaseImpact = _A * _S * ForageQuantityImpactFactor.get();
// float qualityBaseImpact = (_Q - oldQ) * ForageQualityImpactFactor.get();
//
// Now it's constant (=max), but the amount of damage depends on the level of the extraction:
float quantityBaseImpact = MaxAS * ForageQuantityImpactFactor . get ( ) ;
float qualityBaseImpact = MaxDeltaQ * ForageQualityImpactFactor . get ( ) ;
uint impactScheme = _IImpactMappingScheme ;
if ( impactScheme > = SpecialNewbieImpactSchemeD )
{
// Lower impacts for newbies
impactScheme - = SpecialNewbieImpactSchemeD ;
quantityBaseImpact * = 0.5f ;
qualityBaseImpact * = 0.5f ;
}
if ( ForceAbsorption . get ( ) ! = 0 )
{
absPosProps [ A ] = ForceAbsorption . get ( ) ;
absPosProps [ Q ] = ForceAbsorption . get ( ) ;
absPosProps [ S ] = ForceAbsorption . get ( ) ;
}
for ( uint i = D ; i ! = NbRTProps ; + + i )
{
if ( i = = E & & _SafeSource )
break ;
uint impactType = ImpactSchemes [ impactScheme ] [ i - NbPosRTProps ] ;
float impact ;
switch ( impactType )
{
case 0 : impact = quantityBaseImpact * ( 1.0f - absPosProps [ A ] ) ; break ;
case 1 : impact = qualityBaseImpact * ( 1.0f - absPosProps [ Q ] ) ; break ;
default : impact = ( quantityBaseImpact + qualityBaseImpact ) / 2.0f * ( 1.0f - absPosProps [ S ] ) ; break ; // bound on the average of both, absorption of S
}
impact + = RandomGenerator . frandPlusMinus ( impact ) ; // result impact from 0 to impact*2
// add spire effect ( aggressivity )
if ( player )
{
const CSEffect * pEffect = player - > lookForActiveEffect ( EFFECT_FAMILIES : : TotemHarvestAgg ) ;
if ( pEffect ! = NULL )
{
impact * = ( 1.0f - pEffect - > getParamValue ( ) / 100.0f ) ;
}
}
if ( impact < 0 ) impact = 0 ; // impact can't be negative
if ( ( i = = D ) & & ( lifeAbsorberRatio ! = 0 ) )
{
// Damage the life absorber, instead of impacting D
CEntityBase * entity = CEntityBaseManager : : getEntityBasePtr ( extractingEntityRow ) ; // getEntityBasePtr() tests TheDataset.isAccessible( extractingEntity )
if ( entity )
{
float impactOnHP = ( ( float ) lifeAbsorberRatio ) * impact * 0.01f ;
impact - = impactOnHP ;
float dmgRatio = impactOnHP * ForageHPRatioPerSourceLifeImpact . get ( ) ;
sint32 dmg = ( sint32 ) ( ( float ) entity - > maxHp ( ) * dmgRatio ) ;
if ( dmg ! = 0 )
CHarvestSource : : hitEntity ( RYZOMID : : forageSource , entity , dmg , dmg , true ) ;
}
}
if ( ( _TargetRTProps [ i - D ] < CommonRiskThreshold * 0.90f ) & & ( _TargetRTProps [ i - D ] + impact > CommonRiskThreshold ) )
{
// Avoid a brutal unnatural end, make a step just before reaching threshold
impactRTProp ( ( TTargetRTProp ) ( i - D ) , CommonRiskThreshold - 2.0f ) ;
}
else
{
// Normal impact
impactRTProp ( ( TTargetRTProp ) ( i - D ) , _TargetRTProps [ i - D ] + impact ) ;
}
}
}
/*
* Update the source state with a care ( see doc in . h )
*/
void CHarvestSource : : takeCare ( float * deltas , bool * isUseful )
{
H_AUTO ( CHarvestSource_takeCare ) ;
// Do not count care if from the "begin zone"
if ( _TargetRTProps [ TargetD ] > ForageCareBeginZone . get ( ) )
* isUseful = true ;
if ( _TargetRTProps [ TargetE ] > ForageCareBeginZone . get ( ) )
* isUseful = true ;
//if ( deltas[DeltaD] > ForageCareBeginZone.get() )
// *isUseful = true;
// Calc actual deltas
deltas [ DeltaD ] + = RandomGenerator . frandPlusMinus ( deltas [ DeltaD ] * 0.05f ) ;
deltas [ DeltaE ] + = RandomGenerator . frandPlusMinus ( deltas [ DeltaE ] * 0.05f ) ;
//deltas[DeltaC] += RandomGenerator.frandPlusMinus( deltas[DeltaC]*0.05f );
// TODO: impact on S,A,Q
// Apply deltas
float targetValue = _TargetRTProps [ TargetD ] - ( deltas [ DeltaD ] * ForageCareFactor . get ( ) ) ;
if ( targetValue < 0 )
targetValue = 0 ;
impactRTProp ( TargetD , targetValue ) ;
if ( ! _SafeSource )
{
targetValue = _TargetRTProps [ TargetE ] - ( deltas [ DeltaE ] * ForageCareFactor . get ( ) ) ;
if ( targetValue < 0 )
targetValue = 0 ;
impactRTProp ( TargetE , targetValue ) ;
}
//_C -= (deltas[DeltaC] * ForageCareFactor.get());
//if ( _C < 0 ) _C = 0;
}
/*
* When the threshold of E is reached .
*/
void CHarvestSource : : makeDamagingEvent ( )
{
H_AUTO ( CHarvestSource_makeDamagingEvent ) ;
sint32 r = RandomGenerator . rand ( 1 ) ;
if ( r = = 0 )
{
spawnToxicCloud ( ) ;
}
else
{
explode ( ) ;
}
_Events . clear ( ) ;
setNewImpactScheme ( ) ;
}
/*
*
*/
class CForageDamagingEventRangeSelector : public CRangeSelector
{
public :
void buildTargetList ( sint32 x , sint32 y , float radius /*, float minFactor*/ )
{
H_AUTO ( CForageDamagingEventRangeSelector_buildTargetList ) ;
buildDisc ( 0 , x , y , radius , EntityMatrix , true ) ;
}
float getFactor ( uint entityIdx )
{
return 1.0f ; // every entity in the radius gets the same damage, not depending of his location
} // improvement note: for explosion, could be decreasing with the distance
} ;
/*
* A continuous damaging event
*/
void CHarvestSource : : spawnToxicCloud ( )
{
H_AUTO ( CHarvestSource_spawnToxicCloud ) ;
sendMessageToExtractors ( " SOURCE_TOXIC_CLOUD " ) ;
// Get random cloud params near the source (TODO: Z)
float dmgFactor = getDamageFactor ( ) ;
sint32 iRadius = min ( ( sint32 ) 2 , ( sint32 ) ( dmgFactor * 3.0f ) ) ; // => mapping [0..1] to {0, 1, 2}
float Radiuses [ 3 ] = { 1.5f , 3.0f , 5.0f } ; // corresponding to the 3 sheets
float radius = Radiuses [ iRadius ] ;
CVector cloudPos ( _Pos . x , _Pos . y , 0.0f ) ;
if ( iRadius ! = 0 )
{
// For a big toxic cloud, shift the centre in a axis-aligned square of 4 m width (max dist = 2.8 m)
const float MaxAxisDistFromSource = 2.0f ;
float dX = RandomGenerator . frand ( MaxAxisDistFromSource * 2.0f ) ;
float dY = RandomGenerator . frand ( MaxAxisDistFromSource * 2.0f ) ;
cloudPos . x + = dX - MaxAxisDistFromSource ;
cloudPos . y + = dY - MaxAxisDistFromSource ;
}
// Spawn the toxic cloud
CToxicCloud * tc = new CToxicCloud ( ) ;
tc - > init ( cloudPos , radius , ( sint32 ) ( dmgFactor * ToxicCloudDamage . get ( ) ) , ToxicCloudUpdateFrequency ) ;
CSheetId sheet ( toString ( " toxic_cloud_%d.fx " , iRadius ) ) ;
if ( tc - > spawn ( sheet ) )
{
CEnvironmentalEffectManager : : getInstance ( ) - > addEntity ( tc ) ;
# ifdef NL_DEBUG
nldebug ( " FG: Toxic cloud spawned (radius %g) " , radius ) ;
# endif
}
else
{
nlwarning ( " FG: Unable to spawn toxic cloud (mirror range full?) " ) ;
delete tc ;
}
}
/*
* Test which entities to hit ( all entities except NPC and non - pets creatures )
*/
inline bool isAffectedByForageDamage ( CEntityBase * entity )
{
uint8 entityType = entity - > getId ( ) . getType ( ) ;
return ! ( ( entityType = = RYZOMID : : npc ) | |
( ( entityType = = RYZOMID : : creature ) & &
( entity - > getRace ( ) ! = EGSPD : : CPeople : : MektoubMount ) & &
( entity - > getRace ( ) ! = EGSPD : : CPeople : : MektoubPacker ) ) ) ;
}
/*
* A one - time damaging event
*/
void CHarvestSource : : explode ( )
{
H_AUTO ( CHarvestSource_explode ) ;
sendMessageToExtractors ( " SOURCE_EXPLOSION " ) ;
// Set the FX
CMirrorPropValue < TYPE_VISUAL_FX > visualFx ( TheDataset , _DataSetRow , DSPropertyVISUAL_FX ) ;
visualFx = ( visualFx ( ) | 0x400 ) ; // set bit 10
_ExplosionResetCounter = ExplosionResetPeriod ;
// Get entities around the source, and hit them
if ( HarvestAreaEffectOn )
{
// Calculate damage
float fDmg = getDamageFactor ( ) * ForageExplosionDamage . get ( ) ;
float dmgAvoided = fDmg ;
for ( CRDEvents : : const_iterator iev = _Events . begin ( ) ; iev ! = _Events . end ( ) ; + + iev )
{
const CReduceDamageEvent & event = ( * iev ) ;
if ( CTickEventHandler : : getGameCycle ( ) - event . Time < ForageReduceDamageTimeWindow . get ( ) )
{
//nldebug( "Damage %.1f x %.1f", fDmg, event.Ratio );
fDmg * = event . Ratio ; // multiple events are multiplied (e.g. 50% and 50% again do 25%)
}
}
dmgAvoided = dmgAvoided - fDmg ;
bool wereAllEventsMissed = ( ! _Events . empty ( ) ) & & ( dmgAvoided = = 0 ) ;
// Make area of effect
const float explosionRadius = 4.0f ;
CForageDamagingEventRangeSelector targetSelector ;
targetSelector . buildTargetList ( ( sint32 ) ( _Pos . x * 1000.0f ) , ( sint32 ) ( _Pos . y * 1000.0f ) , explosionRadius ) ;
const vector < CEntityBase * > & targets = targetSelector . getEntities ( ) ;
for ( vector < CEntityBase * > : : const_iterator it = targets . begin ( ) ; it ! = targets . end ( ) ; + + it )
{
CEntityBase * entity = ( * it ) ;
if ( entity & & isAffectedByForageDamage ( entity ) )
{
sint32 dmg = ( sint32 ) ( entity - > getActualDamageFromExplosionWithArmor ( fDmg ) ) ;
CHarvestSource : : hitEntity ( RYZOMID : : forageSource , entity , dmg , ( sint32 ) ( fDmg + dmgAvoided ) , false , ( sint32 ) dmgAvoided ) ; // is not blocked by any armor
if ( wereAllEventsMissed & & ( entity - > getId ( ) . getType ( ) = = RYZOMID : : player ) )
{
PHRASE_UTILITIES : : sendDynamicSystemMessage ( entity - > getEntityRowId ( ) , " SOURCE_DMG_REDUX_MISSED " ) ;
}
}
}
}
}
/*
* Reduce the damage of the next blowing up ( if it is in near time delta )
*/
void CHarvestSource : : reduceBlowingUpDmg ( float ratio )
{
H_AUTO ( CHarvestSource_reduceBlowingUpDmg ) ;
CReduceDamageEvent event ;
event . Time = CTickEventHandler : : getGameCycle ( ) ;
event . Ratio = ratio ;
_Events . push_back ( event ) ;
}
/*
* Get the damage factor of a source ( for explosion or toxic cloud )
*/
float CHarvestSource : : getDamageFactor ( ) const
{
H_AUTO ( CHarvestSource_getDamageFactor ) ;
// Map linearly using 5 -> 0.5, 80 -> 1.0 (to match previous algorithm)
float statQualityFactor = ( ( ( ( float ) getStatQuality ( ) ) + 70.0f ) / 150.0f ) ;
switch ( ImpactSchemes [ _IImpactMappingScheme ] [ E ] )
{
case 0 : return _A * _S * statQualityFactor / MaxAS ; break ;
case 1 : return _Q * statQualityFactor / MaxQ ; break ; // not using DeltaQ but Q
default : return ( _A * _S / MaxAS + _Q / MaxQ ) * statQualityFactor / 2 ; break ;
}
}
/*
* Return the stat quality of the raw material
*/
/*CHarvestSource::TStatClassForage CHarvestSource::getStatQuality() const
{
H_AUTO ( CHarvestSource_getStatQuality ) ;
const CStaticItem * itemInfo = CSheets : : getForm ( _MaterialSheet ) ;
if ( itemInfo & & itemInfo - > Mp )
{
// (0..20 - 1) / 20 = 0
// (21..40 - 1) / 20 = 1
// (41..51 - 1) / 20 = 2;
// (52..59) / 20 = 2
// (61..79) / 20 = 3
// (80..99) / 20 = 4
// (100...) -> 4
sint16 statEnergy = ( sint16 ) ( itemInfo - > Mp - > StatEnergy ) ;
TStatClassForage sq =
( statEnergy < 51 ) ? ( statEnergy - 1 ) / 20 :
( ( statEnergy < 100 ) ? statEnergy / 20 : SupremeMagnificient ) ;
return sq ;
}
nlwarning ( " Invalid raw material %s " , _MaterialSheet . toString ( ) . c_str ( ) ) ;
return BasicPlainAverage ;
} */
/*
* Return the stat quality of the raw material [ 0. .100 ]
* ( Frequent values : 20 35 50 65 80 )
*/
uint16 CHarvestSource : : getStatQuality ( ) const
{
H_AUTO ( CHarvestSource_getStatQuality ) ;
const CStaticItem * itemInfo = CSheets : : getForm ( _MaterialSheet ) ;
if ( itemInfo & & itemInfo - > Mp )
{
return itemInfo - > Mp - > StatEnergy ;
}
nlwarning ( " Invalid raw material %s " , _MaterialSheet . toString ( ) . c_str ( ) ) ;
return 0 ;
}
/*
* Damage an entity
*/
void CHarvestSource : : hitEntity ( RYZOMID : : TTypeId aggressorType , CEntityBase * entity , sint32 hpDamageAmount , sint32 hpDamageAmountWithoutArmour , bool isIntentional , sint32 hpAvoided )
{
H_AUTO ( CHarvestSource_hitEntity ) ;
if ( entity - > isDead ( ) )
return ;
bool killed = entity - > changeCurrentHp ( - hpDamageAmount ) ;
if ( isIntentional )
{
SM_STATIC_PARAMS_1 ( params , STRING_MANAGER : : integer ) ;
params [ 0 ] . Int = hpDamageAmount ;
PHRASE_UTILITIES : : sendDynamicSystemMessage ( entity - > getEntityRowId ( ) , " FORAGE_ABSORB_DMG " , params ) ;
}
else
PHRASE_UTILITIES : : sendNaturalEventHitMessages ( aggressorType , entity - > getEntityRowId ( ) , hpDamageAmount , hpDamageAmountWithoutArmour , hpAvoided ) ;
if ( killed )
PHRASE_UTILITIES : : sendDeathMessages ( TDataSetRow ( ) , entity - > getEntityRowId ( ) ) ;
}
NLMISC_VARIABLE ( sint32 , ForageSourceDisplay , " Row index of source to verbose " ) ;
/*
* Testing
*/
TDataSetRow TestSourceRow ;
void forageTestDoBegin ( )
{
CHarvestSource templateSource , * testSource ;
templateSource . setLifetime ( 1140 ) ;
templateSource . setProspectionExtraExtractionTime ( 1140 ) ;
CStaticDepositRawMaterial rm ;
testSource = new CHarvestSource ;
CDeposit deposit ;
testSource - > init ( templateSource , CVector2f ( 1000.0f , 1000.0f ) , NULL , & deposit , & rm , 1.0f ) ;
TDataSetRow dsr ;
if ( testSource - > spawnBegin ( 0 , dsr , false ) )
{
TestSourceRow = testSource - > rowId ( ) ;
}
else
{
delete testSource ;
}
}
bool forageTestDoExtract (
NLMISC : : CLog & log ,
uint nbIterations ,
float reqPeriod ,
float reqA ,
float reqQ ,
float absorption ,
float successFactor )
{
CHarvestSource * testSource = CHarvestSourceManager : : getInstance ( ) - > getEntity ( TestSourceRow ) ;
if ( ! testSource )
{
log . displayNL ( " Call forageTestBegin first " ) ;
return true ;
}
// Request and output results
FILE * f = fopen ( std : : string ( getLogDirectory ( ) + " forage_test.csv " ) . c_str ( ) , " at " ) ;
FILE * f2 = fopen ( std : : string ( getLogDirectory ( ) + " forage_test.log " ) . c_str ( ) , " at " ) ;
float reqS = 1.0f / ( reqPeriod * 10.0f ) ;
float req [ CHarvestSource : : NbPosRTProps ] ;
float abs [ CHarvestSource : : NbPosRTProps ] ;
float res [ CHarvestSource : : NbPosRTProps ] ;
static bool FirstTime = true ;
req [ CHarvestSource : : S ] = reqS ;
req [ CHarvestSource : : A ] = reqA ;
req [ CHarvestSource : : Q ] = reqQ ;
abs [ CHarvestSource : : S ] = absorption ;
abs [ CHarvestSource : : A ] = absorption ;
abs [ CHarvestSource : : Q ] = absorption ;
res [ CHarvestSource : : S ] = 0.025f ;
res [ CHarvestSource : : A ] = 0.0f ;
res [ CHarvestSource : : Q ] = 0.0f ;
if ( FirstTime )
{
FirstTime = false ;
fprintf ( f , " A;Q;D;E;C;reqS;reqA;reqQ;qty;scheme;limit; \n " ) ;
}
testSource - > beginExtraction ( TDataSetRow : : createFromRawIndex ( INVALID_DATASET_INDEX ) , false ) ;
bool eventD = false , eventE = false , eventC = false ;
for ( uint i = 0 ; i ! = nbIterations ; + + i )
{
TDataSetRow row ;
CHarvestSource : : TRealTimeProp propDrop ;
testSource - > extractMaterial ( req , abs , ForageQualityCeilingFactor . get ( ) , ForageQualitySlowFactor . get ( ) , res , successFactor , 0 , row , propDrop ) ;
fprintf ( f , " %g;%g;%g;%g;%g;%g;%g;%g;%g;%u;%u; \n " ,
res [ CHarvestSource : : A ] , res [ CHarvestSource : : Q ] ,
testSource - > getD ( ) , testSource - > getE ( ) , 0 /*testSource->getC()*/ ,
reqS , reqA , reqQ ,
testSource - > quantity ( ) , testSource - > getImpactScheme ( ) * 5 , 127 ) ;
if ( ( ! eventD ) & & ( testSource - > getD ( ) > 127 ) )
{
fprintf ( f2 , " D: %u \n " , i ) ;
eventD = true ;
}
if ( ( ! eventE ) & & ( testSource - > getE ( ) > 127 ) )
{
fprintf ( f2 , " E: %u \n " , i ) ;
eventE = true ;
}
/*if ( (!eventC) && (testSource->getC() > 127) )
{
fprintf ( f2 , " C: %u \n " , i ) ;
eventC = true ;
} */
}
if ( ! eventD )
fprintf ( f2 , " D--- \n " ) ;
if ( ! eventE )
fprintf ( f2 , " E--- \n " ) ;
if ( ! eventC )
fprintf ( f2 , " C--- \n " ) ;
fclose ( f ) ;
fclose ( f2 ) ;
return true ;
}
void forageTestDoEnd ( )
{
CHarvestSource * testSource = CHarvestSourceManager : : getInstance ( ) - > getEntity ( TestSourceRow ) ;
if ( ! testSource )
return ;
CHarvestSourceManager : : getInstance ( ) - > destroyEntity ( testSource - > rowId ( ) ) ;
testSource = NULL ;
}
NLMISC_COMMAND ( forageTestBegin , " Start forage test " , " " )
{
forageTestDoBegin ( ) ;
return true ;
}
NLMISC_COMMAND ( forageTestExtract , " Make a test extraction (floats in percent) " ,
" <nbIterations> <reqPeriod=2> <reqA=2> <reqQ=50> <absorption=10> <successFactor=100> " )
{
// Read args
sint n = ( sint ) args . size ( ) ;
uint nbIterations = 1 ;
float reqPeriod = 2.0f ;
float reqA = 2.0f ;
float reqQ = 50.0f ;
float absorption = 0.1f ;
float successFactor = 1.0f ;
if ( n > 0 )
{
NLMISC : : fromString ( args [ 0 ] , nbIterations ) ;
if ( n > 1 )
{
NLMISC : : fromString ( args [ 1 ] , reqPeriod ) ;
if ( n > 2 )
{
NLMISC : : fromString ( args [ 2 ] , reqA ) ;
if ( n > 3 )
{
NLMISC : : fromString ( args [ 3 ] , reqQ ) ;
if ( n > 4 )
{
NLMISC : : fromString ( args [ 4 ] , absorption ) ;
absorption / = 100.0f ;
if ( n > 5 )
{
NLMISC : : fromString ( args [ 5 ] , successFactor ) ;
successFactor / = 100.0f ;
}
}
}
}
}
}
return forageTestDoExtract ( log , nbIterations , reqPeriod , reqA , reqQ , absorption , successFactor ) ;
}
NLMISC_COMMAND ( forageTestBatch , " Batch forage tests " , " " )
{
uint nbIterations = 15 ;
float reqPeriod ;
float reqA ;
float reqQ ;
float absorption ;
float successFactor = 1.0f ;
for ( absorption = 0.1f ; absorption < = 0.8f ; absorption + = 0.7f )
{
forageTestDoBegin ( ) ;
for ( reqQ = 1.0f ; reqQ < = 251.0f ; reqQ + = 50.0f )
{
for ( reqA = 1.0f ; reqA < = 5.0f ; reqA + = 2.0f )
{
for ( reqPeriod = 2.2f ; reqPeriod > = 0.2f ; reqPeriod - = 0.5f )
{
forageTestDoExtract ( log , nbIterations , reqPeriod , reqA , reqQ , absorption , successFactor ) ;
CHarvestSource * testSource = CHarvestSourceManager : : getInstance ( ) - > getEntity ( TestSourceRow ) ;
if ( testSource )
{
CHarvestSource templateSource ;
templateSource . setLifetime ( 1140 ) ;
templateSource . setProspectionExtraExtractionTime ( 1140 ) ;
testSource - > resetSource ( templateSource ) ;
testSource - > setN ( 120 ) ;
testSource - > setD ( 0 ) ;
testSource - > setE ( 0 ) ;
//testSource->setC( 0 );
}
}
}
}
forageTestDoEnd ( ) ;
}
return true ;
}
NLMISC_COMMAND ( forageTestEnd , " End forage test " , " " )
{
// TODO: despawn spawned source!
forageTestDoEnd ( ) ;
return true ;
}
NLMISC_DYNVARIABLE ( uint , NbForageSources , " Number of forage sources " )
{
if ( get )
* pointer = CHarvestSourceManager : : getInstance ( ) - > nbEntities ( ) ;
}
NLMISC_VARIABLE ( uint , NbAutoSpawnedForageSources , " Number of auto-spawned forage sources " ) ;