#include "stdafx.h" #include "GameRule.h" #include #include //#include #include "SQuestMgr.h" namespace GameRule { float fPartyEXPRate = 1.0f; // 파티 경치 보너스 float fEXPRate = 2.0f; // 경치 비율 float fGoldDropRate = 2.0f; // 돈 드랍 비율 float fItemDropRate = 2.0f; // 아이템 드랍 비율 float fChaosDropRate = 2.0f; // 혼돈 드랍 비율 bool bMonsterWandering = true; // 플레이어가 최대로 들 수 있는 무게 float stamina_ratio[MAX_LEVEL]; int player_exp_limit[MAX_LEVEL]; int normal_summon_exp_limit[NORMAL_SUMMON_MAX_LEVEL]; int growth_summon_exp_limit[GROWTH_SUMMON_MAX_LEVEL]; int evolve_summon_exp_limit[EVOLVE_SUMMON_MAX_LEVEL]; int GetMaxWeight( int strength ) { return ( strength * 100 ) + 3000; } // 물건을 주울 수 있는 거리 int GetPickableRange() { return 20; } // 등급에 따른 아이템 레벨 제한 int GetItemLevelLimit( int item_rank ) { static int _table[] = { 0, 20, 50, 80, 100, 120, 150, 180 }; if( item_rank < 1 ) item_rank = 1; if( item_rank > 8 ) item_rank = 8; return _table[ item_rank-1 ]; } // 등급별 아이템 권장레벨 조정 테이블 int GetItemRecommendModTable( int item_rank ) { //아이템 권장 레벨 6랭크 3, 7랭크 3->2 로 변경 //hunee: 2009-08-25 static int _table[] = { //0, 3, 3, 2, 2, 2, 3, 2 0, 3, 3, 2, 2, 3, 2, 2 }; if( item_rank < 1 ) item_rank = 1; if( item_rank > 8 ) item_rank = 8; return _table[ item_rank-1 ]; } // 아이템 권장 레벨 int GetItemRecommendLevel( int item_min_level, int item_rank, int item_level ) { int ret = 0; if( item_min_level == 0 ) { if( item_rank <= 1 ) ret = 0; else ret = GetItemLevelLimit( item_rank ) + (item_level-1) * GetItemRecommendModTable( item_rank ); } else ret = item_min_level + (item_level-1) * GetItemRecommendModTable( item_rank ); ret = std::min(ret, 200); // 최대 200으로 제한. return ret; } // 아이템 권장 레벨에 따른 페널티 비율 float GetItemLevelPenalty( int creature_level, int item_min_level, int item_rank, int item_level, int item_limit_level ) { const float A = 1.0f; const float B = 0.05f; int recommend_level = GetItemRecommendLevel( item_min_level, item_rank, item_level ); int limit_level = item_limit_level; if(limit_level<=0) limit_level = GetItemLevelLimit( item_rank ); if( item_level == 1 || creature_level < limit_level || creature_level >= recommend_level ) { return 1.0f; } float result; result = static_cast< float >( (recommend_level - creature_level ) ) / ( recommend_level - limit_level ); result = result * ( A - item_level * B ); return ( 1.0f - result ); } // 내구도에 따른 페널티 비율 float GetItemEndurancePenalty( float item_endurance_percentage ) { if( item_endurance_percentage >= 0.3f ) return 1.0f; if( item_endurance_percentage >= 0.1f ) return 0.7f; if( item_endurance_percentage > 0.0f ) return 0.5f; return 0.2f; } // 수리 비용 int GetRepairCost( int item_price, int item_endurance_percentage ) { return static_cast< int >( item_price * item_endurance_percentage * 0.1 ); } // 각 레벨에 따른 성능 조정 (데미지, 방어구 동일) int GetItemValue( float item_current_value, float item_endurance_percentage, int item_rank_value, int creature_level, int item_min_level,int item_rank, int item_level, int item_limit_level ) { float v = ( item_current_value - item_rank_value ) * GetItemLevelPenalty( creature_level, item_min_level, item_rank, item_level, item_limit_level ) + item_rank_value; v = v * GetItemEndurancePenalty( item_endurance_percentage ); return static_cast< int >( v ); } int GetItemSellPrice( int price, int rank, int lv, bool isEquiment ) { if( !isEquiment ) return price; if( rank < 0 || rank >= 9 ) { assert(0); return 0; } int add_price = 0; // 표준가격 증가값 계산 (1~8랭크 모두 통합) int k = price; // 2013.06.03 - 기획팀에서 사용하고 있던 계산 테이블과 클라에서 가지고 있던 테이블이 달라 기획쪽테이블로 맞춤 float f[] = {1.35f, 0.2f, 0.115f, 0.092f, 0.085f, 0.1f, 0.1f, 0.1f}; // 랭크당 증가가격용 팩터 테이블 (from 기획팀- NPC_ItemUp.lua) for( int i = 2; i <= lv; i++ ) { if( rank == 0 ) add_price = (int)(k * f[rank ] * 0.1f) * 10; else if( rank == 1 ) add_price = (int)(k * f[rank-1] * 0.1f) * 10; else if( rank == 2 ) add_price = (int)(k * f[rank-1] * 0.01f) * 100; else add_price = (int)(k * f[rank-1] * 0.001f) * 1000; k = k + add_price; } price = k; // 최종적인 Lv별 표준가는 원래가격 + 추가가격 (Lv1일땐 add_price = 0이 할당된 상태임) return price; } bool IsValidName( const char* name, int nBufferSize, int nLimitMin, int nLimitMax ) { if( nBufferSize > nLimitMax+1 ){ nBufferSize = nLimitMax+1; } unsigned char* c = (unsigned char*)name; for( int i=0; i<=nBufferSize; i++,c++ ) { // 허용가능한 이름 if( *c == 0 ) { if( i < nLimitMin ) { return false; } else { return true; } } // 숫자, 영문의 경우는 pass if((*c >= '0' && *c <= '9') || ( *c >= 'a' && *c <= 'z' ) || ( *c >= 'A' && *c <= 'Z' )) { continue; } // 첫코드가 한글이다. if( *c >= 0xb0 && *c <= 0xc8 ) { if( (i+1) >= nBufferSize ) { return false; } c++;i++; // 두번째 코드도 한글이면 pass if( *c >= 0xa1 && *c <= 0xfe ) { continue; } } // 숫자, 영문, 한글이 아니므로 허용불가. return false; } // 제한길이를 넘어선 이름이므로 허용불가. return true; } float GetStaminaRatio( int level ) { if( !stamina_ratio[level] ) { stamina_ratio[level] = (int) ( pow( (float) (level + 2), 1.8f ) * 2 - pow( (float) (level + 2) , 1.75f ) * 2 + 2 ) * 0.2; } return stamina_ratio[level]; } int GetSummonEXPLimit( int depth, int level ) { if( depth == 1 ) // 기본형 { if( !normal_summon_exp_limit[level] ) { normal_summon_exp_limit[level] = (int)( pow( (float) level, 1.3f ) * 10.0f ) + 30; normal_summon_exp_limit[level] += (int)( normal_summon_exp_limit[level] * 0.1 * (level / 100) ); } return normal_summon_exp_limit[level]; } else if( depth == 2 ) // 성장형 { if( !growth_summon_exp_limit[level] ) { growth_summon_exp_limit[level] = (int)( pow( (float) level, 0.83f ) * 90.0f ) + 400; growth_summon_exp_limit[level] += (int)( growth_summon_exp_limit[level] * 0.1 * (level / 100) ); } return growth_summon_exp_limit[level]; } // 진화형 if( !evolve_summon_exp_limit[level] ) { evolve_summon_exp_limit[level] = (int)( pow( (float) level, 0.7f ) * 220.0f ) + 1300; evolve_summon_exp_limit[level] += (int)( evolve_summon_exp_limit[level] * 0.1 * (level / 100) ); } return evolve_summon_exp_limit[level]; } int GetPlayerEXPLimit( int level ) { if( !player_exp_limit[level] ) { player_exp_limit[level] = (int)( pow( (float) level, 1.8f ) * 5.0f ) + 40; player_exp_limit[level] += (int)( player_exp_limit[level] * 0.1 * (level / 100) ); } return player_exp_limit[level]; } float GetSummonLevelPenalty( int master_level, int summon_level ) { int level_diff = summon_level - master_level; if( level_diff > 0 ) { if( level_diff >= 30 ) { return 10.0f; } return (int) ( level_diff * 0.25f * ( 2.34f - ( level_diff / 30.0f ) ) * 10.0f ) / 10.0f; } return level_diff; } float GetOverBreedLevelPenalty( int master_level, int overbreed_level, int summon_level ) { int level_diff = overbreed_level + summon_level - master_level; if( level_diff >= 10 ) { if( level_diff >= 50 ) { return 0.0f; } return overbreed_level * ( 120 - (int) ( (level_diff + 10) * 0.25 * (2 + (level_diff +10) / 10 ) * 10 ) / 10 ) / 100; } return overbreed_level; } float GetOverBreedStatPenalty( int master_level, int overbreed_level, int summon_level ) { int level_diff = overbreed_level + summon_level - master_level; if( level_diff >= 10 ) { if( level_diff >= 50 ) { return -0.2f; } return (int)( (level_diff * -0.005 + 0.05 ) * 100 ) / 100; } return overbreed_level; } float GetSummonStatPenalty( int master_level, int summon_level ) { int level_diff = summon_level - master_level; if( level_diff > 0 ) { if( level_diff >= 50 ) { return 0.7f; } return ( (int) ( ( 50.0f - level_diff ) * 0.6f ) + 70.0f ) / 100.0f; } return 1.0f; } // sonador 0.2.2 국가별 로컬 비트셋 통합 및 유럽 분리 int GetCurrentLocalBitSet() { std::string strCountry; strCountry = ENV().GetString("country"); if( strCountry != "" ) { if( strCountry == "HK" ) return LOCAL_BITSET::HK; else if( strCountry == "US" ) return LOCAL_BITSET::US; else if( strCountry == "DE" ) return LOCAL_BITSET::DE; else if( strCountry == "JP" ) return LOCAL_BITSET::JP; else if( strCountry == "TW" ) return LOCAL_BITSET::TW; else if( strCountry == "CN" ) return LOCAL_BITSET::CN; else if( strCountry == "FR" ) return LOCAL_BITSET::FR; else if( strCountry == "RU" ) // #2.4.9.6 return LOCAL_BITSET::RU; else if( strCountry == "MASG" ) return LOCAL_BITSET::MASG; // Malaysia (Singapore) else if( strCountry == "PH" ) return LOCAL_BITSET::PH; // 필리핀 else if( strCountry == "VN" ) return LOCAL_BITSET::VN; // 베트남 else if( strCountry == "TL" ) return LOCAL_BITSET::TL; // 태국 else if( strCountry == "ME" ) return LOCAL_BITSET::ME; // 중동 else if( strCountry == "TR" ) return LOCAL_BITSET::TR; // 터키 else if( strCountry == "PL" ) return LOCAL_BITSET::PL; // 폴란드 else if( strCountry == "IT" ) return LOCAL_BITSET::IT; // 이탈리아 else if( strCountry == "BR" ) return LOCAL_BITSET::BR; // 2010.09.08 브라질 - prodongi else if (strCountry == "ES") return LOCAL_BITSET::ES; /// 2011.03.17 스페인 - prodongi else if (strCountry == "ID") return LOCAL_BITSET::ID; /// 2011.07.25 인도네시아 - prodongi } return LOCAL_BITSET::KR; } // 2010.07.12 - prodongi bool isSoutheastAsia() { int bitset = GetCurrentLocalBitSet(); if (LOCAL_BITSET::TW == bitset || LOCAL_BITSET::MASG == bitset || LOCAL_BITSET::PH == bitset || LOCAL_BITSET::VN == bitset || LOCAL_BITSET::TL == bitset) return true; return false; } /// 2011.10.07 - prodongi bool isEurope() { int bitset = GetCurrentLocalBitSet(); if (LOCAL_BITSET::DE == bitset || LOCAL_BITSET::FR == bitset || LOCAL_BITSET::TR == bitset || LOCAL_BITSET::PL == bitset || LOCAL_BITSET::IT == bitset) return true; return false; } // #2.3.1.8 sonador c_fixed10 GetQuestRewardFactor( QuestBase* questBase ) { //랜덤 퀘일 경우 계산됨 if( questBase->nType == QuestBase::QUEST_RANDOM_KILL_INDIVIDUAL || questBase->nType == QuestBase::QUEST_RANDOM_COLLECT ) { int nCount1 = SQuestMgr::GetInstance().GetQuestRandomValue( questBase->nCode, 2-1 ); int nCount2 = SQuestMgr::GetInstance().GetQuestRandomValue( questBase->nCode, 4-1 ); int nCount3 = SQuestMgr::GetInstance().GetQuestRandomValue( questBase->nCode, 6-1 ); c_fixed10 fValue1 = c_fixed10( questBase->nValue[ 4-1 ] ) / 100.f; c_fixed10 fValue2 = c_fixed10( questBase->nValue[ 8-1 ] ) / 100.f; c_fixed10 fValue3 = c_fixed10( questBase->nValue[ 12-1] ) / 100.f; return ( ( fValue1 * nCount1 ) + ( fValue2 * nCount2 ) + ( fValue3 * nCount3 ) ); } return 1.f; } // #2.1.2.6.1 const char* GetSetPartCompositionSlotOnEmoticonByPartId( int partId ) { switch( partId ) { case SETPART_NONE: return ""; case SETPART_ARMO: return "#@SETPART_ARMO_ON@#"; case SETPART_WEAPON1: case SETPART_WEAPON2: case SETPART_WEAPON3: case SETPART_WEAPON4: case SETPART_TWOHAND_WEAPON1: case SETPART_TWOHAND_WEAPON2: case SETPART_SHEILD: return "#@SETPART_HAND_ON@#"; case SETPART_HELM: return "#@SETPART_HELM_ON@#"; default: return ""; } return ""; } const char* GetSetPartCompositionSlotOffEmoticonByPartId( int partId ) { switch( partId ) { case SETPART_NONE: return ""; case SETPART_ARMO: return "#@SETPART_ARMO_OFF@#"; case SETPART_WEAPON1: case SETPART_WEAPON2: case SETPART_WEAPON3: case SETPART_WEAPON4: case SETPART_TWOHAND_WEAPON1: case SETPART_TWOHAND_WEAPON2: case SETPART_SHEILD: return "#@SETPART_HAND_OFF@#"; case SETPART_HELM: return "#@SETPART_HELM_OFF@#"; default: return ""; } return ""; } };