1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "harvest_source.h"
25 #include "egs_globals.h"
26 #include "phrase_manager/phrase_utilities_functions.h"
27 #include "entity_manager/entity_base.h"
28 #include "player_manager/player_manager.h"
29 #include "player_manager/player.h"
30 #include "player_manager/character.h"
31 #include "forage_progress.h"
32 #include "range_selector.h"
33 #include "egs_sheets/egs_sheets.h"
34 #include "nel/misc/variable.h"
35 #include "phrase_manager/s_effect.h"
36 #include "server_share/r2_vision.h"
39 using namespace NLMISC
;
40 using namespace NLNET
;
43 NL_INSTANCE_COUNTER_IMPL(CHarvestSource
);
44 NL_INSTANCE_COUNTER_IMPL(CHarvestSourceManager
);
46 NL_ISO_TEMPLATE_SPEC CSimpleEntityManager
<CHarvestSource
> *CSimpleEntityManager
<CHarvestSource
>::_Instance
= NULL
;
48 uint NbAutoSpawnedForageSources
= 0;
51 const NLMISC::TGameCycle MaxT
= 1200; // 2 min for prospected sources (TODO: external data)
52 const float CommonRiskThreshold
= 127.0f
;
53 const float ThresholdD1
= CommonRiskThreshold
;
54 const float ThresholdD2
= CommonRiskThreshold
* 1.20f
;
55 const float ThresholdE
= CommonRiskThreshold
;
56 const float ThresholdC
= CommonRiskThreshold
;
58 const float DeltaMoveBarPerTick
= (DeltaMoveBarPerSec
/ 10.0f
);
59 const float DeltaResetBarPerTick
= (DeltaResetBarPerSec
/ 10.0f
);
61 sint32 ForageSourceDisplay
= -1;
63 static const NLMISC::TGameCycle Locked
= ~0;
64 static const NLMISC::TGameCycle IniTime
= (~0)-1; // highest positive integer (suitable for unsigned)
67 // Minimum extraction session:
68 // 6 extractions = 24 seconds with 4 seconds per extraction
69 // Maximum extraction session:
70 // 80 extractions = 120 seconds with 1.5 second per extraction
76 // nlctassert(MaxAS>0);
77 const float MaxAS
= (3.5f
/ 15.0f
);
79 // MaxRequiredQ: 250; InitResultQ: 1 => MaxDeltaQ: 26
80 // nlctassert(MaxDeltaQ>0);
81 const float MaxQ
= 250.0f
;
82 const float MaxDeltaQ
= 26.0f
;
84 // { D, E, C } impacted by (0=Qtty, 1=Qlty, 2=Both)
85 uint ImpactSchemes
[6][3] = { { 0, 1, 2 }, { 0, 2, 1 }, { 1, 0, 2 }, { 1, 2, 0 }, { 2, 0, 1 }, { 2, 1, 0 } };
86 // Observed impact on D (/10): 1 3 6 10 3 1
87 // Observed impact on E (/10): 6 3 1 1 3 10
88 // Note: if modifying this schemes, please change FORAGE_SOURCE_IMPACT_MODE in phrase_en.txt.
89 uint16 SpecialNewbieImpactSchemeD
= 10;
90 uint16 LowDangerMappings
[2] = { (uint16
)(SpecialNewbieImpactSchemeD
+ 1), (uint16
)(SpecialNewbieImpactSchemeD
+ 4) };
92 sint8 ExplosionResetPeriod
= 50; // 5 s
94 CHarvestSource AutoSpawnSourceIniProperties
;
99 CHarvestSourceManager
*CHarvestSourceManager::getInstance()
101 return (CHarvestSourceManager
*)_Instance
;
105 * Initialization of source manager
107 void CHarvestSourceManager::init( TDataSetIndex baseRowIndex
, TDataSetIndex size
)
109 CSimpleEntityManager
<CHarvestSource
>::init( baseRowIndex
, size
);
111 // Note: Now, most of these values are overridden by deposit settings (see CFgProspectionPhrase::autoSpawnSource())
112 AutoSpawnSourceIniProperties
.setLifetime( 6000 ); // 10 min
113 AutoSpawnSourceIniProperties
.setProspectionExtraExtractionTime( 0 ); // no extra time
114 //AutoSpawnSourceIniProperties.setDistVis( 100 );
117 void CHarvestSourceManager::release()
119 delete (CHarvestSourceManager
*)_Instance
;
123 * HarvestSource constructor
125 CHarvestSource::CHarvestSource()
131 // Set default values (TODO: external data)
132 _LifeTime
= 200; // 20 s
133 _ExtractionTime
= 250; // 25 s for initial extraction time (now, recalculated using quality of material)
134 _ExtraExtractionTime
= 25; // 2.5 s
135 _IncludedBonusExtractionTime
= 0;
136 _T
= Locked
; // until spawn is completed
137 _S
= 0.025f
; // 4 s per delivery (initial value may be not used by the extraction action)
142 _TargetRTProps
[TargetD
] = 0;
143 _TargetRTProps
[TargetE
] = 0;
146 _IImpactMappingScheme
= 0;
148 _IsInNewbieMode
= false;
150 //_DistanceVisibility = 80;
151 //_StealthVisibility = VISIBILITY_RIGHTS::All;
152 _IsExtractionInProgress
= false;
153 _ExplosionResetCounter
= -1;
154 _IsAutoSpawned
= false;
156 _NbEventTriggered
= 0;
161 * HarvestSource destructor
163 CHarvestSource::~CHarvestSource()
165 // unregister the deposit auto spawn if any
166 setDepositAutoSpawn(NULL
);
171 * setDepositAutoSpawn
173 void CHarvestSource::setDepositAutoSpawn(CDeposit
*deposit
)
175 // unregister the current deposit, if any
176 if(_DepositAutoSpawn
)
178 _DepositAutoSpawn
->decreaseAutoSpawnedSources();
179 _DepositAutoSpawn
= NULL
;
182 // register the new one if any
185 _DepositAutoSpawn
= deposit
;
186 _DepositAutoSpawn
->increaseAutoSpawnedSources();
192 * Init the source. All pointers must be valid (but forageSite may be NULL).
193 * Return false if the current quantity in the deposit is 0.
195 bool CHarvestSource::init( const CHarvestSource
& ini
, const NLMISC::CVector2f
& pos
,
196 CRecentForageSite
*forageSite
,
197 CDeposit
*depositForK
,
198 const CStaticDepositRawMaterial
*rmInfo
, float quantityRatio
)
202 setForageSite( forageSite
);
203 bool isNonEmpty
= setRawMaterial( rmInfo
, quantityRatio
);
205 // Set link to deposit for kami anger level
206 _DepositForK
= depositForK
;
213 * Set the raw material, the initial amount and the max quality, or return false if the current quantity in the deposit is 0.
215 bool CHarvestSource::setRawMaterial( const CStaticDepositRawMaterial
*rmInfo
, float quantityRatio
)
217 H_AUTO(CHarvestSource_setRawMaterial
);
219 _MaterialSheet
= rmInfo
->MaterialSheet
;
221 // Get corresponding initial quantity & max quality
222 const CStaticItem
*staticItem
= CSheets::getForm( _MaterialSheet
);
223 if ( staticItem
&& staticItem
->Mp
)
225 /// The quantity is a fraction of the 'Stackable' property (but it is limited by the constraints of the deposit)
226 _N
= min( max( (((float)staticItem
->Stackable
) * quantityRatio
), 1.0f
), _ForageSite
->getQuantityInDeposit() );
228 // Select either the MaxQuality in the deposit primitive or in the RM sheet (if -1 in the deposit, or no deposit)
229 sint16 depositMaxQuality
= _ForageSite
? _ForageSite
->deposit()->maxQuality() : -1;
230 if ( depositMaxQuality
!= -1 )
231 _MaxQuality
= (uint16
)depositMaxQuality
;
233 _MaxQuality
= staticItem
->Mp
->MaxQuality
;
234 //nldebug( "Quality limited by source to %hu", _MaxQuality );
241 nlwarning( "%s is not a valid raw material sheet", _MaterialSheet
.toString().c_str() );
249 * Recalculate the remaining extraction time depending on the requested quality.
250 * Does nothing if the source is in "extra extraction time".
251 * _ExtraExtractionTime is included in _ExtraExtractionTime.
253 * Precondition: _ExtractionTime != 0
255 void CHarvestSource::recalcExtractionTime( float requestedQuality
)
257 if ( _T
> _ExtraExtractionTime
)
259 nlassert( _ExtractionTime
> _ExtraExtractionTime
);
260 float timeRatio
= ((float)_T
) / ((float)_ExtractionTime
);
261 //float fExtractionTime = requestedQuality*(0.3092f*10.0f) + (22.0f*10.0f); // Q10 -> 25 s; Q250 -> 1'40 s
262 float fExtractionTime
= requestedQuality
*ForageExtractionTimeSlopeGC
.get() + ForageExtractionTimeMinGC
.get() + (float)_ExtraExtractionTime
;
263 _ExtractionTime
= (NLMISC::TGameCycle
)fExtractionTime
;
264 _T
= (NLMISC::TGameCycle
)(fExtractionTime
* timeRatio
);
270 * Prepare the source as an unpublished entity in mirror. Return false in case of failure.
271 * Must be called *after* init().
272 * prospectorDataSetRow must be either null (isNull()) or an accessible row (isAccessible()).
274 bool CHarvestSource::spawnBegin( uint8 knowledgePrecision
, const TDataSetRow
& prospectorDataSetRow
, bool isAutoSpawned
)
276 H_AUTO(CHarvestSource_spawn
);
278 // Add into mirror (but unpublished)
279 CEntityId entityId
= CEntityId::getNewEntityId( RYZOMID::forageSource
);
280 if ( ! Mirror
.createEntity( entityId
) )
282 _DataSetRow
= TheDataset
.getDataSetRow( entityId
);
283 _IsAutoSpawned
= isAutoSpawned
;
285 // Set the sheet id (including knowledge information)
286 uint sourceFXIndex
= _ForageSite
? (uint
)_ForageSite
->deposit()->sourceFXIndex() : 0;
287 CMirrorPropValue
<TYPE_SHEET
> sheet( TheDataset
, _DataSetRow
, DSPropertySHEET
);
288 sheet
= CSheetId( toString( "%u_%u.forage_source", sourceFXIndex
, knowledgePrecision
) ).asInt();
290 // For knowledge 3, fit the sheet id of the RM sitem into NAME_STRING_ID (instead of a string id) !
291 CMirrorPropValue
<TYPE_NAME_STRING_ID
> nameId( TheDataset
, _DataSetRow
, DSPropertyNAME_STRING_ID
);
292 nameId
= (knowledgePrecision
== 3) ? _MaterialSheet
.asInt() : 0;
293 if ( knowledgePrecision
!= 0 )
295 const CStaticItem
*staticItem
= CSheets::getForm( materialSheet() );
296 if ( staticItem
&& staticItem
->Mp
)
298 // Set additional knowledge info into VISUAL_FX
299 CMirrorPropValue
<TYPE_VISUAL_FX
> visualFx( TheDataset
, _DataSetRow
, DSPropertyVISUAL_FX
);
300 switch ( knowledgePrecision
)
302 case 1: visualFx
= (TYPE_VISUAL_FX
)staticItem
->Mp
->getGroup(); break; // initializes the prop, but only 10 bits allowed
303 case 2: // family sent for 2 & 3 (for knowledge 3, used only as icon index)
304 case 3: visualFx
= (TYPE_VISUAL_FX
)staticItem
->Mp
->Family
; break; // initializes the prop, but only 10 bits allowed
305 default:; // default value is 0
307 if ( (visualFx() & 0x400) != 0 )
309 nlwarning( "FG: Family or group index exceeding max!" ); // bit 10 is reserved for explosion FX
315 // Set the target (the prospector, or a nul datasetrow if auto-spawned)
316 CMirrorPropValue
<TYPE_TARGET_ID
> targetRow( TheDataset
, _DataSetRow
, DSPropertyTARGET_ID
);
317 targetRow
= prospectorDataSetRow
;
319 // Add to manager so that update() will be called at each game cycle
320 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
327 * Complete the source spawn: publish the entity in mirror or delete it.
328 * Caution: if authorized, the source object is deleted!
330 void CHarvestSource::spawnEnd( bool authorized
)
335 CHarvestSourceManager::getInstance()->destroyEntity( _DataSetRow
);
340 _ExtractionTime
= IniTime
; // will trigger calculation in recalcExtractionTime() because _T > _ExtraExtractionTime
341 _T
= _ExtractionTime
; // ratio 1.0 => beginning of extraction time
343 if ( _IsAutoSpawned
)
344 ++NbAutoSpawnedForageSources
;
346 // Set the initial position
347 CMirrorPropValue
<TYPE_POSX
> posX( TheDataset
, _DataSetRow
, DSPropertyPOSX
);
348 CMirrorPropValue
<TYPE_POSY
> posY( TheDataset
, _DataSetRow
, DSPropertyPOSY
);
349 posX
= (TYPE_POSX
)(_Pos
.x
* 1000.0f
);
350 posY
= (TYPE_POSY
)(_Pos
.y
* 1000.0f
);
352 // Set the WhoSeesMe bitfield (distance of visibility by players (0-31) and creatures (32-63)) (now constant)
353 uint32 nbBitsOn
= /*_DistanceVisibility*/80 * 32 / 250; // (250 m is the max, corresponding to 32 bits on
354 const uint64 distanceBitfield
= IsRingShard
? R2_VISION::buildWhoSeesMe(R2_VISION::WHOSEESME_VISIBLE_MOB
,false): ((uint64
)1 << (uint64
)nbBitsOn
) - 1; // (hide to creatures)
355 CMirrorPropValue
<TYPE_WHO_SEES_ME
> whoSeesMe(TheDataset
, _DataSetRow
, DSPropertyWHO_SEES_ME
);
356 whoSeesMe
= distanceBitfield
;
358 // Set selectable property to true
359 CMirrorPropValue
<TYPE_CONTEXTUAL
> contextualProperties(TheDataset
, _DataSetRow
, DSPropertyCONTEXTUAL
);
361 prop
.selectable(true);
362 contextualProperties
= prop
;
364 // Update bars and other variable properties
368 TheDataset
.declareEntity( _DataSetRow
);
373 * Return the prospector or a null datasetrow if there was no prospection (auto-spawn)
374 * The accessibility of this datasetrow must be checked before use.
376 const TDataSetRow
& CHarvestSource::getProspectorDataSetRow() const
378 CMirrorPropValueRO
<TYPE_TARGET_ID
> targetRow( TheDataset
, _DataSetRow
, DSPropertyTARGET_ID
);
384 * Despawn the source in mirror, and exit from forage site
386 void CHarvestSource::despawn()
388 H_AUTO(CHarvestSource_despawn
);
390 // Remove from mirror
391 CEntityId entityId
= TheDataset
.getEntityId( _DataSetRow
);
392 Mirror
.removeEntity( entityId
);
394 //nldebug( "--- %p from %p", this, _ForageSite );
396 // Exit from forage site (the entering is done outside class, because a failure may prevent to create the source)
398 _ForageSite
->removeActiveSource();
400 if ( _IsAutoSpawned
)
401 --NbAutoSpawnedForageSources
;
403 // End forage sessions and calculate XP and give result
404 if ( ! _Foragers
.empty() )
406 // The first forager is the only one who can extract. Give result & dispatch XP
407 CForagers::const_iterator it
= _Foragers
.begin();
408 CCharacter
*player
= PlayerManager
.getChar( *it
);
409 if ( player
&& player
->forageProgress() )
411 if ( player
->forageProgress()->sourceRowId() == _DataSetRow
) // check if he has not changed his target
413 player
->giveForageSessionResult( this );
417 // End sessions of care takers (all excluding the first element)
418 for ( ++it
; it
!=_Foragers
.end(); ++it
)
420 player
= PlayerManager
.getChar( *it
);
421 if ( player
&& player
->forageProgress() )
423 if ( player
->forageProgress()->sourceRowId() == _DataSetRow
) // check if he has not changed his target
425 player
->endForageSession();
434 * Helper for updateVisiblePostPos()
436 inline void updateBarValueAtTick( float& destValue
, float& currentValue
)
438 float diff
= destValue
- currentValue
;
441 currentValue
= std::min( destValue
, currentValue
+ DeltaMoveBarPerTick
);
445 float delta
= (currentValue
== 0) ? DeltaResetBarPerTick
: DeltaMoveBarPerTick
;
446 currentValue
= std::max( destValue
, currentValue
- delta
);
454 bool CHarvestSource::update()
456 H_AUTO(CHarvestSource_update
);
458 if ( _IsExtractionInProgress
)
460 // Make the bar transitions smooth (needs to be done on server to match timing on client)
461 updateBarValueAtTick( _TargetRTProps
[TargetD
], _D
);
462 updateBarValueAtTick( _TargetRTProps
[TargetE
], _E
);
464 // Test damaging event risk
465 if ( _E
> ThresholdE
)
469 impactRTProp( TargetE
, 0 );
472 /*if ( _C > ThresholdC )
474 //sendMessageToExtractors( "CREATURE_SPAWN" );
476 //setEventTriggered();
480 // Test depletion risk (if the bar transition is still in progress, wait)
481 if ( (_D
> ThresholdD1
) )
483 // if high risk value, deplete all the forage site (if exist and allow depletion)
484 if ( _ForageSite
&& _ForageSite
->allowDepletionRisk() && _TargetRTProps
[TargetD
] > ThresholdD2
)
486 sendMessageToExtractors( "FORAGE_SOURCE_SITE_DEPLETED" );
487 _ForageSite
->depleteAll();
489 // else will just kill the current source (send appropriate message)
491 sendMessageToExtractors( "FORAGE_SOURCE_DEPLETED" );
492 // in all case kill the current source, and add bad event
497 // Test remaining time
506 float naturalMoveThreshold
= CommonRiskThreshold
- 2.0f
;
507 if ( _TargetRTProps
[TargetD
]+ForageExtractionNaturalDDeltaPerTick
.get() < naturalMoveThreshold
) // don't auto-move if it makes it trigger the event
508 impactRTProp( TargetD
, _TargetRTProps
[TargetD
] + ForageExtractionNaturalDDeltaPerTick
.get() );
511 if ( _TargetRTProps
[TargetE
]+ForageExtractionNaturalEDeltaPerTick
.get() < naturalMoveThreshold
)
512 impactRTProp( TargetE
, _TargetRTProps
[TargetE
] + ForageExtractionNaturalEDeltaPerTick
.get() );
514 if ( _DataSetRow
.getIndex() == (TDataSetIndex
)ForageSourceDisplay
)
515 nldebug( "T: %u", _T
);
522 // Remain locked if the source is not fully spanwed yet
526 // Test end of lifetime
527 if ( _LifeTime
== 0 )
535 if ( _DataSetRow
.getIndex() == (TDataSetIndex
)ForageSourceDisplay
)
536 nldebug( "_LifeTime: %u", _LifeTime
);
544 * Update visual properties & related stuff
546 void CHarvestSource::updateVisuals()
548 H_AUTO(CHarvestSource_updateVisuals
);
550 // Set the bars on the entity
552 float d
= (_TargetRTProps
[TargetD
] > ForageCareBeginZone
.get()) ? _TargetRTProps
[TargetD
] : 0;
553 if ( d
> CommonRiskThreshold
)
554 d
= CommonRiskThreshold
;
555 float e
= (_TargetRTProps
[TargetE
] > ForageCareBeginZone
.get()) ? _TargetRTProps
[TargetE
] : 0;
556 if ( e
> CommonRiskThreshold
)
557 e
= CommonRiskThreshold
;
558 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))
560 statusBar
= statusBar
| ((uint32(_N
)+1) << 7); // round off to next integer (TODO: ratio qtty/initial_qtty)
561 statusBar
= statusBar
| (uint32((127.0f
-d
)/**127.0f*/) << 14);
562 if (!_SafeSource
) // If source is safe let 0 (client will display it full and with a special color)
563 statusBar
= statusBar
| (uint32((127.0f
-e
)/**127.0f*/) << 21);
564 statusBar
= statusBar
| (((uint32
)(_IsExtractionInProgress
)) << 28);
565 //statusBar = statusBar | (uint32(_C/**127.0f*/) << 28);
566 CMirrorPropValue
<TYPE_BARS
> statusBarProp( TheDataset
, _DataSetRow
, DSPropertyBARS
);
567 statusBarProp
= statusBar
;
569 /*if ( (_N < 0) || (_N > 127) )
570 nlwarning( "FG: N = %g", _N );
571 if ( (_D < 0) || (_D > 127) )
572 nlwarning( "FG: N = %g", _D );
573 if ( (_E < 0) || (_E > 127) )
574 nlwarning( "FG: N = %g", _E );*/
576 // Set kami angry level information & extra time state (store in orientation!)
577 float angryLevel7
= 127.0f
- (127.0f
* _DepositForK
->kamiAnger() / ForageKamiAngerThreshold2
.get());
578 uint extraTime7
= _ExtraExtractionTime
* 127 / _ExtractionTime
;
579 uint inclBonusExtraTime7
= _IncludedBonusExtractionTime
* 127 / _ExtractionTime
;
581 CMirrorPropValue
<TYPE_ORIENTATION
> angryLevelExtraTimeProp( TheDataset
, _DataSetRow
, DSPropertyORIENTATION
);
582 TYPE_ORIENTATION angryLevelExtraTimePropV
= angryLevel7
;
583 if ( _IsExtractionInProgress
)
584 angryLevelExtraTimePropV
+= (( ((float)inclBonusExtraTime7
) * 128.0f
+ (float)extraTime7
) * 128.0f
);
585 angryLevelExtraTimeProp
= angryLevelExtraTimePropV
; // stored as float, should be converted to 21b uint by FS
587 // Reset explosion visual fx if needed
588 if ( _ExplosionResetCounter
== 0 )
590 CMirrorPropValue
<TYPE_VISUAL_FX
> visualFx( TheDataset
, _DataSetRow
, DSPropertyVISUAL_FX
);
591 visualFx
= (visualFx() & 0x3FF); // unset bit 10
592 _ExplosionResetCounter
= -1;
594 else if ( _ExplosionResetCounter
> 0 )
596 --_ExplosionResetCounter
;
604 void CHarvestSource::sendMessageToExtractors( const char *msg
)
606 H_AUTO(CHarvestSource_sendMessageToExtractors
);
608 CForagers::const_iterator it
;
609 for ( it
=_Foragers
.begin(); it
!=_Foragers
.end(); ++it
)
611 const TDataSetRow
& extRowId
= (*it
);
612 PHRASE_UTILITIES::sendDynamicSystemMessage( extRowId
, msg
);
620 void CHarvestSource::sendMessageToExtractors( const char *msg
, sint32 param
)
622 H_AUTO(CHarvestSource_sendMessageToExtractors
);
624 CForagers::const_iterator it
;
625 for ( it
=_Foragers
.begin(); it
!=_Foragers
.end(); ++it
)
627 const TDataSetRow
& extRowId
= (*it
);
628 SM_STATIC_PARAMS_1(params
, STRING_MANAGER::integer
);
629 params
[0].Int
= param
;
630 PHRASE_UTILITIES::sendDynamicSystemMessage( extRowId
, msg
, params
);
635 CVariable
<sint32
> ForageForceImpactScheme( "egs", "ForageForceImpactScheme", "", -1 );
638 * Begin an extraction action. Once the extraction process is started, the source remains in
639 * extraction mode until the extraction time is elapsed (even if players stop/restart
641 * Return true if the forager is the extractor (the first one on the source)
643 bool CHarvestSource::beginExtraction( const TDataSetRow
& forager
, bool isNewbie
)
645 H_AUTO(CHarvestSource_beginExtraction
);
647 bool foragerIsFirstExtractor
= false;
648 if ( ! _IsExtractionInProgress
)
650 _IsExtractionInProgress
= true;
651 foragerIsFirstExtractor
= true;
652 _IsInNewbieMode
= isNewbie
; // only the first one sets the mode
654 // Tell him the max quality
655 SM_STATIC_PARAMS_1(params
, STRING_MANAGER::integer
);
656 params
[0].Int
= (sint32
)_MaxQuality
;
657 PHRASE_UTILITIES::sendDynamicSystemMessage( forager
, "FORAGE_SOURCE_MAXLEVEL", params
);
659 // Set the impact scheme
660 setNewImpactScheme(); // at this time, _Foragers is empty so nobody is told yet
663 // Add player to extractor to list (if new)
664 CForagers::iterator it
= find( _Foragers
.begin(), _Foragers
.end(), forager
);
665 if ( it
== _Foragers
.end() )
667 _Foragers
.push_back( forager
);
669 // Tell him the impact mode
670 SM_STATIC_PARAMS_1(params
, STRING_MANAGER::integer
);
671 params
[0].Int
= (sint32
)_IImpactMappingScheme
;
672 PHRASE_UTILITIES::sendDynamicSystemMessage( forager
, "FORAGE_SOURCE_IMPACT_MODE", params
);
674 else if ( it
== _Foragers
.begin() )
676 foragerIsFirstExtractor
= true;
679 return foragerIsFirstExtractor
;
684 * Set a new mapping scheme of property impact
686 void CHarvestSource::setNewImpactScheme()
688 H_AUTO(CHarvestSource_setNewImpactScheme
);
690 // Set mapping scheme of property impact
691 if ( _IsInNewbieMode
)
693 // Force "low dangers" for 1 newbie extractor
694 _IImpactMappingScheme
= (uint16
)LowDangerMappings
[RandomGenerator
.rand( 1 )];
699 if ( ForageForceImpactScheme
.get() == -1 )
700 _IImpactMappingScheme
= (uint16
)RandomGenerator
.rand( 5 );
702 _IImpactMappingScheme
= (uint16
)ForageForceImpactScheme
.get();
705 sendMessageToExtractors( "FORAGE_SOURCE_IMPACT_MODE", (sint32
)_IImpactMappingScheme
);
708 nldebug( "FG: map scheme: %u", _IImpactMappingScheme
);
713 bool ForceDropProp
= false;
714 NLMISC_VARIABLE( bool, ForceDropProp
, "" );
716 CVariable
<float> ForceAbsorption( "egs", "ForceAbsorption", "", 0 );
720 * Update the source state with an extraction (see doc in .h).
722 void CHarvestSource::extractMaterial( float *reqPosProps
, float *absPosProps
, float qualityCeilingFactor
, float qualitySlowFactor
, float *results
, float successFactor
, uint8 lifeAbsorberRatio
, const TDataSetRow
& extractingEntityRow
, CHarvestSource::TRealTimeProp
& propDrop
)
724 H_AUTO(CHarvestSource_extractMaterial
);
726 CCharacter
* player
= PlayerManager
.getChar( extractingEntityRow
);
728 ++_NbExtractions
; // it's 1 at the first call, so that the initial value is used
729 float nbe
= (float)_NbExtractions
;
731 if ( (successFactor
< 0.1f
) || ForceDropProp
)
733 if ( _NbExtractions
< 6 )
734 propDrop
= Q
; // don't drop A at the beginning (wait to reach 1 (cumulated) would be better)
736 propDrop
= (TRealTimeProp
)(RandomGenerator
.rand(1)+1);
737 nldebug( "Prop drop %u", propDrop
);
740 // Aperture: converges towards the requested value, except when a drop occurs (0 at this step)
741 // if ( reqPosProps[A] > 0 )
743 float obtainedQuantity
= (propDrop
== A
) ? 0.0f
: (results
[A
]*ForageQuantitySlowFactor
.get() + reqPosProps
[A
]) / (ForageQuantitySlowFactor
.get()+1);
745 // Apply possible aperture bonus
746 if ( _BonusForAPct
!= 0 )
748 obtainedQuantity
+= obtainedQuantity
* (float)((uint
)_BonusForAPct
) * 0.01f
;
753 obtainedQuantity
= _ForageSite
->consume( obtainedQuantity
); // consume (and limit) in forage site & deposit
754 if ( obtainedQuantity
> _N
) // should not occur because _N uses the deposit quantity
755 obtainedQuantity
= _N
;
756 _N
-= obtainedQuantity
;
757 _A
= (_A
*nbe
+ obtainedQuantity
) / (nbe
+ 1.0f
); // average per source
758 _DepositForK
->incKamiAnger( obtainedQuantity
, _Foragers
);
759 if ( (obtainedQuantity
== 0) && (results
[A
] != 0) && (! (propDrop
== A
)) )
760 PHRASE_UTILITIES::sendDynamicSystemMessage( _Foragers
[0], "FORAGE_DEPOSIT_IS_EMPTY" );
761 results
[A
] = obtainedQuantity
;
763 // add spire effect ( quantity )
766 const CSEffect
* pEffect
= player
->lookForActiveEffect( EFFECT_FAMILIES::TotemHarvestQty
);
767 if ( pEffect
!= NULL
)
769 results
[A
] *= ( 1.0f
+ pEffect
->getParamValue() / 100.0f
);
772 // add item special effect
775 std::vector
<SItemSpecialEffect
> effects
= player
->lookForSpecialItemEffects(ITEM_SPECIAL_EFFECT::ISE_FORAGE_ADD_RM
);
776 std::vector
<SItemSpecialEffect
>::const_iterator it
, itEnd
;
777 double addedQty
= 0.;
778 for (it
=effects
.begin(), itEnd
=effects
.end(); it
!=itEnd
; ++it
)
780 float rnd
= RandomGenerator
.frand();
781 if (rnd
<it
->EffectArgFloat
[0])
783 addedQty
+= it
->EffectArgFloat
[1];
784 PHRASE_UTILITIES::sendItemSpecialEffectProcMessage(ITEM_SPECIAL_EFFECT::ISE_FORAGE_ADD_RM
, player
, NULL
, (sint32
)(it
->EffectArgFloat
[1]*100.));
787 results
[A
] *= 1.0f
+ (float)addedQty
;
795 // Speed: always the requested speed (otherwise, looks like a bug for the player when it's the speed of the action)
796 results
[S
] = reqPosProps
[S
];
797 _S
= (_S
*nbe
+ results
[S
]) / (nbe
+ 1.0f
); // average per source
799 // Quality: converges towards the requested value, except when a drop occurs (0 at this step)
800 float usedReqQ
= (propDrop
== Q
) ? 0.0f
: reqPosProps
[Q
] * qualityCeilingFactor
;
801 float resQ
= (results
[Q
]*qualitySlowFactor
+ usedReqQ
) / (qualitySlowFactor
+1);
802 float maxQOfSource
= (float)_MaxQuality
;
803 if ( resQ
> maxQOfSource
)
806 //if ( results[Q] < (float)_MaxQuality )
807 // nldebug( "Quality limited by source to %hu", _MaxQuality ); // TODO: tell the player(s)
809 if ( (resQ
< _Q
) || (resQ
< reqPosProps
[Q
]) || (! ForageQualityCeilingClamp
.get()) )
811 // Set Q only if not increasing and exceeding requested quality
816 // Clamp Q to the max required by the player
817 results
[Q
] = reqPosProps
[Q
];
820 _Q
= results
[Q
]; // now there is only one extractor => the Q of the source is the resulting Q
821 if ( ((prevQ
< reqPosProps
[Q
]) && (_Q
== reqPosProps
[Q
])) || ((prevQ
< maxQOfSource
) && (_Q
== maxQOfSource
)) )
823 setNewImpactScheme(); // we just reached the max quality
826 // Calc impact of the new average values
828 // Previously, the impact depended on the level of the extraction:
829 // float quantityBaseImpact = _A * _S * ForageQuantityImpactFactor.get();
830 // float qualityBaseImpact = (_Q - oldQ) * ForageQualityImpactFactor.get();
832 // Now it's constant (=max), but the amount of damage depends on the level of the extraction:
833 float quantityBaseImpact
= MaxAS
* ForageQuantityImpactFactor
.get();
834 float qualityBaseImpact
= MaxDeltaQ
* ForageQualityImpactFactor
.get();
835 uint impactScheme
= _IImpactMappingScheme
;
836 if ( impactScheme
>= SpecialNewbieImpactSchemeD
)
838 // Lower impacts for newbies
839 impactScheme
-= SpecialNewbieImpactSchemeD
;
840 quantityBaseImpact
*= 0.5f
;
841 qualityBaseImpact
*= 0.5f
;
843 if ( ForceAbsorption
.get() != 0 )
845 absPosProps
[A
] = ForceAbsorption
.get();
846 absPosProps
[Q
] = ForceAbsorption
.get();
847 absPosProps
[S
] = ForceAbsorption
.get();
849 for ( uint i
=D
; i
!=NbRTProps
; ++i
)
851 if (i
==E
&& _SafeSource
)
853 uint impactType
= ImpactSchemes
[impactScheme
][i
-NbPosRTProps
];
855 switch ( impactType
)
857 case 0 : impact
= quantityBaseImpact
* (1.0f
- absPosProps
[A
]); break;
858 case 1 : impact
= qualityBaseImpact
* (1.0f
- absPosProps
[Q
]); break;
859 default: impact
= (quantityBaseImpact
+ qualityBaseImpact
) / 2.0f
* (1.0f
- absPosProps
[S
]); break; // bound on the average of both, absorption of S
862 impact
+= RandomGenerator
.frandPlusMinus( impact
); // result impact from 0 to impact*2
864 // add spire effect ( aggressivity )
867 const CSEffect
* pEffect
= player
->lookForActiveEffect( EFFECT_FAMILIES::TotemHarvestAgg
);
868 if ( pEffect
!= NULL
)
870 impact
*= ( 1.0f
- pEffect
->getParamValue() / 100.0f
);
874 if ( impact
< 0 ) impact
= 0; // impact can't be negative
875 if ( (i
==D
) && (lifeAbsorberRatio
!= 0) )
877 // Damage the life absorber, instead of impacting D
878 CEntityBase
*entity
= CEntityBaseManager::getEntityBasePtr( extractingEntityRow
); // getEntityBasePtr() tests TheDataset.isAccessible( extractingEntity )
881 float impactOnHP
= ((float)lifeAbsorberRatio
) * impact
* 0.01f
;
882 impact
-= impactOnHP
;
883 float dmgRatio
= impactOnHP
* ForageHPRatioPerSourceLifeImpact
.get();
884 sint32 dmg
= (sint32
)((float)entity
->maxHp() * dmgRatio
);
886 CHarvestSource::hitEntity( RYZOMID::forageSource
, entity
, dmg
, dmg
, true );
889 if ( (_TargetRTProps
[i
-D
] < CommonRiskThreshold
*0.90f
) && (_TargetRTProps
[i
-D
] + impact
> CommonRiskThreshold
) )
891 // Avoid a brutal unnatural end, make a step just before reaching threshold
892 impactRTProp( (TTargetRTProp
)(i
-D
), CommonRiskThreshold
- 2.0f
);
897 impactRTProp( (TTargetRTProp
)(i
-D
), _TargetRTProps
[i
-D
] + impact
);
904 * Update the source state with a care (see doc in .h)
906 void CHarvestSource::takeCare( float *deltas
, bool *isUseful
)
908 H_AUTO(CHarvestSource_takeCare
);
910 // Do not count care if from the "begin zone"
911 if ( _TargetRTProps
[TargetD
] > ForageCareBeginZone
.get() )
913 if ( _TargetRTProps
[TargetE
] > ForageCareBeginZone
.get() )
915 //if ( deltas[DeltaD] > ForageCareBeginZone.get() )
918 // Calc actual deltas
919 deltas
[DeltaD
] += RandomGenerator
.frandPlusMinus( deltas
[DeltaD
]*0.05f
);
920 deltas
[DeltaE
] += RandomGenerator
.frandPlusMinus( deltas
[DeltaE
]*0.05f
);
921 //deltas[DeltaC] += RandomGenerator.frandPlusMinus( deltas[DeltaC]*0.05f );
923 // TODO: impact on S,A,Q
926 float targetValue
= _TargetRTProps
[TargetD
] - (deltas
[DeltaD
] * ForageCareFactor
.get());
927 if ( targetValue
< 0 )
929 impactRTProp( TargetD
, targetValue
);
932 targetValue
= _TargetRTProps
[TargetE
] - (deltas
[DeltaE
] * ForageCareFactor
.get());
933 if ( targetValue
< 0 )
935 impactRTProp( TargetE
, targetValue
);
937 //_C -= (deltas[DeltaC] * ForageCareFactor.get());
938 //if ( _C < 0 ) _C = 0;
943 * When the threshold of E is reached.
945 void CHarvestSource::makeDamagingEvent()
947 H_AUTO(CHarvestSource_makeDamagingEvent
);
949 sint32 r
= RandomGenerator
.rand( 1 );
960 setNewImpactScheme();
967 class CForageDamagingEventRangeSelector
: public CRangeSelector
970 void buildTargetList( sint32 x
, sint32 y
, float radius
/*, float minFactor*/ )
972 H_AUTO(CForageDamagingEventRangeSelector_buildTargetList
);
974 buildDisc( 0, x
, y
, radius
, EntityMatrix
, true );
977 float getFactor( uint entityIdx
)
979 return 1.0f
; // every entity in the radius gets the same damage, not depending of his location
980 } // improvement note: for explosion, could be decreasing with the distance
985 * A continuous damaging event
987 void CHarvestSource::spawnToxicCloud()
989 H_AUTO(CHarvestSource_spawnToxicCloud
);
991 sendMessageToExtractors( "SOURCE_TOXIC_CLOUD" );
993 // Get random cloud params near the source (TODO: Z)
994 float dmgFactor
= getDamageFactor();
995 sint32 iRadius
= min( (sint32
)2, (sint32
)(dmgFactor
* 3.0f
) ); // => mapping [0..1] to {0, 1, 2}
996 float Radiuses
[3] = { 1.5f
, 3.0f
, 5.0f
}; // corresponding to the 3 sheets
997 float radius
= Radiuses
[iRadius
];
998 CVector
cloudPos( _Pos
.x
, _Pos
.y
, 0.0f
);
1001 // For a big toxic cloud, shift the centre in a axis-aligned square of 4 m width (max dist = 2.8 m)
1002 const float MaxAxisDistFromSource
= 2.0f
;
1003 float dX
= RandomGenerator
.frand( MaxAxisDistFromSource
*2.0f
);
1004 float dY
= RandomGenerator
.frand( MaxAxisDistFromSource
*2.0f
);
1005 cloudPos
.x
+= dX
- MaxAxisDistFromSource
;
1006 cloudPos
.y
+= dY
- MaxAxisDistFromSource
;
1009 // Spawn the toxic cloud
1010 CToxicCloud
*tc
= new CToxicCloud();
1011 tc
->init( cloudPos
, radius
, (sint32
)(dmgFactor
* ToxicCloudDamage
.get()), ToxicCloudUpdateFrequency
);
1013 CSheetId
sheet( toString( "toxic_cloud_%d.fx", iRadius
));
1014 if ( tc
->spawn( sheet
) )
1016 CEnvironmentalEffectManager::getInstance()->addEntity( tc
);
1018 nldebug( "FG: Toxic cloud spawned (radius %g)", radius
);
1023 nlwarning( "FG: Unable to spawn toxic cloud (mirror range full?)" );
1030 * Test which entities to hit (all entities except NPC and non-pets creatures)
1032 inline bool isAffectedByForageDamage( CEntityBase
*entity
)
1034 uint8 entityType
= entity
->getId().getType();
1035 return ! ((entityType
== RYZOMID::npc
) ||
1036 ((entityType
== RYZOMID::creature
) &&
1037 (entity
->getRace() != EGSPD::CPeople::MektoubMount
) &&
1038 (entity
->getRace() != EGSPD::CPeople::MektoubPacker
)));
1043 * A one-time damaging event
1045 void CHarvestSource::explode()
1047 H_AUTO(CHarvestSource_explode
);
1049 sendMessageToExtractors( "SOURCE_EXPLOSION" );
1052 CMirrorPropValue
<TYPE_VISUAL_FX
> visualFx( TheDataset
, _DataSetRow
, DSPropertyVISUAL_FX
);
1053 visualFx
= (visualFx() | 0x400); // set bit 10
1054 _ExplosionResetCounter
= ExplosionResetPeriod
;
1056 // Get entities around the source, and hit them
1057 if ( HarvestAreaEffectOn
)
1060 float fDmg
= getDamageFactor() * ForageExplosionDamage
.get();
1061 float dmgAvoided
= fDmg
;
1062 for ( CRDEvents::const_iterator iev
=_Events
.begin(); iev
!=_Events
.end(); ++iev
)
1064 const CReduceDamageEvent
& event
= (*iev
);
1065 if ( CTickEventHandler::getGameCycle() - event
.Time
< ForageReduceDamageTimeWindow
.get() )
1067 //nldebug( "Damage %.1f x %.1f", fDmg, event.Ratio );
1068 fDmg
*= event
.Ratio
; // multiple events are multiplied (e.g. 50% and 50% again do 25%)
1071 dmgAvoided
= dmgAvoided
- fDmg
;
1072 bool wereAllEventsMissed
= (! _Events
.empty()) && (dmgAvoided
== 0);
1074 // Make area of effect
1075 const float explosionRadius
= 4.0f
;
1076 CForageDamagingEventRangeSelector targetSelector
;
1077 targetSelector
.buildTargetList( (sint32
)(_Pos
.x
* 1000.0f
), (sint32
)(_Pos
.y
* 1000.0f
), explosionRadius
);
1078 const vector
<CEntityBase
*>& targets
= targetSelector
.getEntities();
1079 for ( vector
<CEntityBase
*>::const_iterator it
=targets
.begin(); it
!=targets
.end(); ++it
)
1081 CEntityBase
*entity
= (*it
);
1082 if ( entity
&& isAffectedByForageDamage( entity
) )
1084 sint32 dmg
= (sint32
)(entity
->getActualDamageFromExplosionWithArmor( fDmg
));
1085 CHarvestSource::hitEntity( RYZOMID::forageSource
, entity
, dmg
, (sint32
)(fDmg
+dmgAvoided
), false, (sint32
)dmgAvoided
); // is not blocked by any armor
1087 if ( wereAllEventsMissed
&& (entity
->getId().getType() == RYZOMID::player
) )
1089 PHRASE_UTILITIES::sendDynamicSystemMessage( entity
->getEntityRowId(), "SOURCE_DMG_REDUX_MISSED" );
1098 * Reduce the damage of the next blowing up (if it is in near time delta)
1100 void CHarvestSource::reduceBlowingUpDmg( float ratio
)
1102 H_AUTO(CHarvestSource_reduceBlowingUpDmg
);
1104 CReduceDamageEvent event
;
1105 event
.Time
= CTickEventHandler::getGameCycle();
1106 event
.Ratio
= ratio
;
1107 _Events
.push_back( event
);
1112 * Get the damage factor of a source (for explosion or toxic cloud)
1114 float CHarvestSource::getDamageFactor() const
1116 H_AUTO(CHarvestSource_getDamageFactor
);
1118 // Map linearly using 5 -> 0.5, 80 -> 1.0 (to match previous algorithm)
1119 float statQualityFactor
= ((((float)getStatQuality())+70.0f
) / 150.0f
);
1120 switch ( ImpactSchemes
[_IImpactMappingScheme
][E
] )
1122 case 0 : return _A
* _S
* statQualityFactor
/ MaxAS
; break;
1123 case 1 : return _Q
* statQualityFactor
/ MaxQ
; break; // not using DeltaQ but Q
1124 default: return (_A
*_S
/MaxAS
+ _Q
/MaxQ
) * statQualityFactor
/ 2; break;
1130 * Return the stat quality of the raw material
1132 /*CHarvestSource::TStatClassForage CHarvestSource::getStatQuality() const
1134 H_AUTO(CHarvestSource_getStatQuality);
1136 const CStaticItem *itemInfo = CSheets::getForm( _MaterialSheet );
1137 if ( itemInfo && itemInfo->Mp )
1139 // (0..20 - 1) / 20 = 0
1140 // (21..40 - 1) / 20 = 1
1141 // (41..51 - 1) / 20 = 2;
1142 // (52..59) / 20 = 2
1143 // (61..79) / 20 = 3
1144 // (80..99) / 20 = 4
1146 sint16 statEnergy = (sint16)(itemInfo->Mp->StatEnergy);
1147 TStatClassForage sq =
1148 (statEnergy < 51) ? (statEnergy - 1) / 20 :
1149 ((statEnergy < 100) ? statEnergy / 20 : SupremeMagnificient);
1152 nlwarning( "Invalid raw material %s", _MaterialSheet.toString().c_str() );
1153 return BasicPlainAverage;
1158 * Return the stat quality of the raw material [0..100]
1159 * (Frequent values: 20 35 50 65 80)
1161 uint16
CHarvestSource::getStatQuality() const
1163 H_AUTO(CHarvestSource_getStatQuality
);
1165 const CStaticItem
*itemInfo
= CSheets::getForm( _MaterialSheet
);
1166 if ( itemInfo
&& itemInfo
->Mp
)
1168 return itemInfo
->Mp
->StatEnergy
;
1170 nlwarning( "Invalid raw material %s", _MaterialSheet
.toString().c_str() );
1178 void CHarvestSource::hitEntity( RYZOMID::TTypeId aggressorType
, CEntityBase
*entity
, sint32 hpDamageAmount
, sint32 hpDamageAmountWithoutArmour
, bool isIntentional
, sint32 hpAvoided
)
1180 H_AUTO(CHarvestSource_hitEntity
);
1182 if ( entity
->isDead())
1185 bool killed
= entity
->changeCurrentHp( -hpDamageAmount
);
1186 if ( isIntentional
)
1188 SM_STATIC_PARAMS_1(params
, STRING_MANAGER::integer
);
1189 params
[0].Int
= hpDamageAmount
;
1190 PHRASE_UTILITIES::sendDynamicSystemMessage( entity
->getEntityRowId(), "FORAGE_ABSORB_DMG", params
);
1193 PHRASE_UTILITIES::sendNaturalEventHitMessages( aggressorType
, entity
->getEntityRowId(), hpDamageAmount
, hpDamageAmountWithoutArmour
, hpAvoided
);
1195 PHRASE_UTILITIES::sendDeathMessages( TDataSetRow(), entity
->getEntityRowId() );
1199 NLMISC_VARIABLE( sint32
, ForageSourceDisplay
, "Row index of source to verbose" );
1206 TDataSetRow TestSourceRow
;
1208 void forageTestDoBegin()
1210 CHarvestSource templateSource
, *testSource
;
1211 templateSource
.setLifetime( 1140 );
1212 templateSource
.setProspectionExtraExtractionTime( 1140 );
1213 CStaticDepositRawMaterial rm
;
1215 testSource
= new CHarvestSource
;
1217 testSource
->init( templateSource
, CVector2f(1000.0f
,1000.0f
), NULL
, &deposit
, &rm
, 1.0f
);
1219 if ( testSource
->spawnBegin( 0, dsr
, false ) )
1221 TestSourceRow
= testSource
->rowId();
1229 bool forageTestDoExtract(
1236 float successFactor
)
1238 CHarvestSource
*testSource
= CHarvestSourceManager::getInstance()->getEntity( TestSourceRow
);
1241 log
.displayNL( "Call forageTestBegin first" );
1245 // Request and output results
1246 FILE *f
= nlfopen(getLogDirectory() + "forage_test.csv", "at" );
1247 FILE *f2
= nlfopen(getLogDirectory() + "forage_test.log", "at" );
1248 float reqS
= 1.0f
/ (reqPeriod
* 10.0f
);
1249 float req
[CHarvestSource::NbPosRTProps
];
1250 float abs
[CHarvestSource::NbPosRTProps
];
1251 float res
[CHarvestSource::NbPosRTProps
];
1252 static bool FirstTime
= true;
1253 req
[CHarvestSource::S
] = reqS
;
1254 req
[CHarvestSource::A
] = reqA
;
1255 req
[CHarvestSource::Q
] = reqQ
;
1256 abs
[CHarvestSource::S
] = absorption
;
1257 abs
[CHarvestSource::A
] = absorption
;
1258 abs
[CHarvestSource::Q
] = absorption
;
1259 res
[CHarvestSource::S
] = 0.025f
;
1260 res
[CHarvestSource::A
] = 0.0f
;
1261 res
[CHarvestSource::Q
] = 0.0f
;
1265 fprintf( f
, "A;Q;D;E;C;reqS;reqA;reqQ;qty;scheme;limit;\n" );
1267 testSource
->beginExtraction( TDataSetRow::createFromRawIndex( INVALID_DATASET_INDEX
), false );
1268 bool eventD
= false, eventE
= false, eventC
= false;
1269 for ( uint i
=0; i
!=nbIterations
; ++i
)
1272 CHarvestSource::TRealTimeProp propDrop
;
1273 testSource
->extractMaterial( req
, abs
, ForageQualityCeilingFactor
.get(), ForageQualitySlowFactor
.get(), res
, successFactor
, 0, row
, propDrop
);
1274 fprintf( f
, "%g;%g;%g;%g;%g;%g;%g;%g;%g;%u;%u;\n",
1275 res
[CHarvestSource::A
], res
[CHarvestSource::Q
],
1276 testSource
->getD(), testSource
->getE(), 0.f
/*testSource->getC()*/,
1278 testSource
->quantity(), testSource
->getImpactScheme()*5, 127 );
1279 if ( (!eventD
) && (testSource
->getD() > 127) )
1281 fprintf( f2
, "D: %u\n", i
);
1284 if ( (!eventE
) && (testSource
->getE() > 127) )
1286 fprintf( f2
, "E: %u\n", i
);
1289 /*if ( (!eventC) && (testSource->getC() > 127) )
1291 fprintf( f2, "C: %u\n", i );
1296 fprintf( f2
, "D---\n" );
1298 fprintf( f2
, "E---\n" );
1300 fprintf( f2
, "C---\n" );
1307 void forageTestDoEnd()
1309 CHarvestSource
*testSource
= CHarvestSourceManager::getInstance()->getEntity( TestSourceRow
);
1313 CHarvestSourceManager::getInstance()->destroyEntity( testSource
->rowId() );
1317 NLMISC_COMMAND( forageTestBegin
, "Start forage test", "" )
1319 forageTestDoBegin();
1323 NLMISC_COMMAND( forageTestExtract
, "Make a test extraction (floats in percent)",
1324 "<nbIterations> <reqPeriod=2> <reqA=2> <reqQ=50> <absorption=10> <successFactor=100>" )
1327 sint n
= (sint
)args
.size();
1328 uint nbIterations
= 1;
1329 float reqPeriod
= 2.0f
;
1332 float absorption
= 0.1f
;
1333 float successFactor
= 1.0f
;
1336 NLMISC::fromString(args
[0], nbIterations
);
1339 NLMISC::fromString(args
[1], reqPeriod
);
1342 NLMISC::fromString(args
[2], reqA
);
1345 NLMISC::fromString(args
[3], reqQ
);
1348 NLMISC::fromString(args
[4], absorption
);
1349 absorption
/= 100.0f
;
1352 NLMISC::fromString(args
[5], successFactor
);
1353 successFactor
/= 100.0f
;
1361 return forageTestDoExtract( log
, nbIterations
, reqPeriod
, reqA
, reqQ
, absorption
, successFactor
);
1364 NLMISC_COMMAND( forageTestBatch
, "Batch forage tests", "" )
1366 uint nbIterations
= 15;
1371 float successFactor
= 1.0f
;
1373 for ( absorption
=0.1f
; absorption
<=0.8f
; absorption
+=0.7f
)
1375 forageTestDoBegin();
1376 for ( reqQ
=1.0f
; reqQ
<=251.0f
; reqQ
+=50.0f
)
1378 for ( reqA
=1.0f
; reqA
<=5.0f
; reqA
+=2.0f
)
1380 for ( reqPeriod
=2.2f
; reqPeriod
>=0.2f
; reqPeriod
-=0.5f
)
1382 forageTestDoExtract( log
, nbIterations
, reqPeriod
, reqA
, reqQ
, absorption
, successFactor
);
1383 CHarvestSource
*testSource
= CHarvestSourceManager::getInstance()->getEntity( TestSourceRow
);
1386 CHarvestSource templateSource
;
1387 templateSource
.setLifetime( 1140 );
1388 templateSource
.setProspectionExtraExtractionTime( 1140 );
1389 testSource
->resetSource( templateSource
);
1390 testSource
->setN( 120 );
1391 testSource
->setD( 0 );
1392 testSource
->setE( 0 );
1393 //testSource->setC( 0 );
1404 NLMISC_COMMAND( forageTestEnd
, "End forage test", "" )
1406 // TODO: despawn spawned source!
1413 NLMISC_DYNVARIABLE( uint
, NbForageSources
, "Number of forage sources" )
1416 *pointer
= CHarvestSourceManager::getInstance()->nbEntities();
1419 NLMISC_VARIABLE( uint
, NbAutoSpawnedForageSources
, "Number of auto-spawned forage sources" );