diff --git a/ryzom/server/src/entities_game_service/egs_sheets/egs_static_brick.cpp b/ryzom/server/src/entities_game_service/egs_sheets/egs_static_brick.cpp index 92356286a..a287a8721 100644 --- a/ryzom/server/src/entities_game_service/egs_sheets/egs_static_brick.cpp +++ b/ryzom/server/src/entities_game_service/egs_sheets/egs_static_brick.cpp @@ -110,6 +110,7 @@ void CStaticBrick::serial(class NLMISC::IStream &f) f.serial(ForbiddenExclude); f.serialCont( LearnRequiresOneOfSkills ); + f.serialCont( LearnRequiresSkills ); f.serialCont( LearnRequiresBricks ); f.serialEnum( CivRestriction ); f.serial( Faction ); @@ -421,6 +422,23 @@ void CStaticBrick::readStaticBrick( const NLGEORGES::UFormElm &root, const NLMIS nlwarning( " Invalid LearnRequiresOneOfSkills value '%s' in sheet %s", sav.c_str(), sheetId.toString().c_str() ); } + // LearnRequiresSkills + if ( ! root.getValueByName (value, "Basics.LearnRequiresSkills") ) + { + nlwarning(" can't get the value 'LearnRequireSkills' for sheet %s", sheetId.toString().c_str() ); + } + skillsAndValues.clear(); + explode( value, string(":"), skillsAndValues, true ); + for ( vector::const_iterator isv=skillsAndValues.begin(); isv!=skillsAndValues.end(); ++isv ) + { + const string& sav = *isv; + CPlayerSkill ps; + if ( ps.initFromString( sav ) ) // discard the skill if unknown + LearnRequiresSkills.push_back( ps ); + else + nlwarning( " Invalid LearnRequiresSkills value '%s' in sheet %s", sav.c_str(), sheetId.toString().c_str() ); + } + // LearnRequiresBricks if ( ! root.getValueByName (value, "Basics.LearnRequiresBricks") ) { diff --git a/ryzom/server/src/entities_game_service/egs_sheets/egs_static_brick.h b/ryzom/server/src/entities_game_service/egs_sheets/egs_static_brick.h index 2eef41e0d..06be549ca 100644 --- a/ryzom/server/src/entities_game_service/egs_sheets/egs_static_brick.h +++ b/ryzom/server/src/entities_game_service/egs_sheets/egs_static_brick.h @@ -393,6 +393,9 @@ public: /// Skills required to learn the brick (OR) std::vector LearnRequiresOneOfSkills; + /// Skills required to learn the brick (AND: all of them are required) + std::vector LearnRequiresSkills; + /// Bricks required to learn the brick (AND: all of them are required) std::vector LearnRequiresBricks; diff --git a/ryzom/server/src/entities_game_service/phrase_manager/available_phrases.cpp b/ryzom/server/src/entities_game_service/phrase_manager/available_phrases.cpp index 7d4af6d78..436533e39 100644 --- a/ryzom/server/src/entities_game_service/phrase_manager/available_phrases.cpp +++ b/ryzom/server/src/entities_game_service/phrase_manager/available_phrases.cpp @@ -55,6 +55,26 @@ inline bool skillRequiredAreBelowSkillValueLimit( uint skillValueLimit, const ve } +/* + * Find in skillsRequiredList that all skills are lower (by value) than the provided limit value + */ +inline bool skillsAreBelowSkillValueLimit( uint skillValueLimit, const vector& skillsRequiredList ) +{ + H_AUTO(skillsAreBelowSkillValueLimit); + vector::const_iterator irs; + for ( irs=skillsRequiredList.begin(); irs!=skillsRequiredList.end(); ++irs ) + { + const CPlayerSkill& requiredSkill = *irs; + if ( ! requiredSkill.isSkillValueLowerThan( skillValueLimit ) ) + { + return false; + } + } + return true; +} + + + /* * Find in the player skill list has at least one skill that is higher than the provided skill. * @@ -87,6 +107,26 @@ inline bool skillRequiredMatchPlayerSkills( const vector& playerSkills, } +/* + * Find in skillsRequiredList that all skills match in player skills + * + * Precondition: + * - skillsRequiredList contains valid skills (not unknown) + */ +inline bool skillsMatchPlayerSkills( const vector& playerSkills, const vector& skillsRequiredList ) +{ + H_AUTO(skillsMatchPlayerSkills); + vector::const_iterator irs; + for ( irs=skillsRequiredList.begin(); irs!=skillsRequiredList.end(); ++irs ) + { + const CPlayerSkill& requiredSkill = *irs; + if ( ! skillMatchesOneOfList( requiredSkill, playerSkills ) ) + return false; + } + return true; +} + + /* * Check character fame against brick fame * @@ -176,6 +216,16 @@ bool isPlayerAllowedToGetAllBricksFromPhrase( const CEntityId& eid, return false; } + if ( ! staticBrick->LearnRequiresSkills.empty() ) + { + // Check if the brick is below or equal the skill value limit + if ( ! skillsAreBelowSkillValueLimit( skillValueLimit, staticBrick->LearnRequiresSkills ) ) + return false; + // Check if all of the skills match one of the player's + if ( ! skillsMatchPlayerSkills( playerSkills, staticBrick->LearnRequiresSkills ) ) + return false; + } + // Check if one of the fame required doesn't match with brick min fame value if ( ! fameRequiredMatchPlayerFaction( eid, staticBrick->Faction, staticBrick->MinFameValue ) ) return false; diff --git a/ryzom/server/src/entities_game_service/phrase_manager/fg_extraction_phrase.cpp b/ryzom/server/src/entities_game_service/phrase_manager/fg_extraction_phrase.cpp index 6f372bd70..f98965486 100644 --- a/ryzom/server/src/entities_game_service/phrase_manager/fg_extraction_phrase.cpp +++ b/ryzom/server/src/entities_game_service/phrase_manager/fg_extraction_phrase.cpp @@ -219,6 +219,7 @@ bool CFgExtractionPhrase::build( const TDataSetRow & actorRowId, const std::vect case TBrickParam::FG_ECT_SPC: INFOLOG("FG_ECT_SPC: %s",((CSBrickParamForageEcotypeSpec *)param)->Ecotype.c_str()); _Props.Extraction.EcotypeSpec = ECOSYSTEM::stringToEcosystem( ((CSBrickParamForageEcotypeSpec *)param)->Ecotype ); + _Props.Extraction.EcotypeSpecBonus = true; break; case TBrickParam::FG_RMGRP_FILT: INFOLOG("FG_RMGRP_FILT: %i",((CSBrickParamForageRMGroupFilter *)param)->Value); @@ -294,7 +295,7 @@ bool CFgExtractionPhrase::build( const TDataSetRow & actorRowId, const std::vect // else the phrase will be rejected in validate() } - // Bonus: when using ecosystem specialization, decrease impact on some risks (TODO: linearly dependant on specialized skill value). + // when using ecosystem specialization if ( _Props.Extraction.EcotypeSpec != ECOSYSTEM::common_ecosystem ) { // Check if the ecotype specialization matches @@ -303,6 +304,11 @@ bool CFgExtractionPhrase::build( const TDataSetRow & actorRowId, const std::vect PHRASE_UTILITIES::sendDynamicSystemMessage( _ActorRowId, "FORAGE_ECOTYPE_SPEC_NOT_MATCHING" ); return false; } + } + + // Bonus: when using ecosystem/atys specialization, decrease impact on some risks (TODO: linearly dependant on specialized skill value). + if ( _Props.Extraction.EcotypeSpecBonus ) + { if ( _RequestedProps[CHarvestSource::A] != 0 ) { // Extraction diff --git a/ryzom/server/src/entities_game_service/phrase_manager/fg_extraction_phrase.h b/ryzom/server/src/entities_game_service/phrase_manager/fg_extraction_phrase.h index ecbdefadf..a4ebd11c0 100644 --- a/ryzom/server/src/entities_game_service/phrase_manager/fg_extraction_phrase.h +++ b/ryzom/server/src/entities_game_service/phrase_manager/fg_extraction_phrase.h @@ -136,6 +136,9 @@ private: /// Factor for increase speed of quality float QualitySlowFactor; + /// True if terrain specialization or Atys specialization is used + bool EcotypeSpecBonus; + } Extraction; struct diff --git a/ryzom/server/src/entities_game_service/phrase_manager/fg_prospection_phrase.cpp b/ryzom/server/src/entities_game_service/phrase_manager/fg_prospection_phrase.cpp index 53d1674ce..6b963513f 100644 --- a/ryzom/server/src/entities_game_service/phrase_manager/fg_prospection_phrase.cpp +++ b/ryzom/server/src/entities_game_service/phrase_manager/fg_prospection_phrase.cpp @@ -289,6 +289,7 @@ bool CFgSearchPhrase::build( const TDataSetRow & actorRowId, const std::vector< case TBrickParam::FG_ECT_SPC: INFOLOG("FG_ECT_SPC: %s",((CSBrickParamForageEcotypeSpec *)param)->Ecotype.c_str()); _EcotypeSpec = ECOSYSTEM::stringToEcosystem( ((CSBrickParamForageEcotypeSpec *)param)->Ecotype ); + _EcotypeSpecBonus = true; break; case TBrickParam::FG_RMGRP_FILT: INFOLOG("FG_RMGRP_FILT: %i",((CSBrickParamForageRMGroupFilter *)param)->Value); @@ -800,7 +801,7 @@ uint CFgProspectionPhrase::generateSources( CCharacter *player ) CVector2f pos2f = pos; if ( hsource->init( _SourceIniProperties, pos2f, forageSite, depositForK, rawMaterial, quantityRatio ) ) { - if ( _EcotypeSpec != ECOSYSTEM::common_ecosystem ) + if ( _EcotypeSpecBonus ) hsource->setBonusForA( 20 ); if ( hsource->spawnBegin( _KnowledgePrecision, player->getEntityRowId(), false ) ) @@ -1030,7 +1031,7 @@ void CFgProspectionPhrase::startLocateDeposit( CCharacter *player ) CVector2f locatedPoint( retainedLoc->NearestPos ); TReportAction report; sint32 effectFocusCostByUpdate = _FocusCost / ForageFocusRatioOfLocateDeposit.get(); - if ( _EcotypeSpec != ECOSYSTEM::common_ecosystem ) + if ( _EcotypeSpecBonus ) effectFocusCostByUpdate /= 2; // lower focus consumption with terrain specialization CSEffectLocateDeposit *effect = new CSEffectLocateDeposit( player->getEntityRowId(), diff --git a/ryzom/server/src/entities_game_service/phrase_manager/fg_prospection_phrase.h b/ryzom/server/src/entities_game_service/phrase_manager/fg_prospection_phrase.h index 0ea9db921..620ab8782 100644 --- a/ryzom/server/src/entities_game_service/phrase_manager/fg_prospection_phrase.h +++ b/ryzom/server/src/entities_game_service/phrase_manager/fg_prospection_phrase.h @@ -144,6 +144,9 @@ protected: // because CSearchPhrase is a common trunc /// Locator enabled bool _IsLocateDepositProspection; + + /// True if terrain specialization or Atys specialization is used + bool _EcotypeSpecBonus; };