1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "player_manager/character.h"
21 #include "player_manager/player_manager.h"
22 #include "player_manager/player.h"
23 #include "zone_manager.h"
24 #include "entities_game_service.h"
25 #include "egs_globals.h"
26 #include "nel/misc/noise_value.h"
27 #include "nel/misc/variable.h"
28 #include "nel/misc/words_dictionary.h"
29 #include "game_share/time_weather_season/time_date_season_manager.h"
30 #include "game_share/people.h"
31 #include "egs_sheets/egs_sheets.h"
32 #include "phrase_manager/fg_prospection_phrase.h"
33 #include "phrase_manager/phrase_utilities_functions.h"
34 #include "game_share/send_chat.h"
35 #include "game_share/multi_target.h"
36 #include "phrase_manager/s_effect.h"
37 #include "projectile_stats.h"
40 using namespace NLMISC
;
41 using namespace NLLIGO
;
42 using namespace NLNET
;
43 using namespace RM_FAMILY
;
46 const float SmallDepositAreaThreshold
= 64.0f
*64.0f
;
47 const float SmallDepositAreaReference
= 16.0f
*32.0f
;
49 // The ecotype zones (only valid at init, cleared after deposit built)
50 CEcotypeZones
CDeposit::_EcotypeZones
;
52 NL_INSTANCE_COUNTER_IMPL(CAutoSpawnProperties
);
53 NL_INSTANCE_COUNTER_IMPL(CQuantityConstraints
);
55 // Verbose deposits debug variable
56 //bool VerboseDeposits = false;
58 // Total number of CRecentForageSite objects (debug info)
59 uint32 TotalNbRecentForageSites
= 0;
61 /// Export deposit contents report
62 bool ExportDepositContents
= false;
64 /// Verbose the items parsed when filtering deposits
65 bool VerboseDepositFiltering
= false;
68 void cbChangeDepositUpdateFrequency( NLMISC::IVariable
& v
)
70 /*const TGameCycle expectedTTL = 6000; // 10 min
71 if ( DepositUpdateFrequency.get() != 0 )
72 ForageSiteNbUpdatesToLive.set( (uint16)(expectedTTL / DepositUpdateFrequency.get()) );*/
73 nlinfo( "TODO: change ForageSiteNbUpdatesToLive according to DepositUpdateFrequency" );
81 bool malformed( const char *field
, const string
& name
)
83 nlwarning( "FG: Malformed primitive %s, missing field '%s'", name
.c_str(), field
);
88 * Get the enums of the families (using RM_FAMILY::toFamily(), assumes the string are ended by _value)
89 * where value is the identifier number (see .typ).
90 * Removes duplicates (with a warning).
92 void convertRMFamiliesNames( const string
& name
, const vector
<string
>& src
, vector
<TRMFamily
>& dest
)
94 for ( uint i
=0; i
!=src
.size(); ++i
)
96 if ( ! src
[i
].empty() )
98 string::size_type p
= src
[i
].find_last_of( '_' );
99 if ( p
!= string::npos
)
101 TRMFamily family
= toFamily( src
[i
].substr( p
+ 1 ) );
102 if ( find( dest
.begin(), dest
.end(), family
) == dest
.end() )
103 dest
.push_back( family
);
105 nlwarning( "FG: Deposit %s: %s found twice", name
.c_str(), src
[i
].c_str() );
109 nlwarning( "FG: Deposit %s: %s: not found", name
.c_str(), src
[i
].c_str() );
116 * Get the indices of the item parts (assumes the strings are ended by _index).
118 * Removes duplicates (with a warning).
120 void convertItemPartsNames( const string
& name
, const vector
<string
>& src
, vector
<uint
>& dest
)
122 for ( uint i
=0; i
!=src
.size(); ++i
)
124 if ( ! src
[i
].empty() )
126 string::size_type p
= src
[i
].find_last_of( '_' );
127 if ( p
!= string::npos
)
130 NLMISC::fromString(src
[i
].substr( p
+ 1 ), itemPart
);
131 if ( find( dest
.begin(), dest
.end(), itemPart
) == dest
.end() )
132 dest
.push_back( itemPart
);
134 nlwarning( "FG: Deposit %s: %s found twice", name
.c_str(), src
[i
].c_str() );
138 nlwarning( "FG: Deposit %s: %s: not found", name
.c_str(), src
[i
].c_str() );
147 void convertCraftCivNames( const vector
<string
>& src
, vector
<ITEM_ORIGIN::EItemOrigin
>& dest
)
149 dest
.resize( src
.size() );
150 for ( uint i
=0; i
!=src
.size(); ++i
)
152 dest
[i
] = ITEM_ORIGIN::stringToEnum( src
[i
] );
160 inline void makeFullSItemCode( string
& code
)
162 if ( code
.find( ".sitem" ) == string::npos
)
170 * Return always a forage site
172 CRecentForageSite
*CDeposit::findOrCreateForageSite( const NLMISC::CVector
& pos
)
174 // Search in existing ones
175 for ( CRecentForageSites::iterator ihs
=_RecentForageSites
.begin(); ihs
!=_RecentForageSites
.end(); ++ihs
)
177 if ( (*ihs
).contains( pos
) )
183 // Not found, create one
184 ++TotalNbRecentForageSites
;
185 CRecentForageSite
newForageSite( this, pos
);
186 _RecentForageSites
.push_back( newForageSite
);
187 return &_RecentForageSites
.back(); // returning the pointer is valid because an element in std::list is never invalidated
194 bool CRecentForageSite::contains( const NLMISC::CVector
& pos
) const
196 float r
= ForageSiteRadius
.get();
197 return ((pos
-_Pos
).sqrnorm() < r
*r
);
202 * Display debug or stat info
204 void CRecentForageSite::display( NLMISC::CLog
& log
) const
206 log
.displayNL( "Forage site at %s: %u sources, stock %u, %u lowfreq updates remaining",
207 _Pos
.asString().c_str(), _NbActiveSources
, _LowScopeStock
, _TimeToLive
);
211 //-----------------------------------------------------------------------------
212 // Parse primitive file for one ecotype
213 //-----------------------------------------------------------------------------
214 bool CEcotypeZone::build( const NLLIGO::CPrimZone
* zone
)
216 *( (NLLIGO::CPrimZone
*)this ) = *zone
;
218 // Read primitive name
220 if ( ! zone
->getPropertyByName( "name", name
) ) return malformed( "name", name
);
224 if ( ! zone
->getPropertyByName( "ecotype", ecotypeS
) ) return malformed( "ecotype", name
);
225 _Ecotype
= ECOSYSTEM::stringToEcosystem( ecotypeS
); // needs a case-unsensitive comparison, because the
226 if ( _Ecotype
== ECOSYSTEM::unknown
) // World Editor lists names of files in CVS (in deposit_system/ecotypes)
227 nlwarning( "%s: Ecotype %s unknown", name
.c_str(), ecotypeS
.c_str() );
235 CDeposit::~CDeposit()
237 if ( _AutoSpawnSourcePt
)
238 delete _AutoSpawnSourcePt
;
239 _AutoSpawnSourcePt
= NULL
;
240 if ( _QuantityConstraintsPt
)
241 delete _QuantityConstraintsPt
;
242 _QuantityConstraintsPt
= NULL
;
244 // Avoid any bug, remove the deposit from zone manager
245 CZoneManager::getInstance().unregisterDepositToAutoSpawnUpdate(this);
250 * Get the ecotype zone under the position.
251 * This information is valid only at init time. After the deposits are built, this information
252 * can be found only in deposits.
253 * If not found, a NULL pointer is returned.
255 CEcotypeZone
*CDeposit::getEcotypeZone( const NLMISC::CVector
& pos
)
257 // The ecotypes must not be overlapped: only the first one found is returned
258 for ( CEcotypeZones::iterator it
=_EcotypeZones
.begin(); it
!=_EcotypeZones
.end(); ++it
)
260 CEcotypeZone
*ecotypeZone
= (*it
);
261 if ( ecotypeZone
->contains( pos
) )
271 * Clear ecotype information, after having built the deposits
273 void CDeposit::clearEcotypes()
275 for ( CEcotypeZones::iterator iez
=_EcotypeZones
.begin(); iez
!=_EcotypeZones
.end(); ++iez
)
279 _EcotypeZones
.clear();
283 struct TCompareStaticItemPtrBySheetId
: public std::binary_function
<CStaticItem
*,CStaticItem
*,bool>
285 bool operator() ( const CStaticItem
* p1
, const CStaticItem
* p2
)
287 return (p1
->SheetId
< p2
->SheetId
);
292 //-----------------------------------------------------------------------------
293 // Parse primitive file for one deposit
294 //-----------------------------------------------------------------------------
295 bool CDeposit::build( const NLLIGO::CPrimZone
* zone
)
301 *( (NLLIGO::CPrimZone
*)this ) = *zone
;
303 // Read primitive name
305 if ( ! zone
->getPropertyByName( "name", name
) ) return malformed( "name", name
);
308 // Read exact raw material codes to add
309 vector
<string
> *exactRMCodesS
= NULL
;
310 if ( ! (zone
->getPropertyByName( "exact_mp_item", exactRMCodesS
) && exactRMCodesS
) ) return malformed( "exact_mp_item", name
);
312 // Read raw material family filter
313 vector
<string
> *rmFamilyFilterS
= NULL
;
314 if ( ! (zone
->getPropertyByName( "mps", rmFamilyFilterS
) && rmFamilyFilterS
) ) return malformed( "mps", name
);
316 // Read item part / craft civ filter
317 vector
<string
> *itemPartsFilterS
= NULL
, *craftCivS
= NULL
;
318 if ( ! (zone
->getPropertyByName( "item_parts", itemPartsFilterS
) && itemPartsFilterS
) ) return malformed( "item_parts", name
);
319 if ( ! (zone
->getPropertyByName( "craft_civ", craftCivS
) && craftCivS
) ) return malformed( "craft_civ", name
);
321 // Read stat+quality filters
322 string minEnergyS
, maxEnergyS
, minQualityS
, maxQualityS
;
323 if ( ! zone
->getPropertyByName( "deposit_statquality_min", minEnergyS
) ) return malformed( "deposit_statquality_min", name
);
324 if ( ! zone
->getPropertyByName( "deposit_statquality_max", maxEnergyS
) ) return malformed( "deposit_statquality_max", name
);
325 if ( ! zone
->getPropertyByName( "deposit_min_quality_250", minQualityS
) ) return malformed( "deposit_min_quality_250", name
);
326 if ( ! zone
->getPropertyByName( "deposit_max_quality_250", maxQualityS
) ) return malformed( "deposit_max_quality_250", name
);
327 NLMISC::fromString(minQualityS
, _MinQuality
);
328 NLMISC::fromString(maxQualityS
, _MaxQuality
);
330 // Read quantity constraints
331 string qttyLimitS
, qttyRespawnTimeS
;
332 if ( ! zone
->getPropertyByName( "deposit_quantity_limit", qttyLimitS
) ) return malformed( "deposit_quantity_limit", name
);
333 if ( ! zone
->getPropertyByName( "deposit_quantity_respawn_time_ryzomdays", qttyRespawnTimeS
) ) return malformed( "deposit_quantity_respawn_time_ryzomdays", name
);
335 NLMISC::fromString(qttyLimitS
, qttyLimit
);
336 if ( qttyLimit
> -1 )
338 sint qttyRespawnTime
;
339 NLMISC::fromString(qttyRespawnTimeS
, qttyRespawnTime
);
340 if ( (qttyLimit
== 0) || (qttyLimit
> 0xFFFF) || (qttyRespawnTime
< 1) || (qttyRespawnTime
> 0xFFFF) )
341 nlwarning( "Invalid limit or respawn time too high in %s", name
.c_str() );
344 _QuantityConstraintsPt
= new CQuantityConstraints();
345 _QuantityConstraintsPt
->CurrentQuantity
= (float)qttyLimit
;
346 _QuantityConstraintsPt
->InitialQuantity
= (uint16
)qttyLimit
;
347 _QuantityConstraintsPt
->RespawnTimeRyzomDays
= qttyRespawnTime
;
352 CEcotypeZone
*ecotypeZone
= getEcotypeZone( getBarycentre() );
353 _Ecotype
= ecotypeZone
? ecotypeZone
->ecotype() : ECOSYSTEM::common_ecosystem
;
355 nlwarning( "FG: Deposit %s has no ecotype", name
.c_str() );
360 string s1s
, s2s
, s3s
, s4s
;
361 if ( ! zone
->getPropertyByName( "while_season_spring", s1s
) ) return malformed( "while_season_spring", name
);
362 if ( ! zone
->getPropertyByName( "while_season_summer", s2s
) ) return malformed( "while_season_summer", name
);
363 if ( ! zone
->getPropertyByName( "while_season_automn", s3s
) ) return malformed( "while_season_automn", name
);
364 if ( ! zone
->getPropertyByName( "while_season_winter", s4s
) ) return malformed( "while_season_winter", name
);
365 bool s1
= (s1s
=="true"), s2
= (s2s
=="true"), s3
= (s3s
=="true"), s4
= (s4s
=="true");
366 if ( ! (s1
&& s2
&& s3
&& s4
) )
368 if ( s1
) { _SeasonFilter
.push_back( EGSPD::CSeason::Spring
); _FilterPhase
|= 0x1; }
369 if ( s2
) { _SeasonFilter
.push_back( EGSPD::CSeason::Summer
); _FilterPhase
|= 0x2; }
370 if ( s3
) { _SeasonFilter
.push_back( EGSPD::CSeason::Autumn
); _FilterPhase
|= 0x4; }
371 if ( s4
) { _SeasonFilter
.push_back( EGSPD::CSeason::Winter
); _FilterPhase
|= 0x8; }
375 string w1s
, w2s
, w3s
, w4s
;
376 if ( ! zone
->getPropertyByName( "while_weather_0_best", w1s
) ) return malformed( "while_weather_0_best", name
);
377 if ( ! zone
->getPropertyByName( "while_weather_1_good", w2s
) ) return malformed( "while_weather_1_good", name
);
378 if ( ! zone
->getPropertyByName( "while_weather_2_bad", w3s
) ) return malformed( "while_weather_2_bad", name
);
379 if ( ! zone
->getPropertyByName( "while_weather_3_worst", w4s
) ) return malformed( "while_weather_3_worst", name
);
380 bool w1
= (w1s
=="true"), w2
= (w2s
=="true"), w3
= (w3s
=="true"), w4
= (w4s
=="true");
381 if ( ! (w1
&& w2
&& w3
&& w4
) )
383 if ( w1
) { _WeatherFilter
.push_back( CRyzomTime::best
); _FilterPhase
|= 0x10; }
384 if ( w2
) { _WeatherFilter
.push_back( CRyzomTime::good
); _FilterPhase
|= 0x20; }
385 if ( w3
) { _WeatherFilter
.push_back( CRyzomTime::bad
); _FilterPhase
|= 0x40; }
386 if ( w4
) { _WeatherFilter
.push_back( CRyzomTime::worst
); _FilterPhase
|= 0x80; }
391 if ( ! zone
->getPropertyByName( "while_its_day", t1s
) ) return malformed ( "while_its_day", name
);
392 if ( ! zone
->getPropertyByName( "while_its_night", t2s
) ) return malformed ( "while_its_night", name
);
393 bool t1
= (t1s
=="true"), t2
= (t2s
=="true");
398 _TimeOfDayFilter
.push_back( CRyzomTime::dawn
);
399 _TimeOfDayFilter
.push_back( CRyzomTime::day
);
400 _TimeOfDayFilter
.push_back( CRyzomTime::evening
);
401 _FilterPhase
|= 0x100;
405 _TimeOfDayFilter
.push_back( CRyzomTime::nightfall
);
406 _TimeOfDayFilter
.push_back( CRyzomTime::night
);
407 _FilterPhase
|= 0x200;
411 // Read auto-spawn properties
413 if ( ! zone
->getPropertyByName( "auto_spawn_sources", assS
) ) return malformed( "auto_spawn_sources", name
);
416 string aspS
, asltS
, asetS
, amin
; // not really 'average' anymore
417 if ( ! zone
->getPropertyByName( "auto_spawn_average_period_s", aspS
) ) return malformed( "auto_spawn_average_period", name
);
418 if ( ! zone
->getPropertyByName( "auto_spawn_lifetime_s", asltS
) ) return malformed( "auto_spawn_lifetime", name
);
419 if ( ! zone
->getPropertyByName( "auto_spawn_extraction_time_s", asetS
) ) return malformed( "auto_spawn_sources", name
);
420 if ( ! zone
->getPropertyByName( "auto_spawn_min_source", amin
) ) return malformed( "auto_spawn_min_source", name
);
421 _AutoSpawnSourcePt
= new CAutoSpawnProperties
;
422 NLMISC::fromString(aspS
, _AutoSpawnSourcePt
->SpawnPeriodGc
);
423 _AutoSpawnSourcePt
->SpawnPeriodGc
*= 10;
424 NLMISC::fromString(asltS
, _AutoSpawnSourcePt
->LifeTimeGc
);
425 _AutoSpawnSourcePt
->LifeTimeGc
*= 10;
426 NLMISC::fromString(asetS
, _AutoSpawnSourcePt
->ExtractionTimeGc
);
427 _AutoSpawnSourcePt
->ExtractionTimeGc
*= 10;
428 NLMISC::fromString(amin
, _AutoSpawnSourcePt
->MinimumSpawnedSources
);
430 _AutoSpawnSourcePt
->MinimumSpawnedSources
= min(uint32(100), _AutoSpawnSourcePt
->MinimumSpawnedSources
);
434 _AutoSpawnSourcePt
= NULL
;
437 // Read source FX index
439 if ( ! zone
->getPropertyByName( "source_fx", srcFXIndexS
) ) return malformed( "source_fx", name
);
440 NLMISC::fromString(srcFXIndexS
, _SourceFXIndex
);
442 // Read other initial properties
443 string cpS
, eS
, ikaS
, adpR
;
444 if ( ! zone
->getPropertyByName( "can_prospect", cpS
) ) return malformed( "can_prospect", name
);
445 if ( ! zone
->getPropertyByName( "enabled", eS
) ) return malformed( "enabled", name
);
446 if ( ! zone
->getPropertyByName( "initial_kami_anger", ikaS
) ) return malformed( "initial_kami_anger", name
);
447 if ( ! zone
->getPropertyByName( "can_have_depletion_risk", adpR
) ) return malformed( "can_have_depletion_risk", name
);
448 _CanProspect
= (cpS
=="true");
449 _Enabled
= (eS
=="true");
450 _AllowDepletionRisk
= (adpR
=="true");
451 _KamiAnger
= (float)atof( ikaS
.c_str() );
452 if ( (_KamiAnger
!= -1.0f
) && (_KamiAnger
< 0) )
453 nlwarning( "Invalid initial_kami_anger %.1f in %s", _KamiAnger
, name
.c_str() );
456 uint32 minEnergy
, maxEnergy
;
457 NLMISC::fromString(minEnergyS
, minEnergy
);
458 NLMISC::fromString(maxEnergyS
, maxEnergy
);
459 if ( exactRMCodesS
->empty() && rmFamilyFilterS
->empty() && itemPartsFilterS
->empty() )
461 nlwarning( "FG: Deposit %s: No RM, exactRms or item parts specified!", name
.c_str() );
465 selectRMsByFilters( *exactRMCodesS
, *rmFamilyFilterS
, *itemPartsFilterS
, *craftCivS
, minEnergy
, maxEnergy
);
467 nldebug( "FG: Built deposit %s %s %s %s %s", name
.c_str(), _AutoSpawnSourcePt
?"AUTO":"-", _CanProspect
?"PRO":"-", _AllowDepletionRisk
?"ADPR":"-", _Enabled
?"ON":"OFF" );
473 * Select the raw materials, using the specified filters and _Ecotype
475 void CDeposit::selectRMsByFilters( std::vector
<std::string
>& exactRMCodesS
, const std::vector
<std::string
>& rmFamilyFilterS
, const std::vector
<std::string
>& itemPartsFilterS
, const std::vector
<std::string
>& craftCivS
, uint minEnergy
, uint maxEnergy
)
477 vector
<TRMFamily
> rmFamilyFilter
;
478 convertRMFamiliesNames( _Name
, rmFamilyFilterS
, rmFamilyFilter
);
479 vector
<uint
> itemPartsFilter
;
480 convertItemPartsNames( _Name
, itemPartsFilterS
, itemPartsFilter
);
481 vector
<ITEM_ORIGIN::EItemOrigin
> craftCivFilter
;
482 convertCraftCivNames( craftCivS
, craftCivFilter
);
483 for_each( exactRMCodesS
.begin(), exactRMCodesS
.end(), makeFullSItemCode
);
485 if ( VerboseDepositFiltering
)
486 nldebug( "%s", _Name
.c_str() );
488 // Sort the items by sheetId so that the deposits are not dependant on the hash map ordering
489 const CAllStaticItems
& allItems
= CSheets::getItemMapForm();
490 vector
< const CStaticItem
* > sortedItems( allItems
.size() );
492 for ( CAllStaticItems::const_iterator it
=allItems
.begin(); it
!=allItems
.end(); ++it
, ++i
)
494 sortedItems
[i
] = &((*it
).second
);
496 std::sort( sortedItems
.begin(), sortedItems
.end(), TCompareStaticItemPtrBySheetId() );
498 for ( vector
< const CStaticItem
* >::const_iterator it
=sortedItems
.begin(); it
!=sortedItems
.end(); ++it
)
500 // Eliminate non raw materials
501 const CStaticItem
& staticItem
= *(*it
);
502 if ( ! staticItem
.Mp
)
504 const string
& sheetName
= staticItem
.SheetId
.toString();
505 if ( (sheetName
.size() < (CREATURE_OR_DEPOSIT_MP_CHAR
+1)) || (sheetName
[0] != 'm' ) )
508 // Keep raw material directly if matching one of specified exact raw material codes (including creature's raw materials)
509 if ( find( exactRMCodesS
.begin(), exactRMCodesS
.end(), sheetName
) == exactRMCodesS
.end() )
511 // Eliminate non 'forage' raw materials
512 if ( VerboseDepositFiltering
)
513 nldebug( "FG: Submitting %s", sheetName
.c_str() );
514 if ( (sheetName
[CREATURE_OR_DEPOSIT_MP_CHAR
] != 'd') )
517 // Eliminate raw materials of incompatible ecosystem
518 if ( (_Ecotype
!= ECOSYSTEM::common_ecosystem
) && (staticItem
.Mp
->Ecosystem
!= ECOSYSTEM::common_ecosystem
) &&
519 (staticItem
.Mp
->Ecosystem
!= _Ecotype
) )
521 if ( VerboseDepositFiltering
) nldebug( "-Ecotype %s", ECOSYSTEM::toString( staticItem
.Mp
->Ecosystem
).c_str() );
525 // Match energy filter (TEMP: 25 is the minimum maxEnergy threshold) (include boundaries)
526 if ( (staticItem
.Mp
->StatEnergy
< minEnergy
) || (staticItem
.Mp
->StatEnergy
> maxEnergy
/*max(maxEnergy,(uint)25)*/) )
528 if ( VerboseDepositFiltering
) nldebug( "-StatEnergy %hu", staticItem
.Mp
->StatEnergy
);
532 // Match rmFamilyFilter or itemPartsFilter
533 if ( find( rmFamilyFilter
.begin(), rmFamilyFilter
.end(), staticItem
.Mp
->Family
) == rmFamilyFilter
.end() )
535 // If not found in rmFamilyFilter, try if one of itemPartsFilter is matched along with civ
537 for ( vector
<uint
>::iterator ipf
=itemPartsFilter
.begin(); ipf
!=itemPartsFilter
.end(); ++ipf
)
539 uint itemPartIndex
= (*ipf
);
541 // Find if the current RM has the item part matching one of the filter
542 const CMP::TMpFaberParameters
*mpFaberParam
= staticItem
.Mp
->getMpFaberParameters( itemPartIndex
);
543 if ( mpFaberParam
&& (mpFaberParam
->Durability
!= 0) )
545 if ( (craftCivFilter
.empty()) || // no civ constraint
546 (mpFaberParam
->CraftCivSpec
== ITEM_ORIGIN::COMMON
) || // RM matches all civs
547 (find( craftCivFilter
.begin(), craftCivFilter
.end(), mpFaberParam
->CraftCivSpec
) != craftCivFilter
.end()) ) // RM matches civ constraint
549 if ( VerboseDepositFiltering
) nldebug( "+StatEnergy %hu +ItemPart %c +CivSpec %s", staticItem
.Mp
->StatEnergy
, 'A' + (char)itemPartIndex
, ITEM_ORIGIN::enumToString( mpFaberParam
->CraftCivSpec
).c_str() );
551 break; // RM is selected, no need to test other item parts
554 if ( VerboseDepositFiltering
) nldebug( "-CivSpec %s", ITEM_ORIGIN::enumToString( mpFaberParam
->CraftCivSpec
).c_str() );
558 if ( VerboseDepositFiltering
) nldebug( "-ItemPart %c", 'A' + (char)itemPartIndex
);
566 if ( VerboseDepositFiltering ) nldebug( "+rmFamilyFilter %u", staticItem.Mp->Family );
571 if ( VerboseDepositFiltering ) nldebug( "+exact_mp_item %s", sheetName.c_str() );
574 // Select if matching (do not check duplicate, keep them if item part matches explicit family)
575 CStaticDepositRawMaterial rm
;
576 rm
.MaterialSheet
= staticItem
.SheetId
;
577 _RawMaterials
.push_back( rm
);
578 if ( VerboseDepositFiltering
)
579 nldebug( "SELECTED %s", sheetName
.c_str() );
581 // Export deposit contents report if requested
582 if ( ExportDepositContents
)
584 static FILE *depositReportFile
;
585 static bool depositReportCreated
= false;
586 if ( ! depositReportCreated
)
588 depositReportCreated
= true;
589 depositReportFile
= nlfopen( "deposit_contents.csv", "wt" ); // fclose() auto?
590 if ( depositReportFile
)
592 fprintf( depositReportFile
, "Deposit;RM;When in year;When in day;Weather;\n" );
595 if ( depositReportFile
)
596 fprintf( depositReportFile
, "%s;%s;%s;%s;%s;\n", _Name
.c_str(), rm
.MaterialSheet
.toString().c_str(), getSeasonStr().c_str(), getTimeOfDayStr().c_str(), getWeatherStr().c_str() );
599 if ( _RawMaterials
.empty() )
600 nlwarning( "FG: Selected 0 items in deposit %s", _Name
.c_str() );
602 nldebug( "FG: Selected %u RM (on %u items) in deposit %s", _RawMaterials
.size(), allItems
.size(), _Name
.c_str() );
607 * Helper for CDeposit::hasFamily()
609 struct CIsOfFamilyPred
: public std::binary_function
< CStaticDepositRawMaterial
, RM_FAMILY::TRMFamily
, bool >
612 bool operator() ( const CStaticDepositRawMaterial
& rm
, RM_FAMILY::TRMFamily family
) const
614 const CAllStaticItems
& allItems
= CSheets::getItemMapForm();
615 CAllStaticItems::const_iterator it
= allItems
.find( rm
.MaterialSheet
);
616 if ( it
!= allItems
.end() )
618 const CStaticItem
& staticItem
= (*it
).second
;
619 return staticItem
.Mp
&& (staticItem
.Mp
->Family
== family
);
628 * Helper for CDeposit::hasFamily()
630 struct CIsOfGroupPred
: public std::binary_function
< CStaticDepositRawMaterial
, RM_GROUP::TRMGroup
, bool >
633 bool operator() ( const CStaticDepositRawMaterial
& rm
, RM_GROUP::TRMGroup group
) const
635 const CAllStaticItems
& allItems
= CSheets::getItemMapForm();
636 CAllStaticItems::const_iterator it
= allItems
.find( rm
.MaterialSheet
);
637 if ( it
!= allItems
.end() )
639 const CStaticItem
& staticItem
= (*it
).second
;
640 return staticItem
.Mp
&& (staticItem
.Mp
->getGroup() == group
);
649 * Helper for CDeposit::hasRMForItemPart()
651 struct CCanCraftItemPartPred
: public std::binary_function
< CStaticDepositRawMaterial
, uint
, bool >
654 bool operator() ( const CStaticDepositRawMaterial
& rm
, uint itemPartIndex
) const
656 const CAllStaticItems
& allItems
= CSheets::getItemMapForm();
657 CAllStaticItems::const_iterator it
= allItems
.find( rm
.MaterialSheet
);
658 if ( it
!= allItems
.end() )
660 const CStaticItem
& staticItem
= (*it
).second
;
663 const CMP::TMpFaberParameters
*mpFaberParam
= staticItem
.Mp
->getMpFaberParameters( itemPartIndex
);
664 return (mpFaberParam
&& (mpFaberParam
->Durability
!= 0));
676 * Helper for CDeposit::hasFamily()
678 struct CMatchStatEnergyPred
: public std::binary_function
< CStaticDepositRawMaterial
, uint8
, bool >
681 bool operator() ( const CStaticDepositRawMaterial
& rm
, uint8 maxStatEnergy
) const
683 const CAllStaticItems
& allItems
= CSheets::getItemMapForm();
684 CAllStaticItems::const_iterator it
= allItems
.find( rm
.MaterialSheet
);
685 if ( it
!= allItems
.end() )
687 const CStaticItem
& staticItem
= (*it
).second
;
688 return staticItem
.Mp
&& (staticItem
.Mp
->StatEnergy
<= maxStatEnergy
); // include boundary
692 nlwarning( "%s not found", rm
.MaterialSheet
.toString().c_str() );
700 * Helper for CDeposit::hasFamily()
702 struct CMatchExactStatEnergyPred
: public std::binary_function
< CStaticDepositRawMaterial
, uint8
, bool >
705 bool operator() ( const CStaticDepositRawMaterial
& rm
, uint8 maxStatEnergy
) const
707 const CAllStaticItems
& allItems
= CSheets::getItemMapForm();
708 CAllStaticItems::const_iterator it
= allItems
.find( rm
.MaterialSheet
);
709 if ( it
!= allItems
.end() )
711 const CStaticItem
& staticItem
= (*it
).second
;
712 return staticItem
.Mp
&& (staticItem
.Mp
->StatEnergy
== maxStatEnergy
);
721 * Return true if the deposit contains at least one RM of the specified family
723 bool CDeposit::hasFamily( RM_FAMILY::TRMFamily family
) const
725 return find_if( _RawMaterials
.begin(), _RawMaterials
.end(), bind2nd( CIsOfFamilyPred(), family
) ) != _RawMaterials
.end();
729 * Return true if the deposit contains at least one RM of the specified group
731 bool CDeposit::hasGroup( RM_GROUP::TRMGroup group
) const
733 return find_if( _RawMaterials
.begin(), _RawMaterials
.end(), bind2nd( CIsOfGroupPred(), group
) ) != _RawMaterials
.end();
737 * Return true if the deposit contains at least one RM than can craft the specified item part
739 bool CDeposit::hasRMForItemPart( uint itemPartIndex
) const
741 return find_if( _RawMaterials
.begin(), _RawMaterials
.end(), bind2nd( CCanCraftItemPartPred(), itemPartIndex
) ) != _RawMaterials
.end();
745 * Return true if the deposit contains at least one RM with energy lower_eq than the specified value
747 bool CDeposit::hasLowerStatEnergy( uint8 maxStatEnergy
) const
749 return find_if( _RawMaterials
.begin(), _RawMaterials
.end(), bind2nd( CMatchStatEnergyPred(), maxStatEnergy
) ) != _RawMaterials
.end();
753 * Return true if the deposit contains at least one RM with energy equalling the specifing value
755 bool CDeposit::hasExactStatEnergy( uint8 statEnergy
) const
757 return find_if( _RawMaterials
.begin(), _RawMaterials
.end(), bind2nd( CMatchExactStatEnergyPred(), statEnergy
) ) != _RawMaterials
.end();
762 * Called by lowFreqUpdate and autoSpawnUpdate
764 void CDeposit::autoSpawnSource(const CVector
&cornerMin
, const CVector
&cornerMax
)
767 Yoyo: This method may fail because it selects a random position in a box and then check if it's in the zone.
768 We can do better by making a list of triangles of the concave polygon, then selecting randomly and
769 carefully in this list of triangle.
772 // Randomize a position in the deposit
775 const uint NB_ATTEMPTS
= 5;
777 for ( iAttempt
=0; iAttempt
!=NB_ATTEMPTS
; ++iAttempt
)
779 pos
.x
= cornerMin
.x
+ RandomGenerator
.frand( cornerMax
.x
- cornerMin
.x
);
780 pos
.y
= cornerMin
.y
+ RandomGenerator
.frand( cornerMax
.y
- cornerMin
.y
);
781 if ( contains( pos
) )
785 // If a valid position could not be found, abort spawning of this source
786 if ( iAttempt
== NB_ATTEMPTS
)
790 CFgProspectionPhrase::autoSpawnSource( pos
, this );
795 * Update deposit (especially recent forage sites)
797 void CDeposit::lowFreqUpdate()
799 if ( !HarvestSystemEnabled
)
801 // Update recent forage sites
802 for ( CRecentForageSites::iterator it
=_RecentForageSites
.begin(); it
!=_RecentForageSites
.end(); )
804 CRecentForageSite
& forageSite
= (*it
);
805 if ( forageSite
.lowFreqUpdate() )
811 --TotalNbRecentForageSites
;
812 it
= _RecentForageSites
.erase( it
);
816 // Decrease kami anger level
817 decKamiAnger( ForageKamiAngerDecreasePerHour
.get() / 36000.0f
* ((float)DepositUpdateFrequency
.get()) );
819 // Auto-spawn a source from time to time (if the deposit has this flag)
820 if ( _AutoSpawnSourcePt
&& _Enabled
)
823 //TTime testYoyoLT0= CTime::getLocalTime();
824 //uint countBefore= _CurrentNbAutoSpawnedSources;
826 uint spawnPeriodLFUpdates
= (AutoSpawnForageSourcePeriodOverride
.get() != 0) ? AutoSpawnForageSourcePeriodOverride
.get() / DepositUpdateFrequency
.get() : _AutoSpawnSourcePt
->SpawnPeriodGc
/ DepositUpdateFrequency
.get();
829 CVector cornerMin
, cornerMax
;
830 getAABox( cornerMin
, cornerMax
);
832 // Previously, the rythm of spawning was randomized. Now it's constant.
833 //TGameCycle spawnAvgPeriod = (AutoSpawnForageSourceAveragePeriodOverride.get() != 0) ? AutoSpawnForageSourceAveragePeriodOverride.get() : _AutoSpawnSourcePt->SpawnAveragePeriodGc;
834 //sint32 r = RandomGenerator.rand( (uint16)(spawnAvgPeriod / DepositUpdateFrequency.get()) );
836 bool spawnSourceBecauseOfFrequency
= (CTickEventHandler::getGameCycle() / DepositUpdateFrequency
.get()) % spawnPeriodLFUpdates
== 0;
838 // Avoid infinite loop if the spawn of source is too buggy:
839 // count first the number of sources to force spawn then run this count, and forget the ones that fail.
840 uint numSourceToForceSpawn
= 0;
841 if(_CurrentNbAutoSpawnedSources
< _AutoSpawnSourcePt
->MinimumSpawnedSources
)
842 numSourceToForceSpawn
= _AutoSpawnSourcePt
->MinimumSpawnedSources
- _CurrentNbAutoSpawnedSources
;
843 uint numSourceSpawned
= 0;
844 while ( spawnSourceBecauseOfFrequency
|| numSourceSpawned
<numSourceToForceSpawn
)
846 // this method may fail, but don't cares and continues
847 autoSpawnSource(cornerMin
, cornerMax
);
850 // If continue this loop, won't be because of frequency update, but because of minimum source requirement
851 spawnSourceBecauseOfFrequency
= false;
855 //TTime testYoyoLT1= CTime::getLocalTime();
856 //nlinfo("*** [%03d]AutoSpawnLOWFREQ Time(%d->%d): %d ms", CTickEventHandler::getGameCycle()%1000, countBefore, _CurrentNbAutoSpawnedSources, testYoyoLT1 - testYoyoLT0);
859 // Beware: can return before
864 * Update deposit that need to auto spawn because number of harvest sources is too low
866 void CDeposit::autoSpawnUpdate()
868 if ( !HarvestSystemEnabled
)
871 // Auto-spawn a source from time to time (if the deposit has this flag)
872 if ( _AutoSpawnSourcePt
&& _Enabled
&& _CurrentNbAutoSpawnedSources
< _AutoSpawnSourcePt
->MinimumSpawnedSources
)
875 //TTime testYoyoLT0= CTime::getLocalTime();
876 //uint countBefore= _CurrentNbAutoSpawnedSources;
879 CVector cornerMin
, cornerMax
;
880 getAABox( cornerMin
, cornerMax
);
882 // Avoid infinite loop if the spawn of source is too buggy:
883 // count first the number of sources to force spawn then run this count, and forget the ones that fail.
884 uint numSourceToForceSpawn
= _AutoSpawnSourcePt
->MinimumSpawnedSources
- _CurrentNbAutoSpawnedSources
;
886 // for all sources to spawn
887 for( uint i
= 0; i
<numSourceToForceSpawn
; i
++)
889 // this method may fail, but don't cares and continues
890 autoSpawnSource(cornerMin
, cornerMax
);
893 //TTime testYoyoLT1= CTime::getLocalTime();
894 //nlinfo("*** [%03d]AutoSpawnFORCE Time(%d->%d): %d ms", CTickEventHandler::getGameCycle()%1000, countBefore, _CurrentNbAutoSpawnedSources, testYoyoLT1 - testYoyoLT0);
897 // Beware: can return before
902 * Auto Spawn Deposit mgt
904 void CDeposit::decreaseAutoSpawnedSources()
906 BOMB_IF(_CurrentNbAutoSpawnedSources
==0, "nb auto spawned sources should be > 0!", return);
907 _CurrentNbAutoSpawnedSources
--;
909 // If the deposit has not enough ressources, must refill at next tick update
910 // NB: don't do it at next lowFreqUpdate(), to avoid big jump in CPU each 30 sec
911 // as soon an autospawned harvest source is unspawned, the deposit will refill at next tick.
912 if(_AutoSpawnSourcePt
&& _CurrentNbAutoSpawnedSources
< _AutoSpawnSourcePt
->MinimumSpawnedSources
)
914 CZoneManager::getInstance().registerDepositToAutoSpawnUpdate(this);
918 void CDeposit::increaseAutoSpawnedSources()
920 _CurrentNbAutoSpawnedSources
++;
924 //-----------------------------------------------------------------------------
925 // character take MP, kami eat this fool character ?
926 //-----------------------------------------------------------------------------
928 //void CDeposit::characterTakeRM( const CEntityId& charId, uint32 depositIndexContent, uint16 quantity )
930 // // check if depositIndexContent is in valid range
931 // if( depositIndexContent < _DepositContent.size() )
933 // // process kami guardian reaction and fame impact
934 // CDepositRawMaterialSeasonParameters * seasonParameters;
935 // switch( CTimeDateSeasonManager::getRyzomTimeReference().getRyzomSeason() )
937 // case EGSPD::CSeason::Spring:
938 // seasonParameters = &_DepositContent[ depositIndexContent ]->SpringParams;
940 // case EGSPD::CSeason::Summer:
941 // seasonParameters = &_DepositContent[ depositIndexContent ]->SummerParams;
943 // case EGSPD::CSeason::Autumn:
944 // seasonParameters = &_DepositContent[ depositIndexContent ]->AutumnParams;
946 // case EGSPD::CSeason::Winter:
947 // seasonParameters = &_DepositContent[ depositIndexContent ]->WinterParams;
950 // nlstop; //=> debug CTimeDateSeasonManager....
953 // if( seasonParameters->AngryLevel >= _DepositContent[ depositIndexContent ]->CurrentQuantity )
955 // sint32 fameImpact;
956 // uint32 kamiImpact;
958 // CMessage msgString("STATIC_STRING");
959 // msgString.serial( const_cast< CEntityId& > ( charId ) );
960 // // serial exclude set of empty exclude set
961 // set< CEntityId > empty;
962 // msgString.serialCont( empty );
964 // if( seasonParameters->BlackKamiLevel >= _DepositContent[ depositIndexContent ]->CurrentQuantity )
966 // // kami impact for AIS when Kami expulse a black kami
969 // // set fame impact
972 // string str("WOS_KAMI_BLACK_KAMI");
973 // msgString.serial(str);
975 // else if( seasonParameters->FuryLevel >= _DepositContent[ depositIndexContent ]->CurrentQuantity )
977 // // kami impact for AIS when Kami is fury against harvester
980 // // set fame impact
983 // string str("WOS_KAMI_FURY");
984 // msgString.serial( str );
986 // else if( seasonParameters->AngryLevel >= _DepositContent[ depositIndexContent ]->CurrentQuantity )
988 // // kami impact for AIS when Kami is angry against harvester
991 // // set fame impact
994 // string str("WOS_KAMI_ANGRY");
995 // msgString.serial( str );
997 // sendMessageViaMirror( "IOS", msgString );
999 // // Send message to AIS for kami impact
1000 // CMessage msgout("KAMI_IMPACT");
1001 // // TODO : if this code reactivated, add the instance number and send to the corect AIS
1002 // msgout.serial( const_cast<CEntityId&> (charId) );
1003 // msgout.serial( _Alias );
1004 // msgout.serial( kamiImpact );
1005 // sendMessageViaMirror( "AIS", msgout );
1008 // // send message to EGS for fame impact
1009 // // TODO boris : update fame with new fame system
1010 ///* CCharacter * c = PlayerManager.getChar( charId );
1011 // uint8 fameType = FAMES::kami;
1014 // c->fameChange( fameType, fameImpact );
1018 // // update deposit quantity
1019 // if( _DepositContent[ depositIndexContent ]->CurrentQuantity < quantity )
1021 // _DepositContent[ depositIndexContent ]->CurrentQuantity = 0;
1025 // _DepositContent[ depositIndexContent ]->CurrentQuantity -= quantity;
1030 // nlwarning("FG: <CDeposit::characterTakeRM> Received invalid depositIndexContent %d (deposit content size id %d)", depositIndexContent, _DepositContent.size() );
1036 string
CDeposit::getSeasonStr() const
1039 if ( _SeasonFilter
.empty() )
1041 for ( uint i
=0; i
!=_SeasonFilter
.size(); ++i
)
1045 s
+= EGSPD::CSeason::toString( _SeasonFilter
[i
] );
1050 string
CDeposit::getTimeOfDayStr() const
1053 if ( _TimeOfDayFilter
.empty() )
1054 return "Night & day";
1055 for ( uint i
=0; i
!=_TimeOfDayFilter
.size(); ++i
)
1059 s
+= toString( "%u", (uint
)_TimeOfDayFilter
[i
] );
1064 string
CDeposit::getWeatherStr() const
1067 if ( _WeatherFilter
.empty() )
1068 return "All weathers";
1069 for ( uint i
=0; i
!=_WeatherFilter
.size(); ++i
)
1073 s
+= toString( "%u", (uint
)_WeatherFilter
[i
] );
1079 //-----------------------------------------------------------------------------
1080 // display deposit content
1081 //-----------------------------------------------------------------------------
1082 void CDeposit::displayContent( NLMISC::CLog
* log
, bool extendedInfo
, NLMISC::CWordsDictionary
*itemDictionary
)
1084 const CAllStaticItems
& allItems
= CSheets::getItemMapForm();
1085 uint32 materialNumber
= 0;
1086 log
->displayRawNL( "---- DEPOSIT %s ----", _Name
.c_str() );
1087 log
->displayRawNL( "\t Centre: %s", getBarycentre().toString().c_str() );
1088 if ( getContents().empty() )
1089 log
->displayRawNL( "\tNo RM was selected in this deposit" );
1090 log
->displayRawNL( "\t%u RMs:", getContents().size() );
1091 for( std::vector
< CStaticDepositRawMaterial
>::const_iterator it
= getContents().begin(); it
!= getContents().end(); ++it
)
1094 log
->displayRawNL( "\tRM #%d", materialNumber
);
1096 CSString sheetCode
= (*it
).MaterialSheet
.toString();
1097 string fullNameInfo
;
1098 if ( itemDictionary
)
1100 CVectorSString result
;
1101 sheetCode
= sheetCode
.splitTo( '.' );
1102 itemDictionary
->lookup( sheetCode
, result
);
1103 if ( ! result
.empty() )
1104 fullNameInfo
= string(" ") + result
[0];
1106 if ( fullNameInfo
.empty() )
1107 log
->displayRawNL( "\t\tRM Id: %s", sheetCode
.c_str() );
1109 log
->displayRawNL( "\t\tRM Id: %s", fullNameInfo
.c_str() );
1110 //log->displayNL( "\t\tMax Amount: %d", (*it).MaxAmount );
1113 CAllStaticItems::const_iterator itItem
= allItems
.find( (*it
).MaterialSheet
);
1114 if ( itItem
!= allItems
.end() && (*itItem
).second
.Mp
)
1116 const CStaticItem
& staticItem
= (*itItem
).second
;
1117 log
->displayRawNL( "\t\tFamily: %u", staticItem
.Mp
->Family
);
1118 log
->displayRawNL( "\t\tGroup: %u", staticItem
.Mp
->getGroup() );
1119 log
->displayRawNL( "\t\tEcosystem: %s", ECOSYSTEM::toString( staticItem
.Mp
->Ecosystem
).c_str() );
1120 //log->displayRawNL( "\t\tRarity: %hu", staticItem.Mp->Rarity );
1121 log
->displayRawNL( "\t\tStatEnergy: %hu", staticItem
.Mp
->StatEnergy
);
1125 log
->displayRawNL( "\tEcotype: %s", ECOSYSTEM::toString( _Ecotype
).c_str() );
1127 if ( _WeatherFilter
.empty() )
1131 for( vector
<CRyzomTime::EWeather
>::const_iterator iwf
=_WeatherFilter
.begin(); iwf
!=_WeatherFilter
.end(); ++iwf
)
1132 ws
+= toString( "%u:", *iwf
);
1134 log
->displayRawNL( "\tWeathers: %s", ws
.c_str() );
1136 if ( _TimeOfDayFilter
.empty() )
1140 for( vector
<CRyzomTime::ETimeOfDay
>::const_iterator itf
=_TimeOfDayFilter
.begin(); itf
!=_TimeOfDayFilter
.end(); ++itf
)
1141 ts
+= toString( "%u:", *itf
);
1143 log
->displayRawNL( "\tTimes of day: %s", ts
.c_str() );
1145 if ( _SeasonFilter
.empty() )
1149 for( vector
<CRyzomTime::ESeason
>::const_iterator isf
=_SeasonFilter
.begin(); isf
!=_SeasonFilter
.end(); ++isf
)
1150 ws
+= toString( "%u:", *isf
);
1152 log
->displayRawNL( "\tSeasons: %s", ss
.c_str() );
1153 log
->displayRaw( "\tKami anger: %.1f", _KamiAnger
);
1154 if ( _KamiAnger
== -1.0f
)
1155 log
->displayRawNL( " disabled" );
1157 log
->displayRawNL( " on %.1f, %.1f", ForageKamiAngerThreshold1
.get(), ForageKamiAngerThreshold2
.get() );
1158 if ( _AutoSpawnSourcePt
)
1159 log
->displayRawNL( "\tAutoSpawnSource: %s", _AutoSpawnSourcePt
?"ON":"OFF" );
1160 if ( ! _CanProspect
)
1161 log
->displayRawNL( "\tCanProspect: %d", _CanProspect
);
1163 log
->displayRawNL( "\tEnabled: %d", _Enabled
);
1164 if ( ! _AllowDepletionRisk
)
1165 log
->displayRawNL( "\tAllowDepletionRisk: %d", _AllowDepletionRisk
);
1169 float GenRand
= 1.0f
;
1170 float GenFreq
= 0.05f
;
1172 NLMISC_COMMAND( setDepositRand
, "Set CNoiseValue params for deposits", "<rand> <freq>" )
1174 if ( args
.size() < 2 )
1176 GenRand
= (float)atof( args
[0].c_str() );
1177 GenFreq
= (float)atof( args
[1].c_str() );
1185 class CIndexNoiseValue
: public CNoiseValue
1190 CIndexNoiseValue( uint arraySize
, uint phase
, float freq
) : CNoiseValue(0.0f
, 1.0f
, freq
), _MaxIndex((float)(arraySize
)), _Phase(1210.191f
*phase
, 523.8883f
*phase
, 403.57614f
*phase
) {}
1192 /// Evaluate the value corresponding to the pos
1193 uint
eval( const CVector
& pos
) const
1195 uint indexOfMax
= 0;
1198 // 1 dephased noise per possible value, and take the max result (otherwise with '(CNoiseValue::eval( pos ) * _MaxIndex)', the result would be biased)
1199 for( uint i
=0; i
!=_MaxIndex
; ++i
)
1201 float f
= CNoiseValue::eval(
1202 pos
+ _Phase
+ CVector(5245.346f
*i
, 785.67985f
*i
, 7842.783367f
*i
) );
1221 * Compute freq according to deposit size (small deposits under 64x64 have a proportionally higher frequency)
1223 inline float getFreqFromDepositArea( float depositBBoxArea
)
1225 if ( depositBBoxArea
< SmallDepositAreaThreshold
)
1227 const float gradient
= (0.05f
-0.3f
)*2.0f
/(SmallDepositAreaThreshold
-SmallDepositAreaReference
);
1228 return gradient
*depositBBoxArea
+ (GenFreq
- gradient
*(SmallDepositAreaThreshold
));
1238 * Get a random RM from the neighbourhood of the specified position.
1239 * OptFastFloorBegin()/OptFastFloorEnd() must enclose one or more calls to this method.
1241 const CStaticDepositRawMaterial
*CDeposit::getRandomRMAtPos( const NLMISC::CVector
& pos
, bool testIfSiteDepleted
, bool& isDepleted
)
1243 const float cellWidth
= 1.0f
;
1244 const uint16 nbNeighbours
= 5; // center + 4 neighbour cells
1246 //nldebug( "Selecting RM in deposit" );
1248 if ( getContents().empty() )
1251 // Test is local zone is depleted
1252 if ( testIfSiteDepleted
)
1254 for ( CRecentForageSites::iterator ihs
=_RecentForageSites
.begin(); ihs
!=_RecentForageSites
.end(); ++ihs
)
1256 if ( (*ihs
).isDepleted() && (*ihs
).contains( pos
) )
1258 //nldebug( "Harvest site depleted" );
1265 // Compute freq according to deposit size
1266 float freq
= getFreqFromDepositArea( getAreaOfAABox() );
1268 // Get raw materials in neighbourhood
1269 uint neighbourhoud
[nbNeighbours
];
1270 CVector cellPos
= pos
;
1271 CIndexNoiseValue
noiseIndex( getContentSize(), _FilterPhase
, freq
); // the phrase prevents to have the same map for two deposits with identical size but different seasons, etc.
1272 neighbourhoud
[0] = noiseIndex
.eval( cellPos
);
1273 cellPos
.x
-= cellWidth
;
1274 cellPos
.y
-= cellWidth
;
1275 neighbourhoud
[1] = noiseIndex
.eval( cellPos
);
1276 cellPos
.x
= pos
.x
+ cellWidth
;
1277 neighbourhoud
[2] = noiseIndex
.eval( cellPos
);
1278 cellPos
.y
= pos
.y
+ cellWidth
;
1279 neighbourhoud
[3] = noiseIndex
.eval( cellPos
);
1280 cellPos
.x
= pos
.x
- cellWidth
;
1281 neighbourhoud
[4] = noiseIndex
.eval( cellPos
);
1282 //nldebug( "Indices: %u %u %u %u", neighbourhoud[0], neighbourhoud[1], neighbourhoud[2], neighbourhoud[3] );
1284 // Select a random RM among neighbourhood
1285 uint rmIndex
= neighbourhoud
[RandomGenerator
.rand( nbNeighbours
-1 )];
1286 return &(getContents()[rmIndex
]);
1289 if( seasonParameters->AngryLevel >= _DepositContent[ infos.DepositIndexContent ]->CurrentQuantity )
1291 CMessage msgout("STATIC_STRING");
1292 msgout.serial( const_cast< CEntityId& > ( charId ) );
1293 // serial exclude set of empty exclude set
1294 set< CEntityId > empty;
1295 msgout.serialCont( empty );
1296 string str("EGS_KAMI_ALERTE");
1297 msgout.serial( str );
1298 sendMessageViaMirror( "IOS", msgout );
1305 * Get the RM at the specified position.
1306 * OptFastFloorBegin()/OptFastFloorEnd() must enclose one or more calls to this method.
1307 * \param testIfSiteDepleted Set it to false for map generation.
1309 const CStaticDepositRawMaterial
*CDeposit::getRMAtPos( const NLMISC::CVector
& pos
, bool testIfSiteDepleted
, bool& isDepleted
)
1311 //const float cellWidth = 5.0f;
1313 //nldebug( "Selecting RM in deposit" );
1315 if ( getContents().empty() )
1318 // Test is local zone is depleted
1319 if ( testIfSiteDepleted
)
1321 for ( CRecentForageSites::iterator ihs
=_RecentForageSites
.begin(); ihs
!=_RecentForageSites
.end(); ++ihs
)
1323 if ( (*ihs
).isDepleted() && (*ihs
).contains( pos
) )
1325 //nldebug( "Harvest site depleted" );
1332 // Compute freq according to deposit size
1333 float freq
= getFreqFromDepositArea( getAreaOfAABox() );
1335 // Get raw material at position
1336 CIndexNoiseValue
noiseIndex( getContentSize(), _FilterPhase
, freq
);
1337 uint rmIndex
= noiseIndex
.eval( pos
);
1338 //nldebug( "Index: %u", rmIndex );
1339 if ( rmIndex
>= getContentSize() )
1341 nlwarning( "FG: CIndexNoiseValue returned a value out of range" );
1342 rmIndex
= getContentSize()-1;
1344 return &(getContents()[rmIndex
]);
1349 * Return the current quantity. If 0 and the respawn time is elapsed, unlock.
1351 float CQuantityConstraints::getCurrentQuantity()
1353 if ( CurrentQuantity
== 0 )
1356 const CRyzomTime
& ryzomTime
= CTimeDateSeasonManager::getRyzomTimeReference();
1357 if ( ryzomTime
.getRyzomDay() < NextRespawnDay
)
1365 CurrentQuantity
= InitialQuantity
;
1368 return CurrentQuantity
;
1375 * Last possible consumption => lock deposit for RespawnTimeRyzomDays.
1376 * Does not unlock the deposit (see getCurrentQuantity() instead)
1377 * Argument by value.
1379 float CQuantityConstraints::consumeQuantity( float consumed
)
1381 if ( CurrentQuantity
> 0 )
1383 float newQuantity
= CurrentQuantity
- consumed
;
1384 if ( newQuantity
<= 0 )
1386 // Lock if the deposit is now empty (and wasn't before)
1387 const CRyzomTime
& ryzomTime
= CTimeDateSeasonManager::getRyzomTimeReference();
1388 NextRespawnDay
= ryzomTime
.getRyzomDay() + (uint32
)RespawnTimeRyzomDays
;
1390 // Give only the remaining quantity
1391 consumed
= CurrentQuantity
;
1396 CurrentQuantity
= newQuantity
;
1405 * Display forage sites info
1407 void CDeposit::displayRecentForageSites( NLMISC::CLog
& log
) const
1409 if ( ! _RecentForageSites
.empty() )
1411 log
.displayNL( "Deposit %s:", _Name
.c_str() );
1412 for ( CRecentForageSites::const_iterator it
=_RecentForageSites
.begin(); it
!=_RecentForageSites
.end(); ++it
)
1414 const CRecentForageSite
& forageSite
= (*it
);
1415 forageSite
.display( log
);
1422 * Empty all forage sites
1424 void CDeposit::depleteAllRecentForageSites()
1426 for ( CRecentForageSites::iterator it
=_RecentForageSites
.begin(); it
!=_RecentForageSites
.end(); ++it
)
1428 CRecentForageSite
& forageSite
= (*it
);
1429 forageSite
.depleteAll();
1435 * Increment the kami anger level (delta < 768). React if a threshold is reached. Return the kami anger level.
1437 float CDeposit::incKamiAnger( float delta
, const std::vector
<TDataSetRow
>& foragers
)
1439 if ( _KamiAnger
== -1.0f
)
1442 if ( ForageKamiAngerOverride
.get() != 0 )
1443 _KamiAnger
= ForageKamiAngerOverride
.get();
1445 _KamiAnger
+= delta
;
1446 if ( _KamiAnger
> ForageKamiAngerThreshold1
.get() )
1448 if ( _KamiAnger
< ForageKamiAngerThreshold2
.get() )
1450 // Only a warning (and small punishment ?)
1451 for ( vector
<TDataSetRow
>::const_iterator itf
=foragers
.begin(); itf
!=foragers
.end(); ++itf
)
1453 // Send a warning message
1454 const TDataSetRow
& rowId
= (*itf
);
1456 npcTellToPlayer( noRow
, rowId
, "FORAGE_KAMI_ANGER_WARNING", false );
1462 if( HarvestAreaEffectOn
)
1464 for ( vector
<TDataSetRow
>::const_iterator itf
=foragers
.begin(); itf
!=foragers
.end(); ++itf
)
1466 const TDataSetRow
& rowId
= (*itf
);
1467 CEntityBase
*entity
= CEntityBaseManager::getEntityBasePtr( rowId
);
1470 // Send a warning message
1472 npcTellToPlayer( noRow
, rowId
, "FORAGE_KAMI_ANGER_PUNISH", false );
1474 // Set target list for FX (must be done before behaviour)
1475 CMirrorPropValueList
<uint32
> targets( TheDataset
, rowId
, DSPropertyTARGET_LIST
);
1477 targets
.push_front( 0 ); // null distance (self)
1478 uint32 urowId
= *((uint32
*)&rowId
);
1479 targets
.push_front( urowId
);
1481 // Set behaviour for FX (must be done after target list)
1482 MBEHAV::CBehaviour
behav( MBEHAV::CAST_OFF_SUCCESS
);
1483 behav
.Spell
.SpellMode
= MAGICFX::Bomb
;
1484 behav
.Spell
.SpellId
= MAGICFX::Piercing
;// + ForageKamiAngerPunishFX.get();
1485 behav
.Spell
.SpellIntensity
= 5;
1486 behav
.Spell
.Resist
= 0;
1487 behav
.Spell2
.SelfSpell
= 1; // 'self offensive cast' does not plays the cast anim, only impact & FX
1488 PHRASE_UTILITIES::sendUpdateBehaviour( rowId
, behav
);
1490 // tmp nico : stats about projectiles
1491 projStatsIncrement();
1494 CHarvestSource::hitEntity( RYZOMID::creature
, entity
, ForageKamiAngerPunishDamage
.get(), ForageKamiAngerPunishDamage
.get(), false );
1496 //Bsi.append( StatPath, NLMISC::toString("[FKWP] %s '%s' %.1f", entity->getId().toString().c_str(), name().c_str(), _KamiAnger) );
1497 //EgsStat.displayNL("[FKWP] %s '%s' %.1f", entity->getId().toString().c_str(), name().c_str(), _KamiAnger);
1498 // EGSPD::forageKamiWrathPunishment(entity->getId(), name(), _KamiAnger);
1502 // Don't reset the kami anger level to the min value, but nearly to the threshold 2 value!
1503 _KamiAnger
= ForageKamiAngerThreshold2
.get() - 1.0f
; // +2 will reach the threshold 2 again
1510 //NLMISC_VARIABLE( bool, VerboseDeposits, "Verbose info for deposits" );
1512 NLMISC_COMMAND( forageDisplayRecentForageSitesNb
, "Display the number of recent forage sites", "" )
1514 log
.displayNL( "%u forage sites", TotalNbRecentForageSites
);
1518 NLMISC_COMMAND( forageDisplayRecentForageSitesInfo
, "Display the info on all recent forage sites", "" )
1520 const std::vector
<CDeposit
*>& deposits
= CZoneManager::getInstance().getDeposits();
1521 std::vector
<CDeposit
*>::const_iterator it
;
1522 for ( it
=deposits
.begin(); it
!=deposits
.end(); ++it
)
1524 CDeposit
*deposit
= (*it
);
1525 deposit
->displayRecentForageSites( log
);
1530 NLMISC_COMMAND( forageEmptyAllRecentForageSites
, "Empty all forage sites", "" )
1532 const std::vector
<CDeposit
*>& deposits
= CZoneManager::getInstance().getDeposits();
1533 std::vector
<CDeposit
*>::const_iterator it
;
1534 for ( it
=deposits
.begin(); it
!=deposits
.end(); ++it
)
1536 CDeposit
*deposit
= (*it
);
1537 deposit
->depleteAllRecentForageSites();
1542 NLMISC_COMMAND( forageDisplayDeposit
, "Display info about one or all the deposits", "<name=ALL> <extendedInfo=0>" )
1544 string depName
= "ALL";
1545 bool extendedInfo
= false;
1546 if ( args
.size() > 0 )
1549 if ( args
.size() > 1 )
1550 extendedInfo
= (args
[1] == "1");
1552 CZoneManager::getInstance().dumpDeposits( log
, depName
, extendedInfo
);
1556 struct TCompareDepositsByHighestKamiAnger
: public std::binary_function
<CDeposit
*,CDeposit
*,bool>
1558 bool operator() ( const CDeposit
* d1
, const CDeposit
* d2
)
1560 return d1
->kamiAnger() > d2
->kamiAnger();
1564 NLMISC_COMMAND( forageDisplayKamiAngerLevels
, "Display the N deposits with the highest anger levels", "<N=10>" )
1567 if ( args
.size() > 0 )
1568 NLMISC::fromString(args
[0], nb
);
1570 std::vector
<CDeposit
*> newDepositList
= CZoneManager::getInstance().getDeposits();
1571 std::sort( newDepositList
.begin(), newDepositList
.end(), TCompareDepositsByHighestKamiAnger() );
1573 log
.displayNL( "%u first deposits by kami anger:", nb
);
1574 for ( uint i
=0; i
!=nb
&& i
<newDepositList
.size(); ++i
)
1576 log
.displayRawNL( "%.1f\t%s", newDepositList
[i
]->kamiAnger(), newDepositList
[i
]->name().c_str() );
1581 NLMISC_VARIABLE( bool, VerboseDepositFiltering
, "Verbose the items parsed when filtering deposits" );
1582 NLMISC_VARIABLE( bool, ExportDepositContents
, "When loading the deposit primitives, export contents report" );