convert comments to utf-8

This commit is contained in:
sdgmt2 2024-04-05 23:34:45 +02:00
parent 4a1460f36e
commit eacc808366
No known key found for this signature in database
114 changed files with 2214 additions and 2214 deletions

View File

@ -237,7 +237,7 @@ void CDragonLairManager::OnDragonDead(LPCHARACTER pDragon, DWORD KillerGuildID)
iter->second->OnDragonDead( pDragon ); iter->second->OnDragonDead( pDragon );
// 애들 다 집으로 보내고 맵 없애기 // 애들 다 집으로 보내고 맵 없애기
tag_DragonLair_Collapse_EventInfo* info; tag_DragonLair_Collapse_EventInfo* info;
info = AllocEventInfo<tag_DragonLair_Collapse_EventInfo>(); info = AllocEventInfo<tag_DragonLair_Collapse_EventInfo>();

View File

@ -31,7 +31,7 @@ int Gamble(std::vector<float>& vec_probs)
return -1; return -1;
} }
// 가중치 테이블(prob_lst)을 받아 random_set.size()개의 index를 선택하여 random_set을 return // 가중치 테이블(prob_lst)을 받아 random_set.size()개의 index를 선택하여 random_set을 return
bool MakeDistinctRandomNumberSet(std::list <float> prob_lst, OUT std::vector<int>& random_set) bool MakeDistinctRandomNumberSet(std::list <float> prob_lst, OUT std::vector<int>& random_set)
{ {
int size = prob_lst.size(); int size = prob_lst.size();
@ -67,11 +67,11 @@ bool MakeDistinctRandomNumberSet(std::list <float> prob_lst, OUT std::vector<int
return true; return true;
} }
/* 용혼석 Vnum에 대한 comment /* 용혼석 Vnum에 대한 comment
* ITEM VNUM을 10만 자리부터, FEDCBA라고 한다면 * ITEM VNUM을 10만 자리부터, FEDCBA라고 한다면
* FE : 용혼석 종류. D : 등급 * FE : 용혼석 종류. D : 등급
* C : 단계 B : 강화 * C : 단계 B : 강화
* A : 여벌의 번호들... * A : 여벌의 번호들...
*/ */
BYTE GetType(DWORD dwVnum) BYTE GetType(DWORD dwVnum)
@ -169,7 +169,7 @@ bool DSManager::RefreshItemAttributes(LPITEM pDS)
return false; return false;
} }
// add_min과 add_max는 더미로 읽음. // add_min과 add_max는 더미로 읽음.
int basic_apply_num, add_min, add_max; int basic_apply_num, add_min, add_max;
if (!m_pTable->GetApplyNumSettings(ds_type, grade_idx, basic_apply_num, add_min, add_max)) if (!m_pTable->GetApplyNumSettings(ds_type, grade_idx, basic_apply_num, add_min, add_max))
{ {
@ -315,7 +315,7 @@ int DSManager::GetDuration(const LPITEM pItem) const
return pItem->GetDuration(); return pItem->GetDuration();
} }
// 용혼석을 받아서 용심을 추출하는 함수 // 용혼석을 받아서 용심을 추출하는 함수
bool DSManager::ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtractor) bool DSManager::ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtractor)
{ {
if (NULL == ch || NULL == pItem) if (NULL == ch || NULL == pItem)
@ -397,7 +397,7 @@ bool DSManager::ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtract
} }
} }
// 특정 용혼석을 장비창에서 제거할 때에 성공 여부를 결정하고, 실패시 부산물을 주는 함수. // 특정 용혼석을 장비창에서 제거할 때에 성공 여부를 결정하고, 실패시 부산물을 주는 함수.
bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM pExtractor) bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM pExtractor)
{ {
if (NULL == ch || NULL == pItem) if (NULL == ch || NULL == pItem)
@ -406,7 +406,7 @@ bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM
return false; return false;
} }
// 목표 위치가 valid한지 검사 후, valid하지 않다면 임의의 빈 공간을 찾는다. // 목표 위치가 valid한지 검사 후, valid하지 않다면 임의의 빈 공간을 찾는다.
if (!IsValidCellForThisItem(pItem, DestCell)) if (!IsValidCellForThisItem(pItem, DestCell))
{ {
int iEmptyCell = ch->GetEmptyDragonSoulInventory(pItem); int iEmptyCell = ch->GetEmptyDragonSoulInventory(pItem);
@ -430,14 +430,14 @@ bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM
int iBonus = 0; int iBonus = 0;
float fProb; float fProb;
float fDice; float fDice;
// 용혼석 추출 성공 여부 결정. // 용혼석 추출 성공 여부 결정.
{ {
DWORD dwVnum = pItem->GetVnum(); DWORD dwVnum = pItem->GetVnum();
BYTE ds_type, grade_idx, step_idx, strength_idx; BYTE ds_type, grade_idx, step_idx, strength_idx;
GetDragonSoulInfo(pItem->GetVnum(), ds_type, grade_idx, step_idx, strength_idx); GetDragonSoulInfo(pItem->GetVnum(), ds_type, grade_idx, step_idx, strength_idx);
// 추출 정보가 없다면 일단 무조건 성공하는 것이라 생각하자. // 추출 정보가 없다면 일단 무조건 성공하는 것이라 생각하자.
if (!m_pTable->GetDragonSoulExtValues(ds_type, grade_idx, fProb, dwByProduct)) if (!m_pTable->GetDragonSoulExtValues(ds_type, grade_idx, fProb, dwByProduct))
{ {
pItem->AddToCharacter(ch, DestCell); pItem->AddToCharacter(ch, DestCell);
@ -454,7 +454,7 @@ bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM
bSuccess = fDice <= (fProb * (100 + iBonus) / 100.f); bSuccess = fDice <= (fProb * (100 + iBonus) / 100.f);
} }
// 캐릭터의 용혼석 추출 및 추가 혹은 제거. 부산물 제공. // 캐릭터의 용혼석 추출 및 추가 혹은 제거. 부산물 제공.
{ {
char buf[128]; char buf[128];
@ -519,8 +519,8 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
return false; return false;
} }
// 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용 // 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용
// 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다. // 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다.
std::set <LPITEM> set_items; std::set <LPITEM> set_items;
for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++) for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++)
{ {
@ -529,7 +529,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
LPITEM pItem = ch->GetItem(aItemPoses[i]); LPITEM pItem = ch->GetItem(aItemPoses[i]);
if (NULL != pItem) if (NULL != pItem)
{ {
// 용혼석이 아닌 아이템이 개량창에 있을 수 없다. // 용혼석이 아닌 아이템이 개량창에 있을 수 없다.
if (!pItem->IsDragonSoul()) if (!pItem->IsDragonSoul())
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB5\xEE\xB1\xDE \xB0\xB3\xB7\xAE\xBF\xA1 \xC7\xCA\xBF\xE4\xC7\xD1 \xC0\xE7\xB7\xE1\xB0\xA1 \xBE\xC6\xB4\xD5\xB4\xCF\xB4\xD9.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB5\xEE\xB1\xDE \xB0\xB3\xB7\xAE\xBF\xA1 \xC7\xCA\xBF\xE4\xC7\xD1 \xC0\xE7\xB7\xE1\xB0\xA1 \xBE\xC6\xB4\xD5\xB4\xCF\xB4\xD9."));
@ -557,7 +557,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
BYTE ds_type, grade_idx, step_idx, strength_idx; BYTE ds_type, grade_idx, step_idx, strength_idx;
int result_grade; int result_grade;
// 가장 처음 것을 강화의 기준으로 삼는다. // 가장 처음 것을 강화의 기준으로 삼는다.
std::set <LPITEM>::iterator it = set_items.begin(); std::set <LPITEM>::iterator it = set_items.begin();
{ {
LPITEM pItem = *it; LPITEM pItem = *it;
@ -576,8 +576,8 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
{ {
LPITEM pItem = *it; LPITEM pItem = *it;
// 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에, // 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에,
// 별도의 알림 처리는 안함. // 별도의 알림 처리는 안함.
if (pItem->IsEquipped()) if (pItem->IsEquipped())
{ {
return false; return false;
@ -592,7 +592,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
} }
} }
// 클라에서 한번 갯수 체크를 하기 때문에 count != need_count라면 invalid 클라일 가능성이 크다. // 클라에서 한번 갯수 체크를 하기 때문에 count != need_count라면 invalid 클라일 가능성이 크다.
if (count != need_count) if (count != need_count)
{ {
SPDLOG_ERROR("Possiblity of invalid client. Name {}", ch->GetName()); SPDLOG_ERROR("Possiblity of invalid client. Name {}", ch->GetName());
@ -679,15 +679,15 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_
return false; return false;
} }
// 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용 // 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용
// 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다. // 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다.
std::set <LPITEM> set_items; std::set <LPITEM> set_items;
for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++) for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++)
{ {
LPITEM pItem = ch->GetItem(aItemPoses[i]); LPITEM pItem = ch->GetItem(aItemPoses[i]);
if (NULL != pItem) if (NULL != pItem)
{ {
// 용혼석이 아닌 아이템이 개량창에 있을 수 없다. // 용혼석이 아닌 아이템이 개량창에 있을 수 없다.
if (!pItem->IsDragonSoul()) if (!pItem->IsDragonSoul())
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB4\xDC\xB0\xE8 \xB0\xB3\xB7\xAE\xBF\xA1 \xC7\xCA\xBF\xE4\xC7\xD1 \xC0\xE7\xB7\xE1\xB0\xA1 \xBE\xC6\xB4\xD5\xB4\xCF\xB4\xD9.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB4\xDC\xB0\xE8 \xB0\xB3\xB7\xAE\xBF\xA1 \xC7\xCA\xBF\xE4\xC7\xD1 \xC0\xE7\xB7\xE1\xB0\xA1 \xBE\xC6\xB4\xD5\xB4\xCF\xB4\xD9."));
@ -713,7 +713,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_
BYTE ds_type, grade_idx, step_idx, strength_idx; BYTE ds_type, grade_idx, step_idx, strength_idx;
int result_step; int result_step;
// 가장 처음 것을 강화의 기준으로 삼는다. // 가장 처음 것을 강화의 기준으로 삼는다.
std::set <LPITEM>::iterator it = set_items.begin(); std::set <LPITEM>::iterator it = set_items.begin();
{ {
LPITEM pItem = *it; LPITEM pItem = *it;
@ -730,8 +730,8 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_
while(++it != set_items.end()) while(++it != set_items.end())
{ {
LPITEM pItem = *it; LPITEM pItem = *it;
// 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에, // 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에,
// 별도의 알림 처리는 안함. // 별도의 알림 처리는 안함.
if (pItem->IsEquipped()) if (pItem->IsEquipped())
{ {
return false; return false;
@ -744,7 +744,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_
} }
} }
// 클라에서 한번 갯수 체크를 하기 때문에 count != need_count라면 invalid 클라일 가능성이 크다. // 클라에서 한번 갯수 체크를 하기 때문에 count != need_count라면 invalid 클라일 가능성이 크다.
if (count != need_count) if (count != need_count)
{ {
SPDLOG_ERROR("Possiblity of invalid client. Name {}", ch->GetName()); SPDLOG_ERROR("Possiblity of invalid client. Name {}", ch->GetName());
@ -840,8 +840,8 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S
return false; return false;
} }
// 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용 // 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용
// 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다. // 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다.
std::set <LPITEM> set_items; std::set <LPITEM> set_items;
for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++) for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++)
{ {
@ -863,15 +863,15 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S
for (std::set <LPITEM>::iterator it = set_items.begin(); it != set_items.end(); it++) for (std::set <LPITEM>::iterator it = set_items.begin(); it != set_items.end(); it++)
{ {
LPITEM pItem = *it; LPITEM pItem = *it;
// 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에, // 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에,
// 별도의 알림 처리는 안함. // 별도의 알림 처리는 안함.
if (pItem->IsEquipped()) if (pItem->IsEquipped())
{ {
return false; return false;
} }
// 용혼석과 강화석만이 개량창에 있을 수 있다. // 용혼석과 강화석만이 개량창에 있을 수 있다.
// 그리고 하나씩만 있어야한다. // 그리고 하나씩만 있어야한다.
if (pItem->IsDragonSoul()) if (pItem->IsDragonSoul())
{ {
if (pDragonSoul != NULL) if (pDragonSoul != NULL)
@ -912,14 +912,14 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S
GetDragonSoulInfo(pDragonSoul->GetVnum(), bType, bGrade, bStep, bStrength); GetDragonSoulInfo(pDragonSoul->GetVnum(), bType, bGrade, bStep, bStrength);
float fWeight = 0.f; float fWeight = 0.f;
// 가중치 값이 없다면 강화할 수 없는 용혼석 // 가중치 값이 없다면 강화할 수 없는 용혼석
if (!m_pTable->GetWeight(bType, bGrade, bStep, bStrength + 1, fWeight)) if (!m_pTable->GetWeight(bType, bGrade, bStep, bStrength + 1, fWeight))
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB0\xAD\xC8\xAD\xC7\xD2 \xBC\xF6 \xBE\xF8\xB4\xC2 \xBF\xEB\xC8\xA5\xBC\xAE\xC0\xD4\xB4\xCF\xB4\xD9.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB0\xAD\xC8\xAD\xC7\xD2 \xBC\xF6 \xBE\xF8\xB4\xC2 \xBF\xEB\xC8\xA5\xBC\xAE\xC0\xD4\xB4\xCF\xB4\xD9."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell())); SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell()));
return false; return false;
} }
// 강화했을 때 가중치가 0이라면 더 이상 강화되서는 안된다. // 강화했을 때 가중치가 0이라면 더 이상 강화되서는 안된다.
if (fWeight < FLT_EPSILON) if (fWeight < FLT_EPSILON)
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB0\xAD\xC8\xAD\xC7\xD2 \xBC\xF6 \xBE\xF8\xB4\xC2 \xBF\xEB\xC8\xA5\xBC\xAE\xC0\xD4\xB4\xCF\xB4\xD9.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB0\xAD\xC8\xAD\xC7\xD2 \xBC\xF6 \xBE\xF8\xB4\xC2 \xBF\xEB\xC8\xA5\xBC\xAE\xC0\xD4\xB4\xCF\xB4\xD9."));
@ -988,7 +988,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S
char buf[128]; char buf[128];
sprintf(buf, "STRENGTH : %d -> %d", bStrength, bStrength - 1); sprintf(buf, "STRENGTH : %d -> %d", bStrength, bStrength - 1);
// strength강화는 실패시 깨질 수도 있어, 원본 아이템을 바탕으로 로그를 남김. // strength강화는 실패시 깨질 수도 있어, 원본 아이템을 바탕으로 로그를 남김.
LogManager::instance().ItemLog(ch, pDragonSoul, "DS_STRENGTH_REFINE_FAIL", buf); LogManager::instance().ItemLog(ch, pDragonSoul, "DS_STRENGTH_REFINE_FAIL", buf);
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB0\xAD\xC8\xAD\xBF\xA1 \xBD\xC7\xC6\xD0\xC7\xDF\xBD\xC0\xB4\xCF\xB4\xD9.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB0\xAD\xC8\xAD\xBF\xA1 \xBD\xC7\xC6\xD0\xC7\xDF\xBD\xC0\xB4\xCF\xB4\xD9."));
@ -1029,12 +1029,12 @@ int DSManager::LeftTime(LPITEM pItem) const
if (pItem == NULL) if (pItem == NULL)
return false; return false;
// 일단은 timer based on wear인 용혼석만 시간 다 되어도 안 없어진다. // 일단은 timer based on wear인 용혼석만 시간 다 되어도 안 없어진다.
if (pItem->GetProto()->cLimitTimerBasedOnWearIndex >= 0) if (pItem->GetProto()->cLimitTimerBasedOnWearIndex >= 0)
{ {
return pItem->GetSocket(ITEM_SOCKET_REMAIN_SEC); return pItem->GetSocket(ITEM_SOCKET_REMAIN_SEC);
} }
// 다른 limit type인 용혼석들은 시간 되면 모두 사라지기 때문에 여기 들어온 아이템은 일단 시간이 남았다고 판단. // 다른 limit type인 용혼석들은 시간 되면 모두 사라지기 때문에 여기 들어온 아이템은 일단 시간이 남았다고 판단.
else else
{ {
return INT_MAX; return INT_MAX;
@ -1046,12 +1046,12 @@ bool DSManager::IsTimeLeftDragonSoul(LPITEM pItem) const
if (pItem == NULL) if (pItem == NULL)
return false; return false;
// 일단은 timer based on wear인 용혼석만 시간 다 되어도 안 없어진다. // 일단은 timer based on wear인 용혼석만 시간 다 되어도 안 없어진다.
if (pItem->GetProto()->cLimitTimerBasedOnWearIndex >= 0) if (pItem->GetProto()->cLimitTimerBasedOnWearIndex >= 0)
{ {
return pItem->GetSocket(ITEM_SOCKET_REMAIN_SEC) > 0; return pItem->GetSocket(ITEM_SOCKET_REMAIN_SEC) > 0;
} }
// 다른 limit type인 용혼석들은 시간 되면 모두 사라지기 때문에 여기 들어온 아이템은 일단 시간이 남았다고 판단. // 다른 limit type인 용혼석들은 시간 되면 모두 사라지기 때문에 여기 들어온 아이템은 일단 시간이 남았다고 판단.
else else
{ {
return true; return true;

View File

@ -30,14 +30,14 @@ static Pixel * LoadOldGuildMarkImageFile()
bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID) bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
{ {
// 폴더 생성 // 폴더 생성
#ifndef __WIN32__ #ifndef __WIN32__
mkdir("mark", S_IRWXU); mkdir("mark", S_IRWXU);
#else #else
_mkdir("mark"); _mkdir("mark");
#endif #endif
// 인덱스 파일이 있나? // 인덱스 파일이 있나?
#ifndef __WIN32__ #ifndef __WIN32__
if (0 != access(OLD_MARK_INDEX_FILENAME, F_OK)) if (0 != access(OLD_MARK_INDEX_FILENAME, F_OK))
#else #else
@ -45,13 +45,13 @@ bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
#endif #endif
return true; return true;
// 인덱스 파일 열기 // 인덱스 파일 열기
FILE* fp = fopen(OLD_MARK_INDEX_FILENAME, "r"); FILE* fp = fopen(OLD_MARK_INDEX_FILENAME, "r");
if (NULL == fp) if (NULL == fp)
return false; return false;
// 이미지 파일 열기 // 이미지 파일 열기
Pixel * oldImagePtr = LoadOldGuildMarkImageFile(); Pixel * oldImagePtr = LoadOldGuildMarkImageFile();
if (NULL == oldImagePtr) if (NULL == oldImagePtr)
@ -61,8 +61,8 @@ bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
} }
/* /*
// guild_mark.tga가 실제 targa 파일이 아니고, 512 * 512 * 4 크기의 raw 파일이다. // guild_mark.tga가 실제 targa 파일이 아니고, 512 * 512 * 4 크기의 raw 파일이다.
// 눈으로 확인하기 위해 실제 targa 파일로 만든다. // 눈으로 확인하기 위해 실제 targa 파일로 만든다.
CGuildMarkImage * pkImage = new CGuildMarkImage; CGuildMarkImage * pkImage = new CGuildMarkImage;
pkImage->Build("guild_mark_real.tga"); pkImage->Build("guild_mark_real.tga");
pkImage->Load("guild_mark_real.tga"); pkImage->Load("guild_mark_real.tga");
@ -86,7 +86,7 @@ bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
continue; continue;
} }
// mark id -> 이미지에서의 위치 찾기 // mark id -> 이미지에서의 위치 찾기
uint row = mark_id / 32; uint row = mark_id / 32;
uint col = mark_id % 32; uint col = mark_id % 32;
@ -102,7 +102,7 @@ bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
Pixel * src = oldImagePtr + sy * 512 + sx; Pixel * src = oldImagePtr + sy * 512 + sx;
Pixel * dst = mark; Pixel * dst = mark;
// 옛날 이미지에서 마크 한개 복사 // 옛날 이미지에서 마크 한개 복사
for (int y = 0; y != SGuildMark::HEIGHT; ++y) for (int y = 0; y != SGuildMark::HEIGHT; ++y)
{ {
for (int x = 0; x != SGuildMark::WIDTH; ++x) for (int x = 0; x != SGuildMark::WIDTH; ++x)
@ -111,7 +111,7 @@ bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
src += 512; src += 512;
} }
// 새 길드 마크 시스템에 넣는다. // 새 길드 마크 시스템에 넣는다.
CGuildMarkManager::instance().SaveMark(guild_id, (BYTE *) mark); CGuildMarkManager::instance().SaveMark(guild_id, (BYTE *) mark);
line[0] = '\0'; line[0] = '\0';
} }
@ -119,7 +119,7 @@ bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
free(oldImagePtr); free(oldImagePtr);
fclose(fp); fclose(fp);
// 컨버트는 한번만 하면되므로 파일을 옮겨준다. // 컨버트는 한번만 하면되므로 파일을 옮겨준다.
#ifndef __WIN32__ #ifndef __WIN32__
system("mv -f guild_mark.idx guild_mark.idx.removable"); system("mv -f guild_mark.idx guild_mark.idx.removable");
system("mv -f guild_mark.tga guild_mark.tga.removable"); system("mv -f guild_mark.tga guild_mark.tga.removable");

View File

@ -129,10 +129,10 @@ void CGuildMarkImage::GetData(UINT x, UINT y, UINT width, UINT height, void * da
ilCopyPixels(x, y, 0, width, height, 1, IL_BGRA, IL_UNSIGNED_BYTE, data); ilCopyPixels(x, y, 0, width, height, 1, IL_BGRA, IL_UNSIGNED_BYTE, data);
} }
// 이미지 = 512x512 // 이미지 = 512x512
// 블럭 = 마크 4 x 4 // 블럭 = 마크 4 x 4
// 마크 = 16 x 12 // 마크 = 16 x 12
// 한 이미지의 블럭 = 8 x 10 // 한 이미지의 블럭 = 8 x 10
// SERVER // SERVER
bool CGuildMarkImage::SaveMark(DWORD posMark, BYTE * pbImage) bool CGuildMarkImage::SaveMark(DWORD posMark, BYTE * pbImage)
@ -143,14 +143,14 @@ bool CGuildMarkImage::SaveMark(DWORD posMark, BYTE * pbImage)
return false; return false;
} }
// 마크를 전체 이미지에 그린다. // 마크를 전체 이미지에 그린다.
DWORD colMark = posMark % MARK_COL_COUNT; DWORD colMark = posMark % MARK_COL_COUNT;
DWORD rowMark = posMark / MARK_COL_COUNT; DWORD rowMark = posMark / MARK_COL_COUNT;
printf("PutMark pos %u %ux%u\n", posMark, colMark * SGuildMark::WIDTH, rowMark * SGuildMark::HEIGHT); printf("PutMark pos %u %ux%u\n", posMark, colMark * SGuildMark::WIDTH, rowMark * SGuildMark::HEIGHT);
PutData(colMark * SGuildMark::WIDTH, rowMark * SGuildMark::HEIGHT, SGuildMark::WIDTH, SGuildMark::HEIGHT, pbImage); PutData(colMark * SGuildMark::WIDTH, rowMark * SGuildMark::HEIGHT, SGuildMark::WIDTH, SGuildMark::HEIGHT, pbImage);
// 그려진 곳의 블럭을 업데이트 // 그려진 곳의 블럭을 업데이트
DWORD rowBlock = rowMark / SGuildMarkBlock::MARK_PER_BLOCK_HEIGHT; DWORD rowBlock = rowMark / SGuildMarkBlock::MARK_PER_BLOCK_HEIGHT;
DWORD colBlock = colMark / SGuildMarkBlock::MARK_PER_BLOCK_WIDTH; DWORD colBlock = colMark / SGuildMarkBlock::MARK_PER_BLOCK_WIDTH;
@ -197,7 +197,7 @@ bool CGuildMarkImage::SaveBlockFromCompressedData(DWORD posBlock, const BYTE * p
return true; return true;
} }
void CGuildMarkImage::BuildAllBlocks() // 이미지 전체를 블럭화 void CGuildMarkImage::BuildAllBlocks() // 이미지 전체를 블럭화
{ {
Pixel apxBuf[SGuildMarkBlock::SIZE]; Pixel apxBuf[SGuildMarkBlock::SIZE];
SPDLOG_INFO("GuildMarkImage::BuildAllBlocks"); SPDLOG_INFO("GuildMarkImage::BuildAllBlocks");

View File

@ -15,7 +15,7 @@ void CGuildMarkManager::__DeleteImage(CGuildMarkImage * pkImgDel)
CGuildMarkManager::CGuildMarkManager() CGuildMarkManager::CGuildMarkManager()
{ {
// 남은 mark id 셋을 만든다. (서버용) // 남은 mark id 셋을 만든다. (서버용)
for (DWORD i = 0; i < MAX_IMAGE_COUNT * CGuildMarkImage::MARK_TOTAL_COUNT; ++i) for (DWORD i = 0; i < MAX_IMAGE_COUNT * CGuildMarkImage::MARK_TOTAL_COUNT; ++i)
m_setFreeMarkID.insert(i); m_setFreeMarkID.insert(i);
} }
@ -44,7 +44,7 @@ void CGuildMarkManager::SetMarkPathPrefix(const char * prefix)
m_pathPrefix = prefix; m_pathPrefix = prefix;
} }
// 마크 인덱스 불러오기 (서버에서만 사용) // 마크 인덱스 불러오기 (서버에서만 사용)
bool CGuildMarkManager::LoadMarkIndex() bool CGuildMarkManager::LoadMarkIndex()
{ {
char buf[64]; char buf[64];
@ -177,7 +177,7 @@ DWORD CGuildMarkManager::__AllocMarkID(DWORD guildID)
DWORD markID = *it; DWORD markID = *it;
DWORD imgIdx = markID / CGuildMarkImage::MARK_TOTAL_COUNT; DWORD imgIdx = markID / CGuildMarkImage::MARK_TOTAL_COUNT;
CGuildMarkImage * pkImage = __GetImage(imgIdx); // 이미지가 없다면 만들기 위해 CGuildMarkImage * pkImage = __GetImage(imgIdx); // 이미지가 없다면 만들기 위해
if (pkImage && AddMarkIDByGuildID(guildID, markID)) if (pkImage && AddMarkIDByGuildID(guildID, markID))
return markID; return markID;
@ -263,7 +263,7 @@ void CGuildMarkManager::GetDiffBlocks(DWORD imgIdx, const DWORD * crcList, std::
{ {
mapDiffBlocks.clear(); mapDiffBlocks.clear();
// 클라이언트에서 서버에 없는 이미지를 요청할 수는 없다. // 클라이언트에서 서버에 없는 이미지를 요청할 수는 없다.
if (m_mapIdx_Image.end() == m_mapIdx_Image.find(imgIdx)) if (m_mapIdx_Image.end() == m_mapIdx_Image.find(imgIdx))
{ {
SPDLOG_ERROR("invalid idx {}", imgIdx); SPDLOG_ERROR("invalid idx {}", imgIdx);
@ -290,7 +290,7 @@ bool CGuildMarkManager::SaveBlockFromCompressedData(DWORD imgIdx, DWORD posBlock
// CLIENT // CLIENT
bool CGuildMarkManager::GetBlockCRCList(DWORD imgIdx, DWORD * crcList) bool CGuildMarkManager::GetBlockCRCList(DWORD imgIdx, DWORD * crcList)
{ {
// 클라이언트에서 서버에 없는 이미지를 요청할 수는 없다. // 클라이언트에서 서버에 없는 이미지를 요청할 수는 없다.
if (m_mapIdx_Image.end() == m_mapIdx_Image.find(imgIdx)) if (m_mapIdx_Image.end() == m_mapIdx_Image.find(imgIdx))
{ {
SPDLOG_ERROR("invalid idx {}", imgIdx); SPDLOG_ERROR("invalid idx {}", imgIdx);

View File

@ -318,11 +318,11 @@ bool COXEventManager::CheckAnswer(bool answer)
int len = snprintf(chatbuf, sizeof(chatbuf), int len = snprintf(chatbuf, sizeof(chatbuf),
"%s %u %u", Random::get(0, 1) == 1 ? "cheer1" : "cheer2", (DWORD)pkChar->GetVID(), 0); "%s %u %u", Random::get(0, 1) == 1 ? "cheer1" : "cheer2", (DWORD)pkChar->GetVID(), 0);
// 리턴값이 sizeof(chatbuf) 이상일 경우 truncate되었다는 뜻.. // 리턴값이 sizeof(chatbuf) 이상일 경우 truncate되었다는 뜻..
if (len < 0 || len >= (int) sizeof(chatbuf)) if (len < 0 || len >= (int) sizeof(chatbuf))
len = sizeof(chatbuf) - 1; len = sizeof(chatbuf) - 1;
// \0 문자 포함 // \0 문자 포함
++len; ++len;
TPacketGCChat pack_chat; TPacketGCChat pack_chat;

View File

@ -18,13 +18,13 @@ EVENTINFO(petsystem_event_info)
CPetSystem* pPetSystem; CPetSystem* pPetSystem;
}; };
// PetSystem을 update 해주는 event. // PetSystem을 update 해주는 event.
// PetSystem은 CHRACTER_MANAGER에서 기존 FSM으로 update 해주는 기존 chracters와 달리, // PetSystem은 CHRACTER_MANAGER에서 기존 FSM으로 update 해주는 기존 chracters와 달리,
// Owner의 STATE를 update 할 때 _UpdateFollowAI 함수로 update 해준다. // Owner의 STATE를 update 할 때 _UpdateFollowAI 함수로 update 해준다.
// 그런데 owner의 state를 update를 CHRACTER_MANAGER에서 해주기 때문에, // 그런데 owner의 state를 update를 CHRACTER_MANAGER에서 해주기 때문에,
// petsystem을 update하다가 pet을 unsummon하는 부분에서 문제가 생겼다. // petsystem을 update하다가 pet을 unsummon하는 부분에서 문제가 생겼다.
// (CHRACTER_MANAGER에서 update 하면 chracter destroy가 pending되어, CPetSystem에서는 dangling 포인터를 가지고 있게 된다.) // (CHRACTER_MANAGER에서 update 하면 chracter destroy가 pending되어, CPetSystem에서는 dangling 포인터를 가지고 있게 된다.)
// 따라서 PetSystem만 업데이트 해주는 event를 발생시킴. // 따라서 PetSystem만 업데이트 해주는 event를 발생시킴.
EVENTFUNC(petsystem_update_event) EVENTFUNC(petsystem_update_event)
{ {
petsystem_event_info* info = dynamic_cast<petsystem_event_info*>( event->info ); petsystem_event_info* info = dynamic_cast<petsystem_event_info*>( event->info );
@ -41,12 +41,12 @@ EVENTFUNC(petsystem_update_event)
pPetSystem->Update(0); pPetSystem->Update(0);
// 0.25초마다 갱신. // 0.25초마다 갱신.
return PASSES_PER_SEC(1) / 4; return PASSES_PER_SEC(1) / 4;
} }
/// NOTE: 1캐릭터가 몇개의 펫을 가질 수 있는지 제한... 캐릭터마다 개수를 다르게 할거라면 변수로 넣등가... 음.. /// NOTE: 1캐릭터가 몇개의 펫을 가질 수 있는지 제한... 캐릭터마다 개수를 다르게 할거라면 변수로 넣등가... 음..
/// 가질 수 있는 개수와 동시에 소환할 수 있는 개수가 틀릴 수 있는데 이런건 기획 없으니 일단 무시 /// 가질 수 있는 개수와 동시에 소환할 수 있는 개수가 틀릴 수 있는데 이런건 기획 없으니 일단 무시
const float PET_COUNT_LIMIT = 3; const float PET_COUNT_LIMIT = 3;
/////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////
@ -119,7 +119,7 @@ void CPetActor::Unsummon()
{ {
if (true == this->IsSummoned()) if (true == this->IsSummoned())
{ {
// 버프 삭제 // 버프 삭제
this->ClearBuff(); this->ClearBuff();
this->SetSummonItem(NULL); this->SetSummonItem(NULL);
if (NULL != m_pkOwner) if (NULL != m_pkOwner)
@ -175,14 +175,14 @@ DWORD CPetActor::Summon(const char* petName, LPITEM pSummonItem, bool bSpawnFar)
// m_pkOwner->DetailLog(); // m_pkOwner->DetailLog();
// m_pkChar->DetailLog(); // m_pkChar->DetailLog();
//펫의 국가를 주인의 국가로 설정함. //펫의 국가를 주인의 국가로 설정함.
m_pkChar->SetEmpire(m_pkOwner->GetEmpire()); m_pkChar->SetEmpire(m_pkOwner->GetEmpire());
m_dwVID = m_pkChar->GetVID(); m_dwVID = m_pkChar->GetVID();
this->SetName(petName); this->SetName(petName);
// SetSummonItem(pSummonItem)를 부른 후에 ComputePoints를 부르면 버프 적용됨. // SetSummonItem(pSummonItem)를 부른 후에 ComputePoints를 부르면 버프 적용됨.
this->SetSummonItem(pSummonItem); this->SetSummonItem(pSummonItem);
m_pkOwner->ComputePoints(); m_pkOwner->ComputePoints();
m_pkChar->Show(m_pkOwner->GetMapIndex(), x, y, z); m_pkChar->Show(m_pkOwner->GetMapIndex(), x, y, z);
@ -197,11 +197,11 @@ bool CPetActor::_UpdatAloneActionAI(float fMinDist, float fMaxDist)
float dest_x = GetOwner()->GetX() + fDist * cos(r); float dest_x = GetOwner()->GetX() + fDist * cos(r);
float dest_y = GetOwner()->GetY() + fDist * sin(r); float dest_y = GetOwner()->GetY() + fDist * sin(r);
//m_pkChar->SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정 //m_pkChar->SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
//GetDeltaByDegree(m_pkChar->GetRotation(), fDist, &fx, &fy); //GetDeltaByDegree(m_pkChar->GetRotation(), fDist, &fx, &fy);
// 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다. // 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다.
//if (!(SECTREE_MANAGER::instance().IsMovablePosition(m_pkChar->GetMapIndex(), m_pkChar->GetX() + (int) fx, m_pkChar->GetY() + (int) fy) //if (!(SECTREE_MANAGER::instance().IsMovablePosition(m_pkChar->GetMapIndex(), m_pkChar->GetX() + (int) fx, m_pkChar->GetY() + (int) fy)
// && SECTREE_MANAGER::instance().IsMovablePosition(m_pkChar->GetMapIndex(), m_pkChar->GetX() + (int) fx/2, m_pkChar->GetY() + (int) fy/2))) // && SECTREE_MANAGER::instance().IsMovablePosition(m_pkChar->GetMapIndex(), m_pkChar->GetX() + (int) fx/2, m_pkChar->GetY() + (int) fy/2)))
// return true; // return true;
@ -218,7 +218,7 @@ bool CPetActor::_UpdatAloneActionAI(float fMinDist, float fMaxDist)
return true; return true;
} }
// char_state.cpp StateHorse함수 그냥 C&P -_-; // char_state.cpp StateHorse함수 그냥 C&P -_-;
bool CPetActor::_UpdateFollowAI() bool CPetActor::_UpdateFollowAI()
{ {
if (0 == m_pkChar->m_pkMobData) if (0 == m_pkChar->m_pkMobData)
@ -227,9 +227,9 @@ bool CPetActor::_UpdateFollowAI()
return false; return false;
} }
// NOTE: 캐릭터(펫)의 원래 이동 속도를 알아야 하는데, 해당 값(m_pkChar->m_pkMobData->m_table.sMovingSpeed)을 직접적으로 접근해서 알아낼 수도 있지만 // NOTE: 캐릭터(펫)의 원래 이동 속도를 알아야 하는데, 해당 값(m_pkChar->m_pkMobData->m_table.sMovingSpeed)을 직접적으로 접근해서 알아낼 수도 있지만
// m_pkChar->m_pkMobData 값이 invalid한 경우가 자주 발생함. 현재 시간관계상 원인은 다음에 파악하고 일단은 m_pkChar->m_pkMobData 값을 아예 사용하지 않도록 함. // m_pkChar->m_pkMobData 값이 invalid한 경우가 자주 발생함. 현재 시간관계상 원인은 다음에 파악하고 일단은 m_pkChar->m_pkMobData 값을 아예 사용하지 않도록 함.
// 여기서 매번 검사하는 이유는 최초 초기화 할 때 정상 값을 제대로 못얻어오는 경우도 있음.. -_-;; ㅠㅠㅠㅠㅠㅠㅠㅠㅠ // 여기서 매번 검사하는 이유는 최초 초기화 할 때 정상 값을 제대로 못얻어오는 경우도 있음.. -_-;; ㅠㅠㅠㅠㅠㅠㅠㅠㅠ
if (0 == m_originalMoveSpeed) if (0 == m_originalMoveSpeed)
{ {
const CMob* mobData = CMobManager::Instance().Get(m_dwVnum); const CMob* mobData = CMobManager::Instance().Get(m_dwVnum);
@ -237,14 +237,14 @@ bool CPetActor::_UpdateFollowAI()
if (0 != mobData) if (0 != mobData)
m_originalMoveSpeed = mobData->m_table.sMovingSpeed; m_originalMoveSpeed = mobData->m_table.sMovingSpeed;
} }
float START_FOLLOW_DISTANCE = 300.0f; // 이 거리 이상 떨어지면 쫓아가기 시작함 float START_FOLLOW_DISTANCE = 300.0f; // 이 거리 이상 떨어지면 쫓아가기 시작함
float START_RUN_DISTANCE = 900.0f; // 이 거리 이상 떨어지면 뛰어서 쫓아감. float START_RUN_DISTANCE = 900.0f; // 이 거리 이상 떨어지면 뛰어서 쫓아감.
float RESPAWN_DISTANCE = 4500.f; // 이 거리 이상 멀어지면 주인 옆으로 소환함. float RESPAWN_DISTANCE = 4500.f; // 이 거리 이상 멀어지면 주인 옆으로 소환함.
int APPROACH = 200; // 접근 거리 int APPROACH = 200; // 접근 거리
bool bDoMoveAlone = true; // 캐릭터와 가까이 있을 때 혼자 여기저기 움직일건지 여부 -_-; bool bDoMoveAlone = true; // 캐릭터와 가까이 있을 때 혼자 여기저기 움직일건지 여부 -_-;
bool bRun = false; // 뛰어야 하나? bool bRun = false; // 뛰어야 하나?
DWORD currentTime = get_dword_time(); DWORD currentTime = get_dword_time();
@ -272,7 +272,7 @@ bool CPetActor::_UpdateFollowAI()
bRun = true; bRun = true;
} }
m_pkChar->SetNowWalking(!bRun); // NOTE: 함수 이름보고 멈추는건줄 알았는데 SetNowWalking(false) 하면 뛰는거임.. -_-; m_pkChar->SetNowWalking(!bRun); // NOTE: 함수 이름보고 멈추는건줄 알았는데 SetNowWalking(false) 하면 뛰는거임.. -_-;
Follow(APPROACH); Follow(APPROACH);
@ -288,7 +288,7 @@ bool CPetActor::_UpdateFollowAI()
// m_dwLastActionTime = currentTime; // m_dwLastActionTime = currentTime;
// } // }
//} //}
// Follow 중이지만 주인과 일정 거리 이내로 가까워졌다면 멈춤 // Follow 중이지만 주인과 일정 거리 이내로 가까워졌다면 멈춤
else else
m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0); m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
//else if (currentTime - m_dwLastActionTime > Random::get(5000, 12000)) //else if (currentTime - m_dwLastActionTime > Random::get(5000, 12000))
@ -303,8 +303,8 @@ bool CPetActor::Update(DWORD deltaTime)
{ {
bool bResult = true; bool bResult = true;
// 펫 주인이 죽었거나, 소환된 펫의 상태가 이상하다면 펫을 없앰. (NOTE: 가끔가다 이런 저런 이유로 소환된 펫이 DEAD 상태에 빠지는 경우가 있음-_-;) // 펫 주인이 죽었거나, 소환된 펫의 상태가 이상하다면 펫을 없앰. (NOTE: 가끔가다 이런 저런 이유로 소환된 펫이 DEAD 상태에 빠지는 경우가 있음-_-;)
// 펫을 소환한 아이템이 없거나, 내가 가진 상태가 아니라면 펫을 없앰. // 펫을 소환한 아이템이 없거나, 내가 가진 상태가 아니라면 펫을 없앰.
if (m_pkOwner->IsDead() || (IsSummoned() && m_pkChar->IsDead()) if (m_pkOwner->IsDead() || (IsSummoned() && m_pkChar->IsDead())
|| NULL == ITEM_MANAGER::instance().FindByVID(this->GetSummonItemVID()) || NULL == ITEM_MANAGER::instance().FindByVID(this->GetSummonItemVID())
|| ITEM_MANAGER::instance().FindByVID(this->GetSummonItemVID())->GetOwner() != this->GetOwner() || ITEM_MANAGER::instance().FindByVID(this->GetSummonItemVID())->GetOwner() != this->GetOwner()
@ -320,10 +320,10 @@ bool CPetActor::Update(DWORD deltaTime)
return bResult; return bResult;
} }
//NOTE : 주의!!! MinDistance를 크게 잡으면 그 변위만큼의 변화동안은 follow하지 않는다, //NOTE : 주의!!! MinDistance를 크게 잡으면 그 변위만큼의 변화동안은 follow하지 않는다,
bool CPetActor::Follow(float fMinDistance) bool CPetActor::Follow(float fMinDistance)
{ {
// 가려는 위치를 바라봐야 한다. // 가려는 위치를 바라봐야 한다.
if( !m_pkOwner || !m_pkChar) if( !m_pkOwner || !m_pkChar)
return false; return false;
@ -367,7 +367,7 @@ void CPetActor::SetSummonItem (LPITEM pItem)
void CPetActor::GiveBuff() void CPetActor::GiveBuff()
{ {
// 파황 펫 버프는 던전에서만 발생함. // 파황 펫 버프는 던전에서만 발생함.
if (34004 == m_dwVnum || 34009 == m_dwVnum) if (34004 == m_dwVnum || 34009 == m_dwVnum)
{ {
if (NULL == m_pkOwner->GetDungeon()) if (NULL == m_pkOwner->GetDungeon())
@ -432,15 +432,15 @@ void CPetSystem::Destroy()
m_petActorMap.clear(); m_petActorMap.clear();
} }
/// 펫 시스템 업데이트. 등록된 펫들의 AI 처리 등을 함. /// 펫 시스템 업데이트. 등록된 펫들의 AI 처리 등을 함.
bool CPetSystem::Update(DWORD deltaTime) bool CPetSystem::Update(DWORD deltaTime)
{ {
bool bResult = true; bool bResult = true;
DWORD currentTime = get_dword_time(); DWORD currentTime = get_dword_time();
// CHARACTER_MANAGER에서 캐릭터류 Update할 때 매개변수로 주는 (Pulse라고 되어있는)값이 이전 프레임과의 시간차이인줄 알았는데 // CHARACTER_MANAGER에서 캐릭터류 Update할 때 매개변수로 주는 (Pulse라고 되어있는)값이 이전 프레임과의 시간차이인줄 알았는데
// 전혀 다른 값이라서-_-; 여기에 입력으로 들어오는 deltaTime은 의미가 없음ㅠㅠ // 전혀 다른 값이라서-_-; 여기에 입력으로 들어오는 deltaTime은 의미가 없음ㅠㅠ
if (m_dwUpdatePeriod > currentTime - m_dwLastUpdateTime) if (m_dwUpdatePeriod > currentTime - m_dwLastUpdateTime)
return true; return true;
@ -473,7 +473,7 @@ bool CPetSystem::Update(DWORD deltaTime)
return bResult; return bResult;
} }
/// 관리 목록에서 펫을 지움 /// 관리 목록에서 펫을 지움
void CPetSystem::DeletePet(DWORD mobVnum) void CPetSystem::DeletePet(DWORD mobVnum)
{ {
TPetActorMap::iterator iter = m_petActorMap.find(mobVnum); TPetActorMap::iterator iter = m_petActorMap.find(mobVnum);
@ -494,7 +494,7 @@ void CPetSystem::DeletePet(DWORD mobVnum)
m_petActorMap.erase(iter); m_petActorMap.erase(iter);
} }
/// 관리 목록에서 펫을 지움 /// 관리 목록에서 펫을 지움
void CPetSystem::DeletePet(CPetActor* petActor) void CPetSystem::DeletePet(CPetActor* petActor)
{ {
for (TPetActorMap::iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter) for (TPetActorMap::iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
@ -542,7 +542,7 @@ CPetActor* CPetSystem::Summon(DWORD mobVnum, LPITEM pSummonItem, const char* pet
{ {
CPetActor* petActor = this->GetByVnum(mobVnum); CPetActor* petActor = this->GetByVnum(mobVnum);
// 등록된 펫이 아니라면 새로 생성 후 관리 목록에 등록함. // 등록된 펫이 아니라면 새로 생성 후 관리 목록에 등록함.
if (0 == petActor) if (0 == petActor)
{ {
petActor = M2_NEW CPetActor(m_pkOwner, mobVnum, options); petActor = M2_NEW CPetActor(m_pkOwner, mobVnum, options);
@ -557,7 +557,7 @@ CPetActor* CPetSystem::Summon(DWORD mobVnum, LPITEM pSummonItem, const char* pet
info->pPetSystem = this; info->pPetSystem = this;
m_pkPetSystemUpdateEvent = event_create(petsystem_update_event, info, PASSES_PER_SEC(1) / 4); // 0.25초 m_pkPetSystemUpdateEvent = event_create(petsystem_update_event, info, PASSES_PER_SEC(1) / 4); // 0.25초
} }
return petActor; return petActor;
@ -589,7 +589,7 @@ CPetActor* CPetSystem::GetByVID(DWORD vid) const
return bFound ? petActor : 0; return bFound ? petActor : 0;
} }
/// 등록 된 펫 중에서 주어진 몹 VNUM을 가진 액터를 반환하는 함수. /// 등록 된 펫 중에서 주어진 몹 VNUM을 가진 액터를 반환하는 함수.
CPetActor* CPetSystem::GetByVnum(DWORD vnum) const CPetActor* CPetSystem::GetByVnum(DWORD vnum) const
{ {
CPetActor* petActor = 0; CPetActor* petActor = 0;

View File

@ -3,7 +3,7 @@
#include "SpeedServer.h" #include "SpeedServer.h"
#include "locale_service.h" #include "locale_service.h"
// 쾌도 서버 보너스 경험치 시스템 // 쾌도 서버 보너스 경험치 시스템
// by rtsummit // by rtsummit
CSpeedServerManager::CSpeedServerManager() CSpeedServerManager::CSpeedServerManager()
@ -361,13 +361,13 @@ HME CSpeedServerEmpireExp::GetCurrentExpPriv(int &duration, bool &is_change)
HME hme; HME hme;
// 현재 날짜가 holiday이면 holiday bonus를 도입한다. // 현재 날짜가 holiday이면 holiday bonus를 도입한다.
if (holi_it != holiday_map.end()) if (holi_it != holiday_map.end())
{ {
for (std::list <HME>::iterator it = holi_it->second.begin(); for (std::list <HME>::iterator it = holi_it->second.begin();
it != wday_exp_table[datetime->tm_wday].end(); it++) it != wday_exp_table[datetime->tm_wday].end(); it++)
{ {
// 현재 시각이 시간 구간 안에 포함되면, // 현재 시각이 시간 구간 안에 포함되면,
if (total_sec < (it->hour * 3600 + it->min * 60 )) if (total_sec < (it->hour * 3600 + it->min * 60 ))
{ {
hme = *it; hme = *it;
@ -380,7 +380,7 @@ HME CSpeedServerEmpireExp::GetCurrentExpPriv(int &duration, bool &is_change)
for (std::list <HME>::iterator it = wday_exp_table[datetime->tm_wday].begin(); for (std::list <HME>::iterator it = wday_exp_table[datetime->tm_wday].begin();
it != wday_exp_table[datetime->tm_wday].end(); it++) it != wday_exp_table[datetime->tm_wday].end(); it++)
{ {
// 현재 시각이 시간 구간 안에 포함되면, // 현재 시각이 시간 구간 안에 포함되면,
if (total_sec < (it->hour * 3600 + it->min * 60 )) if (total_sec < (it->hour * 3600 + it->min * 60 ))
{ {
hme = *it; hme = *it;

View File

@ -55,7 +55,7 @@ const char* FN_weapon_type(int weapon)
class ANI class ANI
{ {
protected: protected:
// [종족][일반0탈것1][무기][콤보] // [종족][일반0탈것1][무기][콤보]
DWORD m_speed[MAIN_RACE_MAX_NUM][2][WEAPON_NUM_TYPES][9]; DWORD m_speed[MAIN_RACE_MAX_NUM][2][WEAPON_NUM_TYPES][9];
public: public:
@ -126,14 +126,14 @@ ANI::ANI()
bool ANI::load() bool ANI::load()
{ {
const char* dir_name[MAIN_RACE_MAX_NUM] = { const char* dir_name[MAIN_RACE_MAX_NUM] = {
"data/pc/warrior", // 무사(남) "data/pc/warrior", // 무사(남)
"data/pc/assassin", // 자객(여) "data/pc/assassin", // 자객(여)
"data/pc/sura", // 수라(남) "data/pc/sura", // 수라(남)
"data/pc/shaman", // 무당(여) "data/pc/shaman", // 무당(여)
"data/pc2/warrior", // 무사(여) "data/pc2/warrior", // 무사(여)
"data/pc2/assassin", // 자객(남) "data/pc2/assassin", // 자객(남)
"data/pc2/sura", // 수라(여) "data/pc2/sura", // 수라(여)
"data/pc2/shaman" // 무당(남) "data/pc2/shaman" // 무당(남)
}; };
for (int race = 0; race <MAIN_RACE_MAX_NUM; ++race) for (int race = 0; race <MAIN_RACE_MAX_NUM; ++race)
@ -203,13 +203,13 @@ bool ANI::load_one_race(int race, const char *dir_name)
for (BYTE combo = 1; combo <= 8; ++combo) for (BYTE combo = 1; combo <= 8; ++combo)
{ {
// 말 안탔을 때 // 말 안탔을 때
m_speed[race][0][weapon][combo] = load_one_weapon(dir_name, weapon, combo, false); m_speed[race][0][weapon][combo] = load_one_weapon(dir_name, weapon, combo, false);
m_speed[race][0][weapon][0] = std::min(m_speed[race][0][weapon][0], m_speed[race][0][weapon][combo]); // 최소값 m_speed[race][0][weapon][0] = std::min(m_speed[race][0][weapon][0], m_speed[race][0][weapon][combo]); // 최소값
// 말 탔을 때 // 말 탔을 때
m_speed[race][1][weapon][combo] = load_one_weapon(dir_name, weapon, combo, true); m_speed[race][1][weapon][combo] = load_one_weapon(dir_name, weapon, combo, true);
m_speed[race][1][weapon][0] = std::min(m_speed[race][1][weapon][0], m_speed[race][1][weapon][combo]); // 최소값 m_speed[race][1][weapon][0] = std::min(m_speed[race][1][weapon][0], m_speed[race][1][weapon][combo]); // 최소값
SPDLOG_TRACE("combo{:02} speed={} horse={}", SPDLOG_TRACE("combo{:02} speed={} horse={}",
combo, m_speed[race][0][weapon][combo], m_speed[race][1][weapon][combo]); combo, m_speed[race][0][weapon][combo], m_speed[race][1][weapon][combo]);
@ -337,8 +337,8 @@ DWORD ani_attack_speed(LPCHARACTER ch)
ch->GetPoint(POINT_ATT_SPEED)); ch->GetPoint(POINT_ATT_SPEED));
*/ */
/* 투핸디드 소드의 경우 삼연참공격과 승마시 */ /* 투핸디드 소드의 경우 삼연참공격과 승마시 */
/* 오류가 많아 한손검 속도로 생각하자 */ /* 오류가 많아 한손검 속도로 생각하자 */
if (weapon == WEAPON_TWO_HANDED) if (weapon == WEAPON_TWO_HANDED)
weapon = WEAPON_SWORD; weapon = WEAPON_SWORD;

View File

@ -290,7 +290,7 @@ EVENTFUNC(ready_to_start_event)
duelStart.header = HEADER_GC_DUEL_START; duelStart.header = HEADER_GC_DUEL_START;
duelStart.wSize = sizeof(TPacketGCDuelStart) + 4; duelStart.wSize = sizeof(TPacketGCDuelStart) + 4;
DWORD dwOppList[8]; // 최대 파티원 8명 이므로.. DWORD dwOppList[8]; // 최대 파티원 8명 이므로..
dwOppList[0] = (DWORD)chB->GetVID(); dwOppList[0] = (DWORD)chB->GetVID();
TEMP_BUFFER buf; TEMP_BUFFER buf;
@ -339,7 +339,7 @@ EVENTFUNC(ready_to_start_event)
TEMP_BUFFER buf; TEMP_BUFFER buf;
TEMP_BUFFER buf2; TEMP_BUFFER buf2;
DWORD dwOppList[8]; // 최대 파티원 8명 이므로.. DWORD dwOppList[8]; // 최대 파티원 8명 이므로..
TPacketGCDuelStart duelStart; TPacketGCDuelStart duelStart;
duelStart.header = HEADER_GC_DUEL_START; duelStart.header = HEADER_GC_DUEL_START;
duelStart.wSize = sizeof(TPacketGCDuelStart) + 4; duelStart.wSize = sizeof(TPacketGCDuelStart) + 4;
@ -678,7 +678,7 @@ bool CArenaMap::CanAttack(LPCHARACTER pCharAttacker, LPCHARACTER pCharVictim)
bool CArena::CanAttack(DWORD dwPIDA, DWORD dwPIDB) bool CArena::CanAttack(DWORD dwPIDA, DWORD dwPIDB)
{ {
// 1:1 전용 다대다 할 경우 수정 필요 // 1:1 전용 다대다 할 경우 수정 필요
if (m_dwPIDA == dwPIDA && m_dwPIDB == dwPIDB) return true; if (m_dwPIDA == dwPIDA && m_dwPIDB == dwPIDB) return true;
if (m_dwPIDA == dwPIDB && m_dwPIDB == dwPIDA) return true; if (m_dwPIDA == dwPIDB && m_dwPIDB == dwPIDA) return true;
@ -728,7 +728,7 @@ bool CArena::OnDead(DWORD dwPIDA, DWORD dwPIDB)
if (pCharA == NULL && pCharB == NULL) if (pCharA == NULL && pCharB == NULL)
{ {
// 둘다 접속이 끊어졌다 ?! // 둘다 접속이 끊어졌다 ?!
SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("\xB4\xEB\xB7\xC3\xC0\xDA \xB9\xAE\xC1\xA6\xB7\xCE \xC0\xCE\xC7\xCF\xBF\xA9 \xB4\xEB\xB7\xC3\xC0\xBB \xC1\xDF\xB4\xDC\xC7\xD5\xB4\xCF\xB4\xD9.")); SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("\xB4\xEB\xB7\xC3\xC0\xDA \xB9\xAE\xC1\xA6\xB7\xCE \xC0\xCE\xC7\xCF\xBF\xA9 \xB4\xEB\xB7\xC3\xC0\xBB \xC1\xDF\xB4\xDC\xC7\xD5\xB4\xCF\xB4\xD9."));
restart = false; restart = false;
} }
@ -811,7 +811,7 @@ bool CArena::OnDead(DWORD dwPIDA, DWORD dwPIDB)
} }
else else
{ {
// 오면 안된다 ?! // 오면 안된다 ?!
} }
if (restart == false) if (restart == false)

View File

@ -215,7 +215,7 @@ void AuctionBoard::YourItemInfoList (TItemInfoVec& vec, DWORD player_id, int sta
} }
// 0~1, 2~3, 4~5, 6~7, 8~9 // 0~1, 2~3, 4~5, 6~7, 8~9
// 짝수면 descending, 홀수면 accending. // 짝수면 descending, 홀수면 accending.
struct FCheckGradeSatisfied struct FCheckGradeSatisfied
{ {
BYTE grade; BYTE grade;
@ -796,7 +796,7 @@ void AuctionManager::YourBidItemInfoList (AuctionBoard::TItemInfoVec& vec, DWORD
} }
else else
{ {
// expired 만들고 여기서 넣어야한다. // expired 만들고 여기서 넣어야한다.
} }
} }
} }
@ -975,7 +975,7 @@ void AuctionManager::bid (LPCHARACTER ch, DWORD item_id, int bid_price)
} }
// fixme // fixme
// 반드시 돈!!! // 반드시 돈!!!
void AuctionManager::immediate_purchase (LPCHARACTER ch, DWORD item_id) void AuctionManager::immediate_purchase (LPCHARACTER ch, DWORD item_id)
{ {
TAuctionItemInfo* item_info = GetAuctionItemInfo (item_id); TAuctionItemInfo* item_info = GetAuctionItemInfo (item_id);
@ -1005,7 +1005,7 @@ void AuctionManager::immediate_purchase (LPCHARACTER ch, DWORD item_id)
db_clientdesc->DBPacket(HEADER_GD_COMMAND_AUCTION, ch->GetPlayerID(), &pack_impur, sizeof(TPacketGDCommnadAuction)); db_clientdesc->DBPacket(HEADER_GD_COMMAND_AUCTION, ch->GetPlayerID(), &pack_impur, sizeof(TPacketGDCommnadAuction));
} }
// 시작 // 시작
void AuctionManager::get_auctioned_item (LPCHARACTER ch, DWORD item_id, DWORD item_num) void AuctionManager::get_auctioned_item (LPCHARACTER ch, DWORD item_id, DWORD item_num)
{ {
TItemTable* proto = ITEM_MANAGER::instance().GetTable(item_num); TItemTable* proto = ITEM_MANAGER::instance().GetTable(item_num);
@ -1120,7 +1120,7 @@ void AuctionManager::bid_cancel (LPCHARACTER ch, DWORD item_id)
db_clientdesc->DBPacket(HEADER_GD_COMMAND_AUCTION, ch->GetPlayerID(), &pack_bc, sizeof(TPacketGDCommnadAuction)); db_clientdesc->DBPacket(HEADER_GD_COMMAND_AUCTION, ch->GetPlayerID(), &pack_bc, sizeof(TPacketGDCommnadAuction));
} }
// 끝 // 끝
void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuction* cmd_result) void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuction* cmd_result)
{ {
LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(commander_id); LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(commander_id);
@ -1354,7 +1354,7 @@ void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuc
} }
else else
{ {
// insert하면 lock이 풀린다. // insert하면 lock이 풀린다.
DWORD item_id = cmd_result->target; DWORD item_id = cmd_result->target;
cmd_result++; cmd_result++;
TAuctionItemInfo* auction_info = (TAuctionItemInfo*)cmd_result; TAuctionItemInfo* auction_info = (TAuctionItemInfo*)cmd_result;

View File

@ -3,7 +3,7 @@
#include "banword.h" #include "banword.h"
#include "config.h" #include "config.h"
extern void SendLog(const char * c_pszBuf); // 운영자에게만 공지 extern void SendLog(const char * c_pszBuf); // 운영자에게만 공지
CBanwordManager::CBanwordManager() CBanwordManager::CBanwordManager()
{ {

View File

@ -46,7 +46,7 @@ bool timed_event_cancel(LPCHARACTER ch)
} }
/* RECALL_DELAY /* RECALL_DELAY
차후 전투로 인해 귀환부 딜레이가 취소 되어야 할 경우 주석 해제 차후 전투로 인해 귀환부 딜레이가 취소 되어야 할 경우 주석 해제
if (ch->m_pk_RecallEvent) if (ch->m_pk_RecallEvent)
{ {
event_cancel(&ch->m_pkRecallEvent); event_cancel(&ch->m_pkRecallEvent);
@ -59,11 +59,11 @@ bool timed_event_cancel(LPCHARACTER ch)
bool battle_is_attackable(LPCHARACTER ch, LPCHARACTER victim) bool battle_is_attackable(LPCHARACTER ch, LPCHARACTER victim)
{ {
// 상대방이 죽었으면 중단한다. // 상대방이 죽었으면 중단한다.
if (victim->IsDead()) if (victim->IsDead())
return false; return false;
// 안전지대면 중단 // 안전지대면 중단
{ {
SECTREE *sectree = NULL; SECTREE *sectree = NULL;
@ -77,7 +77,7 @@ bool battle_is_attackable(LPCHARACTER ch, LPCHARACTER victim)
} }
// 내가 죽었으면 중단한다. // 내가 죽었으면 중단한다.
if (ch->IsStun() || ch->IsDead()) if (ch->IsStun() || ch->IsDead())
return false; return false;
@ -119,7 +119,7 @@ int battle_melee_attack(LPCHARACTER ch, LPCHARACTER victim)
if (test_server&&ch->IsPC()) if (test_server&&ch->IsPC())
SPDLOG_TRACE("battle_melee_attack : [{}] attack to [{}]", ch->GetName(), victim->GetName()); SPDLOG_TRACE("battle_melee_attack : [{}] attack to [{}]", ch->GetName(), victim->GetName());
// 거리 체크 // 거리 체크
int distance = DISTANCE_APPROX(ch->GetX() - victim->GetX(), ch->GetY() - victim->GetY()); int distance = DISTANCE_APPROX(ch->GetX() - victim->GetX(), ch->GetY() - victim->GetY());
if (!victim->IsBuilding()) if (!victim->IsBuilding())
@ -128,12 +128,12 @@ int battle_melee_attack(LPCHARACTER ch, LPCHARACTER victim)
if (false == ch->IsPC()) if (false == ch->IsPC())
{ {
// 몬스터의 경우 몬스터 공격 거리를 사용 // 몬스터의 경우 몬스터 공격 거리를 사용
max = (int) (ch->GetMobAttackRange() * 1.15f); max = (int) (ch->GetMobAttackRange() * 1.15f);
} }
else else
{ {
// PC일 경우 상대가 melee 몹일 경우 몹의 공격 거리가 최대 공격 거리 // PC일 경우 상대가 melee 몹일 경우 몹의 공격 거리가 최대 공격 거리
if (false == victim->IsPC() && BATTLE_TYPE_MELEE == victim->GetMobBattleType()) if (false == victim->IsPC() && BATTLE_TYPE_MELEE == victim->GetMobBattleType())
max = std::max(300, (int) (victim->GetMobAttackRange() * 1.15f)); max = std::max(300, (int) (victim->GetMobAttackRange() * 1.15f));
} }
@ -161,7 +161,7 @@ int battle_melee_attack(LPCHARACTER ch, LPCHARACTER victim)
return battle_hit(ch, victim); return battle_hit(ch, victim);
} }
// 실제 GET_BATTLE_VICTIM을 NULL로 만들고 이벤트를 캔슬 시킨다. // 실제 GET_BATTLE_VICTIM을 NULL로 만들고 이벤트를 캔슬 시킨다.
void battle_end_ex(LPCHARACTER ch) void battle_end_ex(LPCHARACTER ch)
{ {
if (ch->IsPosition(POS_FIGHTING)) if (ch->IsPosition(POS_FIGHTING))
@ -208,7 +208,7 @@ float CalcAttackRating(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, bool bIgnor
int iARSrc; int iARSrc;
int iERSrc; int iERSrc;
if (LC_IsYMIR()) // 천마 if (LC_IsYMIR()) // 천마
{ {
iARSrc = std::min(90, pkAttacker->GetPolymorphPoint(POINT_DX)); iARSrc = std::min(90, pkAttacker->GetPolymorphPoint(POINT_DX));
iERSrc = std::min(90, pkVictim->GetPolymorphPoint(POINT_DX)); iERSrc = std::min(90, pkVictim->GetPolymorphPoint(POINT_DX));
@ -238,11 +238,11 @@ float CalcAttackRating(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, bool bIgnor
int CalcAttBonus(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, int iAtk) int CalcAttBonus(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, int iAtk)
{ {
// PvP에는 적용하지않음 // PvP에는 적용하지않음
if (!pkVictim->IsPC()) if (!pkVictim->IsPC())
iAtk += pkAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_ATTACK_BONUS); iAtk += pkAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_ATTACK_BONUS);
// PvP에는 적용하지않음 // PvP에는 적용하지않음
if (!pkAttacker->IsPC()) if (!pkAttacker->IsPC())
{ {
int iReduceDamagePct = pkVictim->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_TRANSFER_DAMAGE); int iReduceDamagePct = pkVictim->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_TRANSFER_DAMAGE);
@ -327,9 +327,9 @@ int CalcAttBonus(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, int iAtk)
} }
} }
//[ mob -> PC ] 원소 속성 방어 적용 //[ mob -> PC ] 원소 속성 방어 적용
//2013/01/17 //2013/01/17
//몬스터 속성공격 데미지의 30%에 해당하는 수치에만 저항이 적용됨. //몬스터 속성공격 데미지의 30%에 해당하는 수치에만 저항이 적용됨.
if (pkAttacker->IsNPC() && pkVictim->IsPC()) if (pkAttacker->IsNPC() && pkVictim->IsPC())
{ {
if (pkAttacker->IsRaceFlag(RACE_FLAG_ATT_ELEC)) if (pkAttacker->IsRaceFlag(RACE_FLAG_ATT_ELEC))
@ -553,7 +553,7 @@ int CalcArrowDamage(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, LPITEM pkBow,
if (!pkArrow) if (!pkArrow)
return 0; return 0;
// 타격치 계산부 // 타격치 계산부
int iDist = (int) (DISTANCE_SQRT(pkAttacker->GetX() - pkVictim->GetX(), pkAttacker->GetY() - pkVictim->GetY())); int iDist = (int) (DISTANCE_SQRT(pkAttacker->GetX() - pkVictim->GetX(), pkAttacker->GetY() - pkVictim->GetY()));
//int iGap = (iDist / 100) - 5 - pkBow->GetValue(5) - pkAttacker->GetPoint(POINT_BOW_DISTANCE); //int iGap = (iDist / 100) - 5 - pkBow->GetValue(5) - pkAttacker->GetPoint(POINT_BOW_DISTANCE);
int iGap = (iDist / 100) - 5 - pkAttacker->GetPoint(POINT_BOW_DISTANCE); int iGap = (iDist / 100) - 5 - pkAttacker->GetPoint(POINT_BOW_DISTANCE);
@ -613,7 +613,7 @@ int CalcArrowDamage(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, LPITEM pkBow,
void NormalAttackAffect(LPCHARACTER pkAttacker, LPCHARACTER pkVictim) void NormalAttackAffect(LPCHARACTER pkAttacker, LPCHARACTER pkVictim)
{ {
// 독 공격은 특이하므로 특수 처리 // 독 공격은 특이하므로 특수 처리
if (pkAttacker->GetPoint(POINT_POISON_PCT) && !pkVictim->IsAffectFlag(AFF_POISON)) if (pkAttacker->GetPoint(POINT_POISON_PCT) && !pkVictim->IsAffectFlag(AFF_POISON))
{ {
if (Random::get(1, 100) <= pkAttacker->GetPoint(POINT_POISON_PCT)) if (Random::get(1, 100) <= pkAttacker->GetPoint(POINT_POISON_PCT))
@ -637,7 +637,7 @@ int battle_hit(LPCHARACTER pkAttacker, LPCHARACTER pkVictim)
NormalAttackAffect(pkAttacker, pkVictim); NormalAttackAffect(pkAttacker, pkVictim);
// 데미지 계산 // 데미지 계산
//iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST)) / 100; //iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST)) / 100;
LPITEM pkWeapon = pkAttacker->GetWear(WEAR_WEAPON); LPITEM pkWeapon = pkAttacker->GetWear(WEAR_WEAPON);
@ -670,7 +670,7 @@ int battle_hit(LPCHARACTER pkAttacker, LPCHARACTER pkVictim)
} }
//최종적인 데미지 보정. (2011년 2월 현재 대왕거미에게만 적용.) //최종적인 데미지 보정. (2011년 2월 현재 대왕거미에게만 적용.)
float attMul = pkAttacker->GetAttMul(); float attMul = pkAttacker->GetAttMul();
float tempIDam = iDam; float tempIDam = iDam;
iDam = attMul * tempIDam + 0.5f; iDam = attMul * tempIDam + 0.5f;
@ -691,19 +691,19 @@ DWORD GET_ATTACK_SPEED(LPCHARACTER ch)
return 1000; return 1000;
LPITEM item = ch->GetWear(WEAR_WEAPON); LPITEM item = ch->GetWear(WEAR_WEAPON);
DWORD default_bonus = SPEEDHACK_LIMIT_BONUS * 3; // 유두리 공속(기본 80) (일반 유저가 speed hack 에 걸리는 것을 막기 위해 *3 추가. 2013.09.11 CYH) DWORD default_bonus = SPEEDHACK_LIMIT_BONUS * 3; // 유두리 공속(기본 80) (일반 유저가 speed hack 에 걸리는 것을 막기 위해 *3 추가. 2013.09.11 CYH)
DWORD riding_bonus = 0; DWORD riding_bonus = 0;
if (ch->IsRiding()) if (ch->IsRiding())
{ {
// 뭔가를 탔으면 추가공속 50 // 뭔가를 탔으면 추가공속 50
riding_bonus = 50; riding_bonus = 50;
} }
DWORD ani_speed = ani_attack_speed(ch); DWORD ani_speed = ani_attack_speed(ch);
DWORD real_speed = (ani_speed * 100) / (default_bonus + ch->GetPoint(POINT_ATT_SPEED) + riding_bonus); DWORD real_speed = (ani_speed * 100) / (default_bonus + ch->GetPoint(POINT_ATT_SPEED) + riding_bonus);
// 단검의 경우 공속 2배 // 단검의 경우 공속 2배
if (item && item->GetSubType() == WEAPON_DAGGER) if (item && item->GetSubType() == WEAPON_DAGGER)
real_speed /= 2; real_speed /= 2;

View File

@ -170,10 +170,10 @@ static int FN_random_index()
return 0; return 0;
} }
// 충기환의 확률 테이블 // 충기환의 확률 테이블
// blend.txt에서 확률도 받도록 고치면 깔끔하겠지만 // blend.txt에서 확률도 받도록 고치면 깔끔하겠지만
// 각 나라별로 item proto 등을 따로 관리하므로, // 각 나라별로 item proto 등을 따로 관리하므로,
// 혼란이 올 수 있어 이렇게 추가한다. // 혼란이 올 수 있어 이렇게 추가한다.
// by rtsummit // by rtsummit
static int FN_ECS_random_index() static int FN_ECS_random_index()

View File

@ -119,7 +119,7 @@ bool is_blocked_country_ip(const char *user_ip)
#endif #endif
{ {
SPDLOG_INFO("BLOCKED_COUNTRY_IP ({}) : YES", user_ip); SPDLOG_INFO("BLOCKED_COUNTRY_IP ({}) : YES", user_ip);
return true; // 아이피가 괴상하니 일단 블럭처리 return true; // 아이피가 괴상하니 일단 블럭처리
} }
ip_number = htonl(st_addr.s_addr); ip_number = htonl(st_addr.s_addr);

View File

@ -39,8 +39,8 @@ void CBuffOnAttributes::RemoveBuffFromItem(LPITEM pItem)
{ {
TPlayerItemAttribute attr = pItem->GetAttribute(j); TPlayerItemAttribute attr = pItem->GetAttribute(j);
TMapAttr::iterator it = m_map_additional_attrs.find(attr.bType); TMapAttr::iterator it = m_map_additional_attrs.find(attr.bType);
// m_map_additional_attrs에서 해당 attribute type에 대한 값을 제거하고, // m_map_additional_attrs에서 해당 attribute type에 대한 값을 제거하고,
// 변경된 값의 (m_bBuffValue)%만큼의 버프 효과 감소 // 변경된 값의 (m_bBuffValue)%만큼의 버프 효과 감소
if (it != m_map_additional_attrs.end()) if (it != m_map_additional_attrs.end())
{ {
int& sum_of_attr_value = it->second; int& sum_of_attr_value = it->second;
@ -76,15 +76,15 @@ void CBuffOnAttributes::AddBuffFromItem(LPITEM pItem)
TPlayerItemAttribute attr = pItem->GetAttribute(j); TPlayerItemAttribute attr = pItem->GetAttribute(j);
TMapAttr::iterator it = m_map_additional_attrs.find(attr.bType); TMapAttr::iterator it = m_map_additional_attrs.find(attr.bType);
// m_map_additional_attrs에서 해당 attribute type에 대한 값이 없다면 추가. // m_map_additional_attrs에서 해당 attribute type에 대한 값이 없다면 추가.
// 추가된 값의 (m_bBuffValue)%만큼의 버프 효과 추가 // 추가된 값의 (m_bBuffValue)%만큼의 버프 효과 추가
if (it == m_map_additional_attrs.end()) if (it == m_map_additional_attrs.end())
{ {
m_pBuffOwner->ApplyPoint(attr.bType, attr.sValue * m_bBuffValue / 100); m_pBuffOwner->ApplyPoint(attr.bType, attr.sValue * m_bBuffValue / 100);
m_map_additional_attrs.insert(TMapAttr::value_type(attr.bType, attr.sValue)); m_map_additional_attrs.insert(TMapAttr::value_type(attr.bType, attr.sValue));
} }
// m_map_additional_attrs에서 해당 attribute type에 대한 값이 있다면, 그 값을 증가시키고, // m_map_additional_attrs에서 해당 attribute type에 대한 값이 있다면, 그 값을 증가시키고,
// 변경된 값의 (m_bBuffValue)%만큼의 버프 효과 추가 // 변경된 값의 (m_bBuffValue)%만큼의 버프 효과 추가
else else
{ {
int& sum_of_attr_value = it->second; int& sum_of_attr_value = it->second;
@ -105,8 +105,8 @@ void CBuffOnAttributes::ChangeBuffValue(BYTE bNewValue)
Off(); Off();
else else
{ {
// 기존에, m_map_additional_attrs의 값의 (m_bBuffValue)%만큼이 버프로 들어가 있었으므로, // 기존에, m_map_additional_attrs의 값의 (m_bBuffValue)%만큼이 버프로 들어가 있었으므로,
// (bNewValue)%만큼으로 값을 변경함. // (bNewValue)%만큼으로 값을 변경함.
for (TMapAttr::iterator it = m_map_additional_attrs.begin(); it != m_map_additional_attrs.end(); it++) for (TMapAttr::iterator it = m_map_additional_attrs.begin(); it != m_map_additional_attrs.end(); it++)
{ {
int& sum_of_attr_value = it->second; int& sum_of_attr_value = it->second;

View File

@ -112,7 +112,7 @@ void CObject::EncodeInsertPacket(LPENTITY entity)
pack.z = GetZ(); pack.z = GetZ();
pack.wRaceNum = m_data.dwVnum; pack.wRaceNum = m_data.dwVnum;
// 빌딩 회전 정보(벽일때는 문 위치)를 변환 // 빌딩 회전 정보(벽일때는 문 위치)를 변환
pack.dwAffectFlag[0] = unsigned(m_data.xRot); pack.dwAffectFlag[0] = unsigned(m_data.xRot);
pack.dwAffectFlag[1] = unsigned(m_data.yRot); pack.dwAffectFlag[1] = unsigned(m_data.yRot);
@ -298,7 +298,7 @@ void CObject::RegenNPC()
m_chNPC->SetGuild(pGuild); m_chNPC->SetGuild(pGuild);
// 힘의 신전일 경우 길드 레벨을 길마에게 저장해놓는다 // 힘의 신전일 경우 길드 레벨을 길마에게 저장해놓는다
if ( m_pProto->dwVnum == 14061 || m_pProto->dwVnum == 14062 || m_pProto->dwVnum == 14063 ) if ( m_pProto->dwVnum == 14061 || m_pProto->dwVnum == 14062 || m_pProto->dwVnum == 14063 )
{ {
quest::PC* pPC = quest::CQuestManager::instance().GetPC(pGuild->GetMasterPID()); quest::PC* pPC = quest::CQuestManager::instance().GetPC(pGuild->GetMasterPID());
@ -690,10 +690,10 @@ TObjectProto * CManager::GetObjectProto(DWORD dwVnum)
bool CManager::LoadLand(TLand * pTable) // from DB bool CManager::LoadLand(TLand * pTable) // from DB
{ {
// MapAllow에 없는 맵의 땅일지라도 load를 해야한다. // MapAllow에 없는 맵의 땅일지라도 load를 해야한다.
// 건물(object)이 어느 길드에 속해 있는지 알기 위해서는 건물이 세위진 땅이 어느 길드 소속인지 알아한다. // 건물(object)이 어느 길드에 속해 있는지 알기 위해서는 건물이 세위진 땅이 어느 길드 소속인지 알아한다.
// 만약 땅을 load해 놓지 않으면 길드 건물이 어느 길드에 소속된 건지 알지 못해서 // 만약 땅을 load해 놓지 않으면 길드 건물이 어느 길드에 소속된 건지 알지 못해서
// 길드 건물에 의한 길드 버프를 받지 못한다. // 길드 건물에 의한 길드 버프를 받지 못한다.
//if (!map_allow_find(pTable->lMapIndex)) //if (!map_allow_find(pTable->lMapIndex))
// return false; // return false;
@ -1098,7 +1098,7 @@ bool CLand::RequestCreateWall(int nMapIndex, float rot)
int wall_half_w = 1000; int wall_half_w = 1000;
int wall_half_h = 1362; int wall_half_h = 1362;
if (rot == 0.0f) // 남쪽 문 if (rot == 0.0f) // 남쪽 문
{ {
int door_x = wall_x; int door_x = wall_x;
int door_y = wall_y + wall_half_h; int door_y = wall_y + wall_half_h;
@ -1107,7 +1107,7 @@ bool CLand::RequestCreateWall(int nMapIndex, float rot)
RequestCreateObject(WALL_LEFT_VNUM, nMapIndex, wall_x - wall_half_w, wall_y, door_x, door_y, 0.0f, WALL_ANOTHER_CHECKING_ENABLE); RequestCreateObject(WALL_LEFT_VNUM, nMapIndex, wall_x - wall_half_w, wall_y, door_x, door_y, 0.0f, WALL_ANOTHER_CHECKING_ENABLE);
RequestCreateObject(WALL_RIGHT_VNUM, nMapIndex, wall_x + wall_half_w, wall_y, door_x, door_y, 0.0f, WALL_ANOTHER_CHECKING_ENABLE); RequestCreateObject(WALL_RIGHT_VNUM, nMapIndex, wall_x + wall_half_w, wall_y, door_x, door_y, 0.0f, WALL_ANOTHER_CHECKING_ENABLE);
} }
else if (rot == 180.0f) // 북쪽 문 else if (rot == 180.0f) // 북쪽 문
{ {
int door_x = wall_x; int door_x = wall_x;
int door_y = wall_y - wall_half_h; int door_y = wall_y - wall_half_h;
@ -1116,7 +1116,7 @@ bool CLand::RequestCreateWall(int nMapIndex, float rot)
RequestCreateObject(WALL_LEFT_VNUM, nMapIndex, wall_x - wall_half_w, wall_y, door_x, door_y, 0.0f, WALL_ANOTHER_CHECKING_ENABLE); RequestCreateObject(WALL_LEFT_VNUM, nMapIndex, wall_x - wall_half_w, wall_y, door_x, door_y, 0.0f, WALL_ANOTHER_CHECKING_ENABLE);
RequestCreateObject(WALL_RIGHT_VNUM, nMapIndex, wall_x + wall_half_w, wall_y, door_x, door_y, 0.0f, WALL_ANOTHER_CHECKING_ENABLE); RequestCreateObject(WALL_RIGHT_VNUM, nMapIndex, wall_x + wall_half_w, wall_y, door_x, door_y, 0.0f, WALL_ANOTHER_CHECKING_ENABLE);
} }
else if (rot == 90.0f) // 동쪽 문 else if (rot == 90.0f) // 동쪽 문
{ {
int door_x = wall_x + wall_half_h; int door_x = wall_x + wall_half_h;
int door_y = wall_y; int door_y = wall_y;
@ -1125,7 +1125,7 @@ bool CLand::RequestCreateWall(int nMapIndex, float rot)
RequestCreateObject(WALL_LEFT_VNUM, nMapIndex, wall_x, wall_y - wall_half_w, door_x, door_y, 90.0f, WALL_ANOTHER_CHECKING_ENABLE); RequestCreateObject(WALL_LEFT_VNUM, nMapIndex, wall_x, wall_y - wall_half_w, door_x, door_y, 90.0f, WALL_ANOTHER_CHECKING_ENABLE);
RequestCreateObject(WALL_RIGHT_VNUM, nMapIndex, wall_x, wall_y + wall_half_w, door_x, door_y, 90.0f, WALL_ANOTHER_CHECKING_ENABLE); RequestCreateObject(WALL_RIGHT_VNUM, nMapIndex, wall_x, wall_y + wall_half_w, door_x, door_y, 90.0f, WALL_ANOTHER_CHECKING_ENABLE);
} }
else if (rot == 270.0f) // 서쪽 문 else if (rot == 270.0f) // 서쪽 문
{ {
int door_x = wall_x - wall_half_h; int door_x = wall_x - wall_half_h;
int door_y = wall_y; int door_y = wall_y;

View File

@ -3,8 +3,8 @@
* file : castle.cpp * file : castle.cpp
* author : mhh * author : mhh
* description : * description :
* 봉화 번호 : 11506 - 11510 * 봉화 번호 : 11506 - 11510
* 메틴석 번호 : 8012 - 8014, 8024-8027 * 메틴석 번호 : 8012 - 8014, 8024-8027
*/ */
#define _castle_cpp_ #define _castle_cpp_
@ -21,13 +21,13 @@
#include "char.h" #include "char.h"
#include "sectree_manager.h" #include "sectree_manager.h"
#define EMPIRE_NONE 0 // 아무국가 아님 #define EMPIRE_NONE 0 // 아무국가 아님
#define EMPIRE_RED 1 // 신수 #define EMPIRE_RED 1 // 신수
#define EMPIRE_YELLOW 2 // 천조 #define EMPIRE_YELLOW 2 // 천조
#define EMPIRE_BLUE 3 // 진노 #define EMPIRE_BLUE 3 // 진노
#define SIEGE_EVENT_PULSE PASSES_PER_SEC(60*5) // 5분 #define SIEGE_EVENT_PULSE PASSES_PER_SEC(60*5) // 5분
#define GET_CAHR_MANAGER() CHARACTER_MANAGER::instance() #define GET_CAHR_MANAGER() CHARACTER_MANAGER::instance()
@ -171,7 +171,7 @@ static POSITION s_frog_pos[4][MAX_CASTLE_FROG] = {
}; };
/* 경비병 경비구역 */ /* 경비병 경비구역 */
struct GUARD_REGION struct GUARD_REGION
{ {
int sx, sy, ex, ey; int sx, sy, ex, ey;
@ -247,7 +247,7 @@ EVENTFUNC(castle_siege_event)
info->pulse += SIEGE_EVENT_PULSE; info->pulse += SIEGE_EVENT_PULSE;
// 공성 시작후 30분 이내라면 안내만 하자 // 공성 시작후 30분 이내라면 안내만 하자
if (info->pulse < PASSES_PER_SEC(30*60)) if (info->pulse < PASSES_PER_SEC(30*60))
{ {
snprintf(buf, sizeof(buf), LC_TEXT("%s\xBF\xA1\xBC\xAD \xBA\xC0\xC8\xAD\xB8\xA6 \xB5\xD1\xB7\xAF\xBD\xCE\xB0\xED \xC0\xFC\xC5\xF5\xB0\xA1 \xC1\xF8\xC7\xE0\xC1\xDF\xC0\xD4\xB4\xCF\xB4\xD9."), snprintf(buf, sizeof(buf), LC_TEXT("%s\xBF\xA1\xBC\xAD \xBA\xC0\xC8\xAD\xB8\xA6 \xB5\xD1\xB7\xAF\xBD\xCE\xB0\xED \xC0\xFC\xC5\xF5\xB0\xA1 \xC1\xF8\xC7\xE0\xC1\xDF\xC0\xD4\xB4\xCF\xB4\xD9."),
@ -272,7 +272,7 @@ EVENTFUNC(castle_siege_event)
GET_SIEGE_STATE() = CASTLE_SIEGE_END; GET_SIEGE_STATE() = CASTLE_SIEGE_END;
return PASSES_PER_SEC(60*30); // 30분 return PASSES_PER_SEC(60*30); // 30분
} }
break; break;
case CASTLE_SIEGE_END: case CASTLE_SIEGE_END:
@ -331,7 +331,7 @@ EVENTFUNC(castle_stone_event)
if (NULL == sectree_map) if (NULL == sectree_map)
return 0; return 0;
/* 15마리씩 2번 소환 */ /* 15마리씩 2번 소환 */
const int SPAWN_COUNT = 15; const int SPAWN_COUNT = 15;
if (info->spawn_count < (SPAWN_COUNT * 2)) if (info->spawn_count < (SPAWN_COUNT * 2))
@ -351,7 +351,7 @@ EVENTFUNC(castle_stone_event)
info->spawn_count += SPAWN_COUNT; info->spawn_count += SPAWN_COUNT;
if (info->spawn_count < (SPAWN_COUNT * 2)) if (info->spawn_count < (SPAWN_COUNT * 2))
return PASSES_PER_SEC(30 * 60); // 30분 return PASSES_PER_SEC(30 * 60); // 30분
else else
return 0; return 0;
} }
@ -598,24 +598,24 @@ void castle_start_siege(int empire, int tower_count)
castle_spawn_tower(empire, tower_count); castle_spawn_tower(empire, tower_count);
/* 공성 타이머 시작 */ /* 공성 타이머 시작 */
{ {
castle_event_info* info = AllocEventInfo<castle_event_info>(); castle_event_info* info = AllocEventInfo<castle_event_info>();
info->empire = empire; info->empire = empire;
info->pulse = 0; info->pulse = 0;
GET_SIEGE_EVENT(empire) = event_create(castle_siege_event, info, /*5분*/SIEGE_EVENT_PULSE); GET_SIEGE_EVENT(empire) = event_create(castle_siege_event, info, /*5분*/SIEGE_EVENT_PULSE);
} }
/* 메틴석 소환 타이머 시작 */ /* 메틴석 소환 타이머 시작 */
{ {
castle_stone_event_info* info = AllocEventInfo<castle_stone_event_info>(); castle_stone_event_info* info = AllocEventInfo<castle_stone_event_info>();
info->spawn_count = 0; info->spawn_count = 0;
info->empire = empire; info->empire = empire;
GET_STONE_EVENT(empire) = event_create(castle_stone_event, info, /* 1초 */PASSES_PER_SEC(1)); GET_STONE_EVENT(empire) = event_create(castle_stone_event, info, /* 1초 */PASSES_PER_SEC(1));
} }
} }
@ -649,7 +649,7 @@ LPCHARACTER castle_spawn_frog(int empire)
int dir = 1; int dir = 1;
int map_index = FN_castle_map_index(empire); int map_index = FN_castle_map_index(empire);
/* 황금두꺼비 소환할 곳이 있나? */ /* 황금두꺼비 소환할 곳이 있나? */
POSITION *empty_pos = FN_empty_frog_pos(empire); POSITION *empty_pos = FN_empty_frog_pos(empire);
if (NULL == empty_pos) if (NULL == empty_pos)
return NULL; return NULL;
@ -667,7 +667,7 @@ LPCHARACTER castle_spawn_frog(int empire)
{ {
frog->SetEmpire(empire); frog->SetEmpire(empire);
int empty_index = FN_empty_frog_index(empire); int empty_index = FN_empty_frog_index(empire);
// 스폰성공 // 스폰성공
GET_FROG(empire, empty_index) = frog; GET_FROG(empire, empty_index) = frog;
return frog; return frog;
} }
@ -778,7 +778,7 @@ bool castle_spawn_tower(int empire, int tower_count)
if (NULL == sectree_map) if (NULL == sectree_map)
return false; return false;
// 초기화 // 초기화
DO_ALL_TOWER(i) DO_ALL_TOWER(i)
{ {
if (GET_TOWER(empire, i)) if (GET_TOWER(empire, i))
@ -786,7 +786,7 @@ bool castle_spawn_tower(int empire, int tower_count)
GET_TOWER(empire, i) = NULL; GET_TOWER(empire, i) = NULL;
} }
int spawn_count = std::clamp(tower_count, MIN_CASTLE_TOWER, MAX_CASTLE_TOWER); // 5 ~ 10마리 int spawn_count = std::clamp(tower_count, MIN_CASTLE_TOWER, MAX_CASTLE_TOWER); // 5 ~ 10마리
for (int j = 0; j < spawn_count; ++j) for (int j = 0; j < spawn_count; ++j)
{ {
@ -802,7 +802,7 @@ bool castle_spawn_tower(int empire, int tower_count)
return true; return true;
} }
/* 경비병리더가 죽으면 단순하게 슬롯만 비운다. */ /* 경비병리더가 죽으면 단순하게 슬롯만 비운다. */
void castle_guard_die(LPCHARACTER ch, LPCHARACTER killer) void castle_guard_die(LPCHARACTER ch, LPCHARACTER killer)
{ {
int empire = ch->GetEmpire(); int empire = ch->GetEmpire();
@ -823,7 +823,7 @@ void castle_guard_die(LPCHARACTER ch, LPCHARACTER killer)
} }
/* 황금 두꺼비가 죽으면 killer에게 1천만냥 */ /* 황금 두꺼비가 죽으면 killer에게 1천만냥 */
void castle_frog_die(LPCHARACTER ch, LPCHARACTER killer) void castle_frog_die(LPCHARACTER ch, LPCHARACTER killer)
{ {
if (NULL == ch || NULL == killer) if (NULL == ch || NULL == killer)
@ -837,15 +837,15 @@ void castle_frog_die(LPCHARACTER ch, LPCHARACTER killer)
{ {
GET_FROG(empire, i) = NULL; GET_FROG(empire, i) = NULL;
killer->PointChange(POINT_GOLD, 10000000 /*1천만*/, true); killer->PointChange(POINT_GOLD, 10000000 /*1천만*/, true);
//CMonarch::instance().SendtoDBAddMoney(30000000/*3천만*/, killer->GetEmpire(), killer); //CMonarch::instance().SendtoDBAddMoney(30000000/*3천만*/, killer->GetEmpire(), killer);
castle_save(); castle_save();
return; return;
} }
} }
} }
/* 봉화가 모두 죽으면(?) 공성전이 끝난다 */ /* 봉화가 모두 죽으면(?) 공성전이 끝난다 */
void castle_tower_die(LPCHARACTER ch, LPCHARACTER killer) void castle_tower_die(LPCHARACTER ch, LPCHARACTER killer)
{ {
char buf[1024] = {0}; char buf[1024] = {0};
@ -929,27 +929,27 @@ bool castle_is_guard_vnum(DWORD vnum)
{ {
switch (vnum) switch (vnum)
{ {
/* 상급 창경비병 */ /* 상급 창경비병 */
case 11112: case 11112:
case 11114: case 11114:
case 11116: case 11116:
/* 중급 창경비병 */ /* 중급 창경비병 */
case 11106: case 11106:
case 11108: case 11108:
case 11110: case 11110:
/* 하급 창경비병 */ /* 하급 창경비병 */
case 11100: case 11100:
case 11102: case 11102:
case 11104: case 11104:
/* 상급 활경비병 */ /* 상급 활경비병 */
case 11113: case 11113:
case 11115: case 11115:
case 11117: case 11117:
/* 중급 활경비병 */ /* 중급 활경비병 */
case 11107: case 11107:
case 11109: case 11109:
case 11111: case 11111:
/* 하급 활경비병 */ /* 하급 활경비병 */
case 11101: case 11101:
case 11103: case 11103:
case 11105: case 11105:
@ -963,34 +963,34 @@ int castle_cost_of_hiring_guard(DWORD group_vnum)
{ {
switch (group_vnum) switch (group_vnum)
{ {
/* 하급 */ /* 하급 */
case 9501: /* 신수 창경비 */ case 9501: /* 신수 창경비 */
case 9511: /* 진노 창경비 */ case 9511: /* 진노 창경비 */
case 9521: /* 천조 창경비 */ case 9521: /* 천조 창경비 */
case 9502: /* 신수 활경비 */ case 9502: /* 신수 활경비 */
case 9512: /* 진노 활경비 */ case 9512: /* 진노 활경비 */
case 9522: /* 천조 활경비 */ case 9522: /* 천조 활경비 */
return (100*10000); return (100*10000);
/* 중급 */ /* 중급 */
case 9503: /* 신수 창경비 */ case 9503: /* 신수 창경비 */
case 9513: /* 진노 창경비 */ case 9513: /* 진노 창경비 */
case 9523: /* 천조 창경비 */ case 9523: /* 천조 창경비 */
case 9504: /* 신수 활경비 */ case 9504: /* 신수 활경비 */
case 9514: /* 진노 활경비 */ case 9514: /* 진노 활경비 */
case 9524: /* 천조 활경비 */ case 9524: /* 천조 활경비 */
return (300*10000); return (300*10000);
/* 상급 */ /* 상급 */
case 9505: /* 신수 창경비 */ case 9505: /* 신수 창경비 */
case 9515: /* 진노 창경비 */ case 9515: /* 진노 창경비 */
case 9525: /* 천조 창경비 */ case 9525: /* 천조 창경비 */
case 9506: /* 신수 활경비 */ case 9506: /* 신수 활경비 */
case 9516: /* 진노 활경비 */ case 9516: /* 진노 활경비 */
case 9526: /* 천조 활경비 */ case 9526: /* 천조 활경비 */
return (1000*10000); return (1000*10000);
} }
@ -1010,7 +1010,7 @@ bool castle_can_attack(LPCHARACTER ch, LPCHARACTER victim)
if (CASTLE_SIEGE_END == GET_SIEGE_STATE()) if (CASTLE_SIEGE_END == GET_SIEGE_STATE())
{ {
// 수성에 성공했을때 같은 제국만 봉화를 칠 수 있음 // 수성에 성공했을때 같은 제국만 봉화를 칠 수 있음
if (castle_is_tower_vnum(victim->GetRaceNum())) if (castle_is_tower_vnum(victim->GetRaceNum()))
{ {
if (ch->GetEmpire() == victim->GetEmpire()) if (ch->GetEmpire() == victim->GetEmpire())
@ -1020,7 +1020,7 @@ bool castle_can_attack(LPCHARACTER ch, LPCHARACTER victim)
} }
} }
// 같은 제국은 파괴 불가 // 같은 제국은 파괴 불가
if (ch->GetEmpire() == victim->GetEmpire()) if (ch->GetEmpire() == victim->GetEmpire())
return false; return false;
@ -1044,7 +1044,7 @@ bool castle_frog_to_empire_money(LPCHARACTER ch)
if (false == CMonarch::instance().SendtoDBAddMoney(CASTLE_FROG_PRICE, empire, ch)) if (false == CMonarch::instance().SendtoDBAddMoney(CASTLE_FROG_PRICE, empire, ch))
return false; return false;
GET_FROG(empire, i) = NULL; // 등록해제 GET_FROG(empire, i) = NULL; // 등록해제
npc->Dead(/*killer*/NULL, /*immediate_dead*/true); npc->Dead(/*killer*/NULL, /*immediate_dead*/true);
return true; return true;
} }

File diff suppressed because it is too large Load Diff

View File

@ -84,13 +84,13 @@ EVENTFUNC(affect_event)
if (!ch->UpdateAffect()) if (!ch->UpdateAffect())
return 0; return 0;
else else
return passes_per_sec; // 1초 return passes_per_sec; // 1초
} }
bool CHARACTER::UpdateAffect() bool CHARACTER::UpdateAffect()
{ {
// affect_event 에서 처리할 일은 아니지만, 1초짜리 이벤트에서 처리하는 것이 // affect_event 에서 처리할 일은 아니지만, 1초짜리 이벤트에서 처리하는 것이
// 이것 뿐이라 여기서 물약 처리를 한다. // 이것 뿐이라 여기서 물약 처리를 한다.
if (GetPoint(POINT_HP_RECOVERY) > 0) if (GetPoint(POINT_HP_RECOVERY) > 0)
{ {
if (GetMaxHP() <= GetHP()) if (GetMaxHP() <= GetHP())
@ -146,7 +146,7 @@ bool CHARACTER::UpdateAffect()
AutoRecoveryItemProcess( AFFECT_AUTO_HP_RECOVERY ); AutoRecoveryItemProcess( AFFECT_AUTO_HP_RECOVERY );
AutoRecoveryItemProcess( AFFECT_AUTO_SP_RECOVERY ); AutoRecoveryItemProcess( AFFECT_AUTO_SP_RECOVERY );
// 스테미나 회복 // 스테미나 회복
if (GetMaxStamina() > GetStamina()) if (GetMaxStamina() > GetStamina())
{ {
int iSec = (get_dword_time() - GetStopTime()) / 3000; int iSec = (get_dword_time() - GetStopTime()) / 3000;
@ -155,7 +155,7 @@ bool CHARACTER::UpdateAffect()
} }
// ProcessAffect는 affect가 없으면 true를 리턴한다. // ProcessAffect는 affect가 없으면 true를 리턴한다.
if (ProcessAffect()) if (ProcessAffect())
if (GetPoint(POINT_HP_RECOVERY) == 0 && GetPoint(POINT_SP_RECOVERY) == 0 && GetStamina() == GetMaxStamina()) if (GetPoint(POINT_HP_RECOVERY) == 0 && GetPoint(POINT_SP_RECOVERY) == 0 && GetStamina() == GetMaxStamina())
{ {
@ -226,7 +226,7 @@ int CHARACTER::ProcessAffect()
CAffect *pkAff = NULL; CAffect *pkAff = NULL;
// //
// 프리미엄 처리 // 프리미엄 처리
// //
for (int i = 0; i <= PREMIUM_MAX_NUM; ++i) for (int i = 0; i <= PREMIUM_MAX_NUM; ++i)
{ {
@ -300,8 +300,8 @@ int CHARACTER::ProcessAffect()
} }
// AFFECT_DURATION_BUG_FIX // AFFECT_DURATION_BUG_FIX
// 무한 효과 아이템도 시간을 줄인다. // 무한 효과 아이템도 시간을 줄인다.
// 시간을 매우 크게 잡기 때문에 상관 없을 것이라 생각됨. // 시간을 매우 크게 잡기 때문에 상관 없을 것이라 생각됨.
if ( --pkAff->lDuration <= 0 ) if ( --pkAff->lDuration <= 0 )
{ {
bEnd = true; bEnd = true;
@ -470,7 +470,7 @@ void CHARACTER::LoadAffect(DWORD dwCount, TPacketAffectElement * pElements)
for (DWORD i = 0; i < dwCount; ++i, ++pElements) for (DWORD i = 0; i < dwCount; ++i, ++pElements)
{ {
// 무영진은 로드하지않는다. // 무영진은 로드하지않는다.
if (pElements->dwType == SKILL_MUYEONG) if (pElements->dwType == SKILL_MUYEONG)
continue; continue;
@ -524,7 +524,7 @@ void CHARACTER::LoadAffect(DWORD dwCount, TPacketAffectElement * pElements)
m_bIsLoadedAffect = true; m_bIsLoadedAffect = true;
// 용혼석 셋팅 로드 및 초기화 // 용혼석 셋팅 로드 및 초기화
DragonSoul_Initialize(); DragonSoul_Initialize();
} }
@ -562,10 +562,10 @@ bool CHARACTER::AddAffect(DWORD dwType, BYTE bApplyOn, int lApplyValue, DWORD dw
} }
} }
// 이미 있는 효과를 덮어 쓰는 처리 // 이미 있는 효과를 덮어 쓰는 처리
if (pkAff && bOverride) if (pkAff && bOverride)
{ {
ComputeAffect(pkAff, false); // 일단 효과를 삭제하고 ComputeAffect(pkAff, false); // 일단 효과를 삭제하고
if (GetDesc()) if (GetDesc())
SendAffectRemovePacket(GetDesc(), GetPlayerID(), pkAff->dwType, pkAff->bApplyOn); SendAffectRemovePacket(GetDesc(), GetPlayerID(), pkAff->dwType, pkAff->bApplyOn);
@ -573,9 +573,9 @@ bool CHARACTER::AddAffect(DWORD dwType, BYTE bApplyOn, int lApplyValue, DWORD dw
else else
{ {
// //
// 새 에펙를 추가 // 새 에펙를 추가
// //
// NOTE: 따라서 같은 type 으로도 여러 에펙트를 붙을 수 있다. // NOTE: 따라서 같은 type 으로도 여러 에펙트를 붙을 수 있다.
// //
pkAff = CAffect::Acquire(); pkAff = CAffect::Acquire();
m_list_pkAffect.push_back(pkAff); m_list_pkAffect.push_back(pkAff);
@ -677,15 +677,15 @@ bool CHARACTER::RemoveAffect(CAffect * pkAff)
ComputeAffect(pkAff, false); ComputeAffect(pkAff, false);
// 백기 버그 수정. // 백기 버그 수정.
// 백기 버그는 버프 스킬 시전->둔갑->백기 사용(AFFECT_REVIVE_INVISIBLE) 후 바로 공격 할 경우에 발생한다. // 백기 버그는 버프 스킬 시전->둔갑->백기 사용(AFFECT_REVIVE_INVISIBLE) 후 바로 공격 할 경우에 발생한다.
// 원인은 둔갑을 시전하는 시점에, 버프 스킬 효과를 무시하고 둔갑 효과만 적용되게 되어있는데, // 원인은 둔갑을 시전하는 시점에, 버프 스킬 효과를 무시하고 둔갑 효과만 적용되게 되어있는데,
// 백기 사용 후 바로 공격하면 RemoveAffect가 불리게 되고, ComputePoints하면서 둔갑 효과 + 버프 스킬 효과가 된다. // 백기 사용 후 바로 공격하면 RemoveAffect가 불리게 되고, ComputePoints하면서 둔갑 효과 + 버프 스킬 효과가 된다.
// ComputePoints에서 둔갑 상태면 버프 스킬 효과 안 먹히도록 하면 되긴 하는데, // ComputePoints에서 둔갑 상태면 버프 스킬 효과 안 먹히도록 하면 되긴 하는데,
// ComputePoints는 광범위하게 사용되고 있어서 큰 변화를 주는 것이 꺼려진다.(어떤 side effect가 발생할지 알기 힘들다.) // ComputePoints는 광범위하게 사용되고 있어서 큰 변화를 주는 것이 꺼려진다.(어떤 side effect가 발생할지 알기 힘들다.)
// 따라서 AFFECT_REVIVE_INVISIBLE가 RemoveAffect로 삭제되는 경우만 수정한다. // 따라서 AFFECT_REVIVE_INVISIBLE가 RemoveAffect로 삭제되는 경우만 수정한다.
// 시간이 다 되어 백기 효과가 풀리는 경우는 버그가 발생하지 않으므로 그와 똑같이 함. // 시간이 다 되어 백기 효과가 풀리는 경우는 버그가 발생하지 않으므로 그와 똑같이 함.
// (ProcessAffect를 보면 시간이 다 되어서 Affect가 삭제되는 경우, ComputePoints를 부르지 않는다.) // (ProcessAffect를 보면 시간이 다 되어서 Affect가 삭제되는 경우, ComputePoints를 부르지 않는다.)
if (AFFECT_REVIVE_INVISIBLE != pkAff->dwType) if (AFFECT_REVIVE_INVISIBLE != pkAff->dwType)
{ {
ComputePoints(); ComputePoints();
@ -795,41 +795,41 @@ bool CHARACTER::IsGoodAffect(BYTE bAffectType) const
void CHARACTER::RemoveBadAffect() void CHARACTER::RemoveBadAffect()
{ {
SPDLOG_DEBUG("RemoveBadAffect {}", GetName()); SPDLOG_DEBUG("RemoveBadAffect {}", GetName());
// 독 // 독
RemovePoison(); RemovePoison();
RemoveFire(); RemoveFire();
// 스턴 : Value%로 상대방을 5초간 머리 위에 별이 돌아간다. (때리면 1/2 확률로 풀림) AFF_STUN // 스턴 : Value%로 상대방을 5초간 머리 위에 별이 돌아간다. (때리면 1/2 확률로 풀림) AFF_STUN
RemoveAffect(AFFECT_STUN); RemoveAffect(AFFECT_STUN);
// 슬로우 : Value%로 상대방의 공속/이속 모두 느려진다. 수련도에 따라 달라짐 기술로 사용 한 경우에 AFF_SLOW // 슬로우 : Value%로 상대방의 공속/이속 모두 느려진다. 수련도에 따라 달라짐 기술로 사용 한 경우에 AFF_SLOW
RemoveAffect(AFFECT_SLOW); RemoveAffect(AFFECT_SLOW);
// 투속마령 // 투속마령
RemoveAffect(SKILL_TUSOK); RemoveAffect(SKILL_TUSOK);
// 저주 // 저주
//RemoveAffect(SKILL_CURSE); //RemoveAffect(SKILL_CURSE);
// 파법술 // 파법술
//RemoveAffect(SKILL_PABUP); //RemoveAffect(SKILL_PABUP);
// 기절 : Value%로 상대방을 기절시킨다. 2초 AFF_FAINT // 기절 : Value%로 상대방을 기절시킨다. 2초 AFF_FAINT
//RemoveAffect(AFFECT_FAINT); //RemoveAffect(AFFECT_FAINT);
// 다리묶임 : Value%로 상대방의 이동속도를 떨어트린다. 5초간 -40 AFF_WEB // 다리묶임 : Value%로 상대방의 이동속도를 떨어트린다. 5초간 -40 AFF_WEB
//RemoveAffect(AFFECT_WEB); //RemoveAffect(AFFECT_WEB);
// 잠들기 : Value%로 상대방을 10초간 잠재운다. (때리면 풀림) AFF_SLEEP // 잠들기 : Value%로 상대방을 10초간 잠재운다. (때리면 풀림) AFF_SLEEP
//RemoveAffect(AFFECT_SLEEP); //RemoveAffect(AFFECT_SLEEP);
// 저주 : Value%로 상대방의 공등/방등 모두 떨어트린다. 수련도에 따라 달라짐 기술로 사용 한 경우에 AFF_CURSE // 저주 : Value%로 상대방의 공등/방등 모두 떨어트린다. 수련도에 따라 달라짐 기술로 사용 한 경우에 AFF_CURSE
//RemoveAffect(AFFECT_CURSE); //RemoveAffect(AFFECT_CURSE);
// 마비 : Value%로 상대방을 4초간 마비시킨다. AFF_PARA // 마비 : Value%로 상대방을 4초간 마비시킨다. AFF_PARA
//RemoveAffect(AFFECT_PARALYZE); //RemoveAffect(AFFECT_PARALYZE);
// 부동박부 : 무당 기술 // 부동박부 : 무당 기술
//RemoveAffect(SKILL_BUDONG); //RemoveAffect(SKILL_BUDONG);
} }

File diff suppressed because it is too large Load Diff

View File

@ -9,12 +9,12 @@
/* /*
Return Value Return Value
0 : 알 수 없는 에러 or 쿼리 에러 0 : 알 수 없는 에러 or 쿼리 에러
1 : 동일한 제국으로 바꾸려고함 1 : 동일한 제국으로 바꾸려고함
2 : 길드 가입한 캐릭터가 있음 2 : 길드 가입한 캐릭터가 있음
3 : 결혼한 캐릭터가 있음 3 : 결혼한 캐릭터가 있음
999 : 제국 이동 성공 999 : 제국 이동 성공
*/ */
int CHARACTER::ChangeEmpire(BYTE empire) int CHARACTER::ChangeEmpire(BYTE empire)
{ {
@ -27,7 +27,7 @@ int CHARACTER::ChangeEmpire(BYTE empire)
memset(dwPID, 0, sizeof(dwPID)); memset(dwPID, 0, sizeof(dwPID));
{ {
// 1. 내 계정의 모든 pid를 얻어 온다 // 1. 내 계정의 모든 pid를 얻어 온다
snprintf(szQuery, sizeof(szQuery), snprintf(szQuery, sizeof(szQuery),
"SELECT id, pid1, pid2, pid3, pid4 FROM player_index%s WHERE pid1=%u OR pid2=%u OR pid3=%u OR pid4=%u AND empire=%u", "SELECT id, pid1, pid2, pid3, pid4 FROM player_index%s WHERE pid1=%u OR pid2=%u OR pid3=%u OR pid4=%u AND empire=%u",
get_table_postfix(), GetPlayerID(), GetPlayerID(), GetPlayerID(), GetPlayerID(), GetEmpire()); get_table_postfix(), GetPlayerID(), GetPlayerID(), GetPlayerID(), GetPlayerID(), GetEmpire());
@ -51,8 +51,8 @@ int CHARACTER::ChangeEmpire(BYTE empire)
const int loop = 4; const int loop = 4;
{ {
// 2. 각 캐릭터의 길드 정보를 얻어온다. // 2. 각 캐릭터의 길드 정보를 얻어온다.
// 한 캐릭터라도 길드에 가입 되어 있다면, 제국 이동을 할 수 없다. // 한 캐릭터라도 길드에 가입 되어 있다면, 제국 이동을 할 수 없다.
DWORD dwGuildID[4]; DWORD dwGuildID[4];
CGuild * pGuild[4]; CGuild * pGuild[4];
SQLMsg * pMsg = NULL; SQLMsg * pMsg = NULL;
@ -91,8 +91,8 @@ int CHARACTER::ChangeEmpire(BYTE empire)
} }
{ {
// 3. 각 캐릭터의 결혼 정보를 얻어온다. // 3. 각 캐릭터의 결혼 정보를 얻어온다.
// 한 캐릭터라도 결혼 상태라면 제국 이동을 할 수 없다. // 한 캐릭터라도 결혼 상태라면 제국 이동을 할 수 없다.
for (int i = 0; i < loop; ++i) for (int i = 0; i < loop; ++i)
{ {
if (marriage::CManager::instance().IsEngagedOrMarried(dwPID[i]) == true) if (marriage::CManager::instance().IsEngagedOrMarried(dwPID[i]) == true)
@ -101,7 +101,7 @@ int CHARACTER::ChangeEmpire(BYTE empire)
} }
{ {
// 4. db의 제국 정보를 업데이트 한다. // 4. db의 제국 정보를 업데이트 한다.
snprintf(szQuery, sizeof(szQuery), "UPDATE player_index%s SET empire=%u WHERE pid1=%u OR pid2=%u OR pid3=%u OR pid4=%u AND empire=%u", snprintf(szQuery, sizeof(szQuery), "UPDATE player_index%s SET empire=%u WHERE pid1=%u OR pid2=%u OR pid3=%u OR pid4=%u AND empire=%u",
get_table_postfix(), empire, GetPlayerID(), GetPlayerID(), GetPlayerID(), GetPlayerID(), GetEmpire()); get_table_postfix(), empire, GetPlayerID(), GetPlayerID(), GetPlayerID(), GetPlayerID(), GetEmpire());
@ -109,7 +109,7 @@ int CHARACTER::ChangeEmpire(BYTE empire)
if (msg->Get()->uiAffectedRows > 0) if (msg->Get()->uiAffectedRows > 0)
{ {
// 5. 제국 변경 이력을 추가한다. // 5. 제국 변경 이력을 추가한다.
SetChangeEmpireCount(); SetChangeEmpireCount();
return 999; return 999;

View File

@ -5,14 +5,14 @@
#include "DragonSoul.h" #include "DragonSoul.h"
#include "log.h" #include "log.h"
// 용혼석 초기화 // 용혼석 초기화
// 용혼석 on/off는 Affect로 저장되기 때문에, // 용혼석 on/off는 Affect로 저장되기 때문에,
// 용혼석 Affect가 있다면 덱에 있는 용혼석을 activate해야한다. // 용혼석 Affect가 있다면 덱에 있는 용혼석을 activate해야한다.
// 또한 용혼석 사용 자격은 QuestFlag로 저장해 놓았기 때문에, // 또한 용혼석 사용 자격은 QuestFlag로 저장해 놓았기 때문에,
// 퀘스트 Flag에서 용혼석 사용 자격을 읽어온다. // 퀘스트 Flag에서 용혼석 사용 자격을 읽어온다.
// 캐릭터의 affect, quest가 load 되기 전에 DragonSoul_Initialize를 호출하면 안된다. // 캐릭터의 affect, quest가 load 되기 전에 DragonSoul_Initialize를 호출하면 안된다.
// affect가 가장 마지막에 로드되어 LoadAffect에서 호출함. // affect가 가장 마지막에 로드되어 LoadAffect에서 호출함.
void CHARACTER::DragonSoul_Initialize() void CHARACTER::DragonSoul_Initialize()
{ {
for (int i = INVENTORY_MAX_NUM + WEAR_MAX_NUM; i < DRAGON_SOUL_EQUIP_SLOT_END; i++) for (int i = INVENTORY_MAX_NUM + WEAR_MAX_NUM; i < DRAGON_SOUL_EQUIP_SLOT_END; i++)
@ -55,7 +55,7 @@ void CHARACTER::DragonSoul_GiveQualification()
} }
AddAffect(AFFECT_DRAGON_SOUL_QUALIFIED, APPLY_NONE, 0, AFF_NONE, INFINITE_AFFECT_DURATION, 0, false, false); AddAffect(AFFECT_DRAGON_SOUL_QUALIFIED, APPLY_NONE, 0, AFF_NONE, INFINITE_AFFECT_DURATION, 0, false, false);
//SetQuestFlag("dragon_soul.is_qualified", 1); //SetQuestFlag("dragon_soul.is_qualified", 1);
//// 자격있다면 POINT_DRAGON_SOUL_IS_QUALIFIED는 무조건 1 //// 자격있다면 POINT_DRAGON_SOUL_IS_QUALIFIED는 무조건 1
//PointChange(POINT_DRAGON_SOUL_IS_QUALIFIED, 1 - GetPoint(POINT_DRAGON_SOUL_IS_QUALIFIED)); //PointChange(POINT_DRAGON_SOUL_IS_QUALIFIED, 1 - GetPoint(POINT_DRAGON_SOUL_IS_QUALIFIED));
} }

View File

@ -27,7 +27,7 @@ bool CHARACTER::StartRiding()
return false; return false;
} }
// 턱시도 입은 상태의 말 타기 금지 // 턱시도 입은 상태의 말 타기 금지
LPITEM armor = GetWear(WEAR_BODY); LPITEM armor = GetWear(WEAR_BODY);
if (armor && (armor->GetVnum() >= 11901 && armor->GetVnum() <= 11904)) if (armor && (armor->GetVnum() >= 11901 && armor->GetVnum() <= 11904))
@ -57,7 +57,7 @@ bool CHARACTER::StartRiding()
return false; return false;
} }
// 소환한 말 없애고 // 소환한 말 없애고
HorseSummon(false); HorseSummon(false);
MountVnum(dwMountVnum); MountVnum(dwMountVnum);
@ -78,7 +78,7 @@ bool CHARACTER::StopRiding()
DWORD dwOldVnum = GetMountVnum(); DWORD dwOldVnum = GetMountVnum();
MountVnum(0); MountVnum(0);
// [NOTE] 말에서 내릴 땐 자기가 탔던걸 소환하도록 수정 // [NOTE] 말에서 내릴 땐 자기가 탔던걸 소환하도록 수정
HorseSummon(true, false, dwOldVnum); HorseSummon(true, false, dwOldVnum);
} }
else else
@ -139,14 +139,14 @@ void CHARACTER::HorseSummon(bool bSummon, bool bFromFar, DWORD dwVnum, const cha
{ {
if ( bSummon ) if ( bSummon )
{ {
//NOTE : summon했는데 이미 horse가 있으면 아무것도 안한다. //NOTE : summon했는데 이미 horse가 있으면 아무것도 안한다.
if( m_chHorse != NULL ) if( m_chHorse != NULL )
return; return;
if (GetHorseLevel() <= 0) if (GetHorseLevel() <= 0)
return; return;
// 무언가를 타고 있다면 실패 // 무언가를 타고 있다면 실패
if (IsRiding()) if (IsRiding())
return; return;
@ -183,10 +183,10 @@ void CHARACTER::HorseSummon(bool bSummon, bool bFromFar, DWORD dwVnum, const cha
if (GetHorseHealth() <= 0) if (GetHorseHealth() <= 0)
{ {
// 죽은거처럼 있게 하는 처리 // 죽은거처럼 있게 하는 처리
m_chHorse->SetPosition(POS_DEAD); m_chHorse->SetPosition(POS_DEAD);
// 일정시간있다 사라지게 하자. // 일정시간있다 사라지게 하자.
char_event_info* info = AllocEventInfo<char_event_info>(); char_event_info* info = AllocEventInfo<char_event_info>();
info->ch = this; info->ch = this;
m_chHorse->m_pkDeadEvent = event_create(horse_dead_event, info, PASSES_PER_SEC(60)); m_chHorse->m_pkDeadEvent = event_create(horse_dead_event, info, PASSES_PER_SEC(60));
@ -239,7 +239,7 @@ void CHARACTER::HorseSummon(bool bSummon, bool bFromFar, DWORD dwVnum, const cha
} }
else else
{ {
// 멀어지면서 사라지는 처리 하기 // 멀어지면서 사라지는 처리 하기
chHorse->SetNowWalking(false); chHorse->SetNowWalking(false);
float fx, fy; float fx, fy;
chHorse->SetRotation(GetDegreeFromPositionXY(chHorse->GetX(), chHorse->GetY(), GetX(), GetY())+180); chHorse->SetRotation(GetDegreeFromPositionXY(chHorse->GetX(), chHorse->GetY(), GetX(), GetY())+180);
@ -310,7 +310,7 @@ void CHARACTER::SendHorseInfo()
3: 70% < ~ <= 100% 3: 70% < ~ <= 100%
2: 30% < ~ <= 70% 2: 30% < ~ <= 70%
1: 0% < ~ <= 30% 1: 0% < ~ <= 30%
0: 사망 0: 사망
STM STM
@ -343,8 +343,8 @@ STM
{ {
ChatPacket(CHAT_TYPE_COMMAND, "horse_state %d %d %d", GetHorseLevel(), iHealthGrade, iStaminaGrade); ChatPacket(CHAT_TYPE_COMMAND, "horse_state %d %d %d", GetHorseLevel(), iHealthGrade, iStaminaGrade);
// FIX : 클라이언트에 "\xB8\xBB \xBB\xF3\xC5\xC2 \xB9\xF6\xC7\xC1" 아이콘을 표시하지 않을 목적으로 함수 초입에 return함으로써 아래 코드를 무시한다면 // FIX : 클라이언트에 "\xB8\xBB \xBB\xF3\xC5\xC2 \xB9\xF6\xC7\xC1" 아이콘을 표시하지 않을 목적으로 함수 초입에 return함으로써 아래 코드를 무시한다면
// 말을 무한대로 소환하는 무시무시한 버그가 생김.. 정확한 원인은 파악 안해봐서 모름. // 말을 무한대로 소환하는 무시무시한 버그가 생김.. 정확한 원인은 파악 안해봐서 모름.
m_bSendHorseLevel = GetHorseLevel(); m_bSendHorseLevel = GetHorseLevel();
m_bSendHorseHealthGrade = iHealthGrade; m_bSendHorseHealthGrade = iHealthGrade;
m_bSendHorseStaminaGrade = iStaminaGrade; m_bSendHorseStaminaGrade = iStaminaGrade;
@ -366,7 +366,7 @@ bool CHARACTER::CanUseHorseSkill()
if (GetMountVnum() >= 20209 && GetMountVnum() <= 20212) if (GetMountVnum() >= 20209 && GetMountVnum() <= 20212)
return true; return true;
//라마단 흑마 //라마단 흑마
if (CMobVnumHelper::IsRamadanBlackHorse(GetMountVnum())) if (CMobVnumHelper::IsRamadanBlackHorse(GetMountVnum()))
return true; return true;
} }

File diff suppressed because it is too large Load Diff

View File

@ -114,7 +114,7 @@ void CHARACTER_MANAGER::DestroyCharacter(LPCHARACTER ch, const char* file, size_
return; // prevent duplicated destrunction return; // prevent duplicated destrunction
} }
// 던전에 소속된 몬스터는 던전에서도 삭제하도록. // 던전에 소속된 몬스터는 던전에서도 삭제하도록.
if (ch->IsNPC() && !ch->IsPet() && ch->GetRider() == NULL) if (ch->IsNPC() && !ch->IsPet() && ch->GetRider() == NULL)
{ {
if (ch->GetDungeon()) if (ch->GetDungeon())
@ -230,7 +230,7 @@ LPCHARACTER CHARACTER_MANAGER::FindPC(const char * name)
LPCHARACTER CHARACTER_MANAGER::SpawnMobRandomPosition(DWORD dwVnum, int lMapIndex) LPCHARACTER CHARACTER_MANAGER::SpawnMobRandomPosition(DWORD dwVnum, int lMapIndex)
{ {
// 왜구 스폰할지말지를 결정할 수 있게함 // 왜구 스폰할지말지를 결정할 수 있게함
{ {
if (dwVnum == 5001 && !quest::CQuestManager::instance().GetEventFlag("japan_regen")) if (dwVnum == 5001 && !quest::CQuestManager::instance().GetEventFlag("japan_regen"))
{ {
@ -239,7 +239,7 @@ LPCHARACTER CHARACTER_MANAGER::SpawnMobRandomPosition(DWORD dwVnum, int lMapInde
} }
} }
// 해태를 스폰할지 말지를 결정할 수 있게 함 // 해태를 스폰할지 말지를 결정할 수 있게 함
{ {
if (dwVnum == 5002 && !quest::CQuestManager::instance().GetEventFlag("newyear_mob")) if (dwVnum == 5002 && !quest::CQuestManager::instance().GetEventFlag("newyear_mob"))
{ {
@ -248,7 +248,7 @@ LPCHARACTER CHARACTER_MANAGER::SpawnMobRandomPosition(DWORD dwVnum, int lMapInde
} }
} }
// 광복절 이벤트 // 광복절 이벤트
{ {
if (dwVnum == 5004 && !quest::CQuestManager::instance().GetEventFlag("independence_day")) if (dwVnum == 5004 && !quest::CQuestManager::instance().GetEventFlag("independence_day"))
{ {
@ -448,7 +448,7 @@ LPCHARACTER CHARACTER_MANAGER::SpawnMobRange(DWORD dwVnum, int lMapIndex, int sx
if (!pkMob) if (!pkMob)
return NULL; return NULL;
if (pkMob->m_table.bType == CHAR_TYPE_STONE) // 돌은 무조건 SPAWN 모션이 있다. if (pkMob->m_table.bType == CHAR_TYPE_STONE) // 돌은 무조건 SPAWN 모션이 있다.
bSpawnMotion = true; bSpawnMotion = true;
int i = 16; int i = 16;
@ -512,7 +512,7 @@ bool CHARACTER_MANAGER::SpawnMoveGroup(DWORD dwVnum, int lMapIndex, int sx, int
if (!tch) if (!tch)
{ {
if (i == 0) // 못만든 몬스터가 대장일 경우에는 그냥 실패 if (i == 0) // 못만든 몬스터가 대장일 경우에는 그냥 실패
return false; return false;
continue; continue;
@ -596,7 +596,7 @@ LPCHARACTER CHARACTER_MANAGER::SpawnGroup(DWORD dwVnum, int lMapIndex, int sx, i
if (!tch) if (!tch)
{ {
if (i == 0) // 못만든 몬스터가 대장일 경우에는 그냥 실패 if (i == 0) // 못만든 몬스터가 대장일 경우에는 그냥 실패
return NULL; return NULL;
continue; continue;
@ -652,11 +652,11 @@ void CHARACTER_MANAGER::Update(int iPulse)
BeginPendingDestroy(); BeginPendingDestroy();
// PC 캐릭터 업데이트 // PC 캐릭터 업데이트
{ {
if (!m_map_pkPCChr.empty()) if (!m_map_pkPCChr.empty())
{ {
// 컨테이너 복사 // 컨테이너 복사
CHARACTER_VECTOR v; CHARACTER_VECTOR v;
v.reserve(m_map_pkPCChr.size()); v.reserve(m_map_pkPCChr.size());
#ifdef __GNUC__ #ifdef __GNUC__
@ -680,7 +680,7 @@ void CHARACTER_MANAGER::Update(int iPulse)
// for_each_pc(bind2nd(mem_fun(&CHARACTER::UpdateCharacter), iPulse)); // for_each_pc(bind2nd(mem_fun(&CHARACTER::UpdateCharacter), iPulse));
} }
// 몬스터 업데이트 // 몬스터 업데이트
{ {
if (!m_set_pkChrState.empty()) if (!m_set_pkChrState.empty())
{ {
@ -695,7 +695,7 @@ void CHARACTER_MANAGER::Update(int iPulse)
} }
} }
// 산타 따로 업데이트 // 산타 따로 업데이트
{ {
CharacterVectorInteractor i; CharacterVectorInteractor i;
@ -706,7 +706,7 @@ void CHARACTER_MANAGER::Update(int iPulse)
} }
} }
// 1시간에 한번씩 몹 사냥 개수 기록 // 1시간에 한번씩 몹 사냥 개수 기록
if (0 == (iPulse % PASSES_PER_SEC(3600))) if (0 == (iPulse % PASSES_PER_SEC(3600)))
{ {
for (itertype(m_map_dwMobKillCount) it = m_map_dwMobKillCount.begin(); it != m_map_dwMobKillCount.end(); ++it) for (itertype(m_map_dwMobKillCount) it = m_map_dwMobKillCount.begin(); it != m_map_dwMobKillCount.end(); ++it)
@ -715,11 +715,11 @@ void CHARACTER_MANAGER::Update(int iPulse)
m_map_dwMobKillCount.clear(); m_map_dwMobKillCount.clear();
} }
// 테스트 서버에서는 60초마다 캐릭터 개수를 센다 // 테스트 서버에서는 60초마다 캐릭터 개수를 센다
if (test_server && 0 == (iPulse % PASSES_PER_SEC(60))) if (test_server && 0 == (iPulse % PASSES_PER_SEC(60)))
SPDLOG_TRACE("CHARACTER COUNT vid {} pid {}", m_map_pkChrByVID.size(), m_map_pkChrByPID.size()); SPDLOG_TRACE("CHARACTER COUNT vid {} pid {}", m_map_pkChrByVID.size(), m_map_pkChrByPID.size());
// 지연된 DestroyCharacter 하기 // 지연된 DestroyCharacter 하기
FlushPendingDestroy(); FlushPendingDestroy();
} }
@ -835,7 +835,7 @@ void CHARACTER_MANAGER::RegisterRaceNumMap(LPCHARACTER ch)
{ {
DWORD dwVnum = ch->GetRaceNum(); DWORD dwVnum = ch->GetRaceNum();
if (m_set_dwRegisteredRaceNum.find(dwVnum) != m_set_dwRegisteredRaceNum.end()) // 등록된 번호 이면 if (m_set_dwRegisteredRaceNum.find(dwVnum) != m_set_dwRegisteredRaceNum.end()) // 등록된 번호 이면
{ {
SPDLOG_TRACE("RegisterRaceNumMap {} {}", ch->GetName(), dwVnum); SPDLOG_TRACE("RegisterRaceNumMap {} {}", ch->GetName(), dwVnum);
m_map_pkChrByRaceNum[dwVnum].insert(ch); m_map_pkChrByRaceNum[dwVnum].insert(ch);
@ -859,7 +859,7 @@ bool CHARACTER_MANAGER::GetCharactersByRaceNum(DWORD dwRaceNum, CharacterVectorI
if (it == m_map_pkChrByRaceNum.end()) if (it == m_map_pkChrByRaceNum.end())
return false; return false;
// 컨테이너 복사 // 컨테이너 복사
i = it->second; i = it->second;
return true; return true;
} }
@ -1056,8 +1056,8 @@ void CHARACTER_MANAGER::SendScriptToMap(int lMapIndex, const std::string & s)
bool CHARACTER_MANAGER::BeginPendingDestroy() bool CHARACTER_MANAGER::BeginPendingDestroy()
{ {
// Begin 이 후에 Begin을 또 하는 경우에 Flush 하지 않는 기능 지원을 위해 // Begin 이 후에 Begin을 또 하는 경우에 Flush 하지 않는 기능 지원을 위해
// 이미 시작되어있으면 false 리턴 처리 // 이미 시작되어있으면 false 리턴 처리
if (m_bUsePendingDestroy) if (m_bUsePendingDestroy)
return false; return false;
@ -1069,7 +1069,7 @@ void CHARACTER_MANAGER::FlushPendingDestroy()
{ {
using namespace std; using namespace std;
m_bUsePendingDestroy = false; // 플래그를 먼저 설정해야 실제 Destroy 처리가 됨 m_bUsePendingDestroy = false; // 플래그를 먼저 설정해야 실제 Destroy 처리가 됨
if (!m_set_pkChrPendingDestroy.empty()) if (!m_set_pkChrPendingDestroy.empty())
{ {

View File

@ -9,7 +9,7 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// QUICKSLOT HANDLING // QUICKSLOT HANDLING
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
void CHARACTER::SyncQuickslot(BYTE bType, BYTE bOldPos, BYTE bNewPos) // bNewPos == 255 면 DELETE void CHARACTER::SyncQuickslot(BYTE bType, BYTE bOldPos, BYTE bNewPos) // bNewPos == 255 면 DELETE
{ {
if (bOldPos == bNewPos) if (bOldPos == bNewPos)
return; return;
@ -121,7 +121,7 @@ bool CHARACTER::SwapQuickslot(BYTE a, BYTE b)
if (a >= QUICKSLOT_MAX_NUM || b >= QUICKSLOT_MAX_NUM) if (a >= QUICKSLOT_MAX_NUM || b >= QUICKSLOT_MAX_NUM)
return false; return false;
// 퀵 슬롯 자리를 서로 바꾼다. // 퀵 슬롯 자리를 서로 바꾼다.
quickslot = m_quickslot[a]; quickslot = m_quickslot[a];
m_quickslot[a] = m_quickslot[b]; m_quickslot[a] = m_quickslot[b];

View File

@ -6,7 +6,7 @@
#include "affect.h" #include "affect.h"
#include "locale_service.h" #include "locale_service.h"
// 독 // 독
const int poison_damage_rate[MOB_RANK_MAX_NUM] = const int poison_damage_rate[MOB_RANK_MAX_NUM] =
{ {
80, 50, 40, 30, 25, 1 80, 50, 40, 30, 25, 1
@ -135,7 +135,7 @@ EVENTFUNC(fire_event)
/* /*
LEVEL에 의한.. LEVEL에 의한..
+8 0% +8 0%
+7 5% +7 5%
@ -184,7 +184,7 @@ void CHARACTER::AttackedByPoison(LPCHARACTER pkAttacker)
if (m_pkPoisonEvent) if (m_pkPoisonEvent)
return; return;
if (m_bHasPoisoned && !IsPC()) // 몬스터는 독이 한번만 걸린다. if (m_bHasPoisoned && !IsPC()) // 몬스터는 독이 한번만 걸린다.
return; return;
if (pkAttacker && pkAttacker->GetLevel() < GetLevel()) if (pkAttacker && pkAttacker->GetLevel() < GetLevel())
@ -201,7 +201,7 @@ void CHARACTER::AttackedByPoison(LPCHARACTER pkAttacker)
/*if (IsImmune(IMMUNE_POISON)) /*if (IsImmune(IMMUNE_POISON))
return;*/ return;*/
// 독 내성 굴림 실패, 독에 걸렸다! // 독 내성 굴림 실패, 독에 걸렸다!
m_bHasPoisoned = true; m_bHasPoisoned = true;
AddAffect(AFFECT_POISON, POINT_NONE, 0, AFF_POISON, POISON_LENGTH + 1, 0, true); AddAffect(AFFECT_POISON, POINT_NONE, 0, AFF_POISON, POISON_LENGTH + 1, 0, true);

View File

@ -62,7 +62,7 @@ void CHARACTER::SetSkillNextReadTime(DWORD dwVnum, time_t time)
bool TSkillUseInfo::HitOnce(DWORD dwVnum) bool TSkillUseInfo::HitOnce(DWORD dwVnum)
{ {
// 쓰지도않았으면 때리지도 못한다. // 쓰지도않았으면 때리지도 못한다.
if (!bUsed) if (!bUsed)
return false; return false;
@ -97,7 +97,7 @@ bool TSkillUseInfo::UseSkill(bool isGrandMaster, DWORD vid, DWORD dwCooltime, in
this->isGrandMaster = isGrandMaster; this->isGrandMaster = isGrandMaster;
DWORD dwCur = get_dword_time(); DWORD dwCur = get_dword_time();
// 아직 쿨타임이 끝나지 않았다. // 아직 쿨타임이 끝나지 않았다.
if (bUsed && dwNextSkillUsableTime > dwCur) if (bUsed && dwNextSkillUsableTime > dwCur)
{ {
SPDLOG_DEBUG("cooltime is not over delta {}", dwNextSkillUsableTime - dwCur); SPDLOG_DEBUG("cooltime is not over delta {}", dwNextSkillUsableTime - dwCur);
@ -280,7 +280,7 @@ bool CHARACTER::LearnGrandMasterSkill(DWORD dwSkillVnum)
{ {
if (FindAffect(AFFECT_SKILL_NO_BOOK_DELAY)) if (FindAffect(AFFECT_SKILL_NO_BOOK_DELAY))
{ {
// 주안술서 사용중에는 시간 제한 무시 // 주안술서 사용중에는 시간 제한 무시
RemoveAffect(AFFECT_SKILL_NO_BOOK_DELAY); RemoveAffect(AFFECT_SKILL_NO_BOOK_DELAY);
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xC1\xD6\xBE\xC8\xBC\xFA\xBC\xAD\xB8\xA6 \xC5\xEB\xC7\xD8 \xC1\xD6\xC8\xAD\xC0\xD4\xB8\xB6\xBF\xA1\xBC\xAD \xBA\xFC\xC1\xAE\xB3\xAA\xBF\xD4\xBD\xC0\xB4\xCF\xB4\xD9.")); ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xC1\xD6\xBE\xC8\xBC\xFA\xBC\xAD\xB8\xA6 \xC5\xEB\xC7\xD8 \xC1\xD6\xC8\xAD\xC0\xD4\xB8\xB6\xBF\xA1\xBC\xAD \xBA\xFC\xC1\xAE\xB3\xAA\xBF\xD4\xBD\xC0\xB4\xCF\xB4\xD9."));
} }
@ -293,7 +293,7 @@ bool CHARACTER::LearnGrandMasterSkill(DWORD dwSkillVnum)
} }
*/ */
// bType이 0이면 처음부터 책으로 수련 가능 // bType이 0이면 처음부터 책으로 수련 가능
if (pkSk->dwType == 0) if (pkSk->dwType == 0)
{ {
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB1\xD7\xB7\xA3\xB5\xE5 \xB8\xB6\xBD\xBA\xC5\xCD \xBC\xF6\xB7\xC3\xC0\xBB \xC7\xD2 \xBC\xF6 \xBE\xF8\xB4\xC2 \xBD\xBA\xC5\xB3\xC0\xD4\xB4\xCF\xB4\xD9.")); ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB1\xD7\xB7\xA3\xB5\xE5 \xB8\xB6\xBD\xBA\xC5\xCD \xBC\xF6\xB7\xC3\xC0\xBB \xC7\xD2 \xBC\xF6 \xBE\xF8\xB4\xC2 \xBD\xBA\xC5\xB3\xC0\xD4\xB4\xCF\xB4\xD9."));
@ -316,7 +316,7 @@ bool CHARACTER::LearnGrandMasterSkill(DWORD dwSkillVnum)
strTrainSkill = os.str(); strTrainSkill = os.str();
} }
// 여기서 확률을 계산합니다. // 여기서 확률을 계산합니다.
BYTE bLastLevel = GetSkillLevel(dwSkillVnum); BYTE bLastLevel = GetSkillLevel(dwSkillVnum);
int idx = std::min(9, GetSkillLevel(dwSkillVnum) - 30); int idx = std::min(9, GetSkillLevel(dwSkillVnum) - 30);
@ -438,7 +438,7 @@ bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb)
} }
} }
// bType이 0이면 처음부터 책으로 수련 가능 // bType이 0이면 처음부터 책으로 수련 가능
if (pkSk->dwType != 0) if (pkSk->dwType != 0)
{ {
if (GetSkillMasterType(dwSkillVnum) != SKILL_MASTER) if (GetSkillMasterType(dwSkillVnum) != SKILL_MASTER)
@ -457,7 +457,7 @@ bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb)
{ {
if (FindAffect(AFFECT_SKILL_NO_BOOK_DELAY)) if (FindAffect(AFFECT_SKILL_NO_BOOK_DELAY))
{ {
// 주안술서 사용중에는 시간 제한 무시 // 주안술서 사용중에는 시간 제한 무시
RemoveAffect(AFFECT_SKILL_NO_BOOK_DELAY); RemoveAffect(AFFECT_SKILL_NO_BOOK_DELAY);
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xC1\xD6\xBE\xC8\xBC\xFA\xBC\xAD\xB8\xA6 \xC5\xEB\xC7\xD8 \xC1\xD6\xC8\xAD\xC0\xD4\xB8\xB6\xBF\xA1\xBC\xAD \xBA\xFC\xC1\xAE\xB3\xAA\xBF\xD4\xBD\xC0\xB4\xCF\xB4\xD9.")); ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xC1\xD6\xBE\xC8\xBC\xFA\xBC\xAD\xB8\xA6 \xC5\xEB\xC7\xD8 \xC1\xD6\xC8\xAD\xC0\xD4\xB8\xB6\xBF\xA1\xBC\xAD \xBA\xFC\xC1\xAE\xB3\xAA\xBF\xD4\xBD\xC0\xB4\xCF\xB4\xD9."));
} }
@ -469,7 +469,7 @@ bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb)
} }
} }
// 여기서 확률을 계산합니다. // 여기서 확률을 계산합니다.
BYTE bLastLevel = GetSkillLevel(dwSkillVnum); BYTE bLastLevel = GetSkillLevel(dwSkillVnum);
if (bProb != 0) if (bProb != 0)
@ -527,7 +527,7 @@ bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb)
if (Random::get(1, 100) > percent) if (Random::get(1, 100) > percent)
{ {
// 책읽기에 성공 // 책읽기에 성공
if (read_count >= need_bookcount) if (read_count >= need_bookcount)
{ {
SkillLevelUp(dwSkillVnum, SKILL_UP_BY_BOOK); SkillLevelUp(dwSkillVnum, SKILL_UP_BY_BOOK);
@ -564,7 +564,7 @@ bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb)
} }
else else
{ {
// 사용자의 퀘스트 정보 로드 실패 // 사용자의 퀘스트 정보 로드 실패
} }
} }
// INTERNATIONAL_VERSION // INTERNATIONAL_VERSION
@ -721,7 +721,7 @@ void CHARACTER::SkillLevelUp(DWORD dwVnum, BYTE bMethod)
if (!IsLearnableSkill(dwVnum)) if (!IsLearnableSkill(dwVnum))
return; return;
// 그랜드 마스터는 퀘스트로만 수행가능 // 그랜드 마스터는 퀘스트로만 수행가능
if (pkSk->dwType != 0) if (pkSk->dwType != 0)
{ {
switch (GetSkillMasterType(pkSk->dwVnum)) switch (GetSkillMasterType(pkSk->dwVnum))
@ -738,7 +738,7 @@ void CHARACTER::SkillLevelUp(DWORD dwVnum, BYTE bMethod)
if (bMethod == SKILL_UP_BY_POINT) if (bMethod == SKILL_UP_BY_POINT)
{ {
// 마스터가 아닌 상태에서만 수련가능 // 마스터가 아닌 상태에서만 수련가능
if (GetSkillMasterType(pkSk->dwVnum) != SKILL_NORMAL) if (GetSkillMasterType(pkSk->dwVnum) != SKILL_NORMAL)
return; return;
@ -747,7 +747,7 @@ void CHARACTER::SkillLevelUp(DWORD dwVnum, BYTE bMethod)
} }
else if (bMethod == SKILL_UP_BY_BOOK) else if (bMethod == SKILL_UP_BY_BOOK)
{ {
if (pkSk->dwType != 0) // 직업에 속하지 않았거나 포인트로 올릴수 없는 스킬은 처음부터 책으로 배울 수 있다. if (pkSk->dwType != 0) // 직업에 속하지 않았거나 포인트로 올릴수 없는 스킬은 처음부터 책으로 배울 수 있다.
if (GetSkillMasterType(pkSk->dwVnum) != SKILL_MASTER) if (GetSkillMasterType(pkSk->dwVnum) != SKILL_MASTER)
return; return;
} }
@ -801,11 +801,11 @@ void CHARACTER::SkillLevelUp(DWORD dwVnum, BYTE bMethod)
if (pkSk->dwType != 0) if (pkSk->dwType != 0)
{ {
// 갑자기 그레이드 업하는 코딩 // 갑자기 그레이드 업하는 코딩
switch (GetSkillMasterType(pkSk->dwVnum)) switch (GetSkillMasterType(pkSk->dwVnum))
{ {
case SKILL_NORMAL: case SKILL_NORMAL:
// 번섭은 스킬 업그레이드 17~20 사이 랜덤 마스터 수련 // 번섭은 스킬 업그레이드 17~20 사이 랜덤 마스터 수련
if (GetSkillLevel(pkSk->dwVnum) >= 17) if (GetSkillLevel(pkSk->dwVnum) >= 17)
{ {
if (GetQuestFlag("reset_scroll.force_to_master_skill") > 0) if (GetQuestFlag("reset_scroll.force_to_master_skill") > 0)
@ -863,7 +863,7 @@ void CHARACTER::ResetSkill()
if (NULL == m_pSkillLevels) if (NULL == m_pSkillLevels)
return; return;
// 보조 스킬은 리셋시키지 않는다 // 보조 스킬은 리셋시키지 않는다
std::vector<std::pair<DWORD, TPlayerSkill> > vec; std::vector<std::pair<DWORD, TPlayerSkill> > vec;
size_t count = sizeof(s_adwSubSkillVnums) / sizeof(s_adwSubSkillVnums[0]); size_t count = sizeof(s_adwSubSkillVnums) / sizeof(s_adwSubSkillVnums[0]);
@ -994,7 +994,7 @@ EVENTFUNC(ChainLightningEvent)
SPDLOG_DEBUG("chainlighting event {}", pkChr->GetName()); SPDLOG_DEBUG("chainlighting event {}", pkChr->GetName());
if (pkChrVictim->GetParty()) // 파티 먼저 if (pkChrVictim->GetParty()) // 파티 먼저
{ {
pkTarget = pkChrVictim->GetParty()->GetNextOwnership(NULL, pkChrVictim->GetX(), pkChrVictim->GetY()); pkTarget = pkChrVictim->GetParty()->GetNextOwnership(NULL, pkChrVictim->GetX(), pkChrVictim->GetY());
if (pkTarget == pkChrVictim || !Random::get(0, 2) || pkChr->GetChainLightingExcept().find(pkTarget) != pkChr->GetChainLightingExcept().end()) if (pkTarget == pkChrVictim || !Random::get(0, 2) || pkChr->GetChainLightingExcept().find(pkTarget) != pkChr->GetChainLightingExcept().end())
@ -1090,7 +1090,7 @@ struct FuncSplashDamage
} }
if (m_pkChr->IsPC()) if (m_pkChr->IsPC())
// 길드 스킬은 쿨타임 처리를 하지 않는다. // 길드 스킬은 쿨타임 처리를 하지 않는다.
if (!(m_pkSk->dwVnum >= GUILD_SKILL_START && m_pkSk->dwVnum <= GUILD_SKILL_END)) if (!(m_pkSk->dwVnum >= GUILD_SKILL_START && m_pkSk->dwVnum <= GUILD_SKILL_END))
if (!m_bDisableCooltime && m_pInfo && !m_pInfo->HitOnce(m_pkSk->dwVnum) && m_pkSk->dwVnum != SKILL_MUYEONG) if (!m_bDisableCooltime && m_pInfo && !m_pInfo->HitOnce(m_pkSk->dwVnum) && m_pkSk->dwVnum != SKILL_MUYEONG)
{ {
@ -1159,7 +1159,7 @@ struct FuncSplashDamage
m_pkSk->SetPointVar("chain", m_pkChr->GetChainLightningIndex()); m_pkSk->SetPointVar("chain", m_pkChr->GetChainLightningIndex());
m_pkChr->IncChainLightningIndex(); m_pkChr->IncChainLightningIndex();
bool bUnderEunhyung = m_pkChr->GetAffectedEunhyung() > 0; // 이건 왜 여기서 하지?? bool bUnderEunhyung = m_pkChr->GetAffectedEunhyung() > 0; // 이건 왜 여기서 하지??
m_pkSk->SetPointVar("ek", m_pkChr->GetAffectedEunhyung()*1./100); m_pkSk->SetPointVar("ek", m_pkChr->GetAffectedEunhyung()*1./100);
//m_pkChr->ClearAffectedEunhyung(); //m_pkChr->ClearAffectedEunhyung();
@ -1241,11 +1241,11 @@ struct FuncSplashDamage
if (m_pkChr->IsPC() && m_pkChr->m_SkillUseInfo[m_pkSk->dwVnum].GetMainTargetVID() != (DWORD) pkChrVictim->GetVID()) if (m_pkChr->IsPC() && m_pkChr->m_SkillUseInfo[m_pkSk->dwVnum].GetMainTargetVID() != (DWORD) pkChrVictim->GetVID())
{ {
// 데미지 감소 // 데미지 감소
iDam = (int) (iDam * m_pkSk->kSplashAroundDamageAdjustPoly.Eval()); iDam = (int) (iDam * m_pkSk->kSplashAroundDamageAdjustPoly.Eval());
} }
// TODO 스킬에 따른 데미지 타입 기록해야한다. // TODO 스킬에 따른 데미지 타입 기록해야한다.
EDamageType dt = DAMAGE_TYPE_NONE; EDamageType dt = DAMAGE_TYPE_NONE;
switch (m_pkSk->bSkillAttrType) switch (m_pkSk->bSkillAttrType)
@ -1268,7 +1268,7 @@ struct FuncSplashDamage
case WEAPON_TWO_HANDED: case WEAPON_TWO_HANDED:
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_TWOHAND)) / 100; iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_TWOHAND)) / 100;
// 양손검 페널티 10% // 양손검 페널티 10%
//iDam = iDam * 95 / 100; //iDam = iDam * 95 / 100;
break; break;
@ -1293,8 +1293,8 @@ struct FuncSplashDamage
case SKILL_ATTR_TYPE_RANGE: case SKILL_ATTR_TYPE_RANGE:
dt = DAMAGE_TYPE_RANGE; dt = DAMAGE_TYPE_RANGE;
// 으아아아악 // 으아아아악
// 예전에 적용안했던 버그가 있어서 방어력 계산을 다시하면 유저가 난리남 // 예전에 적용안했던 버그가 있어서 방어력 계산을 다시하면 유저가 난리남
//iDam -= pkChrVictim->GetPoint(POINT_DEF_GRADE); //iDam -= pkChrVictim->GetPoint(POINT_DEF_GRADE);
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_BOW)) / 100; iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_BOW)) / 100;
break; break;
@ -1302,8 +1302,8 @@ struct FuncSplashDamage
case SKILL_ATTR_TYPE_MAGIC: case SKILL_ATTR_TYPE_MAGIC:
dt = DAMAGE_TYPE_MAGIC; dt = DAMAGE_TYPE_MAGIC;
iDam = CalcAttBonus(m_pkChr, pkChrVictim, iDam); iDam = CalcAttBonus(m_pkChr, pkChrVictim, iDam);
// 으아아아악 // 으아아아악
// 예전에 적용안했던 버그가 있어서 방어력 계산을 다시하면 유저가 난리남 // 예전에 적용안했던 버그가 있어서 방어력 계산을 다시하면 유저가 난리남
//iDam -= pkChrVictim->GetPoint(POINT_MAGIC_DEF_GRADE); //iDam -= pkChrVictim->GetPoint(POINT_MAGIC_DEF_GRADE);
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_MAGIC)) / 100; iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_MAGIC)) / 100;
break; break;
@ -1314,13 +1314,13 @@ struct FuncSplashDamage
} }
// //
// 20091109 독일 스킬 속성 요청 작업 // 20091109 독일 스킬 속성 요청 작업
// 기존 스킬 테이블에 SKILL_FLAG_WIND, SKILL_FLAG_ELEC, SKILL_FLAG_FIRE를 가진 스킬이 // 기존 스킬 테이블에 SKILL_FLAG_WIND, SKILL_FLAG_ELEC, SKILL_FLAG_FIRE를 가진 스킬이
// 전혀 없었으므로 몬스터의 RESIST_WIND, RESIST_ELEC, RESIST_FIRE도 사용되지 않고 있었다. // 전혀 없었으므로 몬스터의 RESIST_WIND, RESIST_ELEC, RESIST_FIRE도 사용되지 않고 있었다.
// //
// PvP와 PvE밸런스 분리를 위해 의도적으로 NPC만 적용하도록 했으며 기존 밸런스와 차이점을 // PvP와 PvE밸런스 분리를 위해 의도적으로 NPC만 적용하도록 했으며 기존 밸런스와 차이점을
// 느끼지 못하기 위해 mob_proto의 RESIST_MAGIC을 RESIST_WIND, RESIST_ELEC, RESIST_FIRE로 // 느끼지 못하기 위해 mob_proto의 RESIST_MAGIC을 RESIST_WIND, RESIST_ELEC, RESIST_FIRE로
// 복사하였다. // 복사하였다.
// //
if (pkChrVictim->IsNPC()) if (pkChrVictim->IsNPC())
{ {
@ -1627,7 +1627,7 @@ EVENTFUNC(skill_gwihwan_event)
{ {
PIXEL_POSITION pos; PIXEL_POSITION pos;
// 성공 // 성공
if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(ch->GetMapIndex(), ch->GetEmpire(), pos)) if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(ch->GetMapIndex(), ch->GetEmpire(), pos))
{ {
SPDLOG_DEBUG("Recall: {} {} {} -> {} {}", ch->GetName(), ch->GetX(), ch->GetY(), pos.x, pos.y); SPDLOG_DEBUG("Recall: {} {} {} -> {} {}", ch->GetName(), ch->GetX(), ch->GetY(), pos.x, pos.y);
@ -1641,7 +1641,7 @@ EVENTFUNC(skill_gwihwan_event)
} }
else else
{ {
//실패 //실패
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB1\xCD\xC8\xAF\xBF\xA1 \xBD\xC7\xC6\xD0\xC7\xCF\xBF\xB4\xBD\xC0\xB4\xCF\xB4\xD9.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB1\xCD\xC8\xAF\xBF\xA1 \xBD\xC7\xC6\xD0\xC7\xCF\xBF\xB4\xBD\xC0\xB4\xCF\xB4\xD9."));
} }
return 0; return 0;
@ -1666,11 +1666,11 @@ int CHARACTER::ComputeSkillAtPosition(DWORD dwVnum, const PIXEL_POSITION& posTar
SPDLOG_TRACE("ComputeSkillAtPosition {} vnum {} x {} y {} level {}", SPDLOG_TRACE("ComputeSkillAtPosition {} vnum {} x {} y {} level {}",
GetName(), dwVnum, posTarget.x, posTarget.y, bSkillLevel); GetName(), dwVnum, posTarget.x, posTarget.y, bSkillLevel);
// 나에게 쓰는 스킬은 내 위치를 쓴다. // 나에게 쓰는 스킬은 내 위치를 쓴다.
//if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY)) //if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY))
// posTarget = GetXYZ(); // posTarget = GetXYZ();
// 스플래쉬가 아닌 스킬은 주위이면 이상하다 // 스플래쉬가 아닌 스킬은 주위이면 이상하다
if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH)) if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
return BATTLE_NONE; return BATTLE_NONE;
@ -1769,7 +1769,7 @@ int CHARACTER::ComputeSkillAtPosition(DWORD dwVnum, const PIXEL_POSITION& posTar
if (IS_SET(pkSk->dwFlag, SKILL_FLAG_ATTACK | SKILL_FLAG_USE_MELEE_DAMAGE | SKILL_FLAG_USE_MAGIC_DAMAGE)) if (IS_SET(pkSk->dwFlag, SKILL_FLAG_ATTACK | SKILL_FLAG_USE_MELEE_DAMAGE | SKILL_FLAG_USE_MAGIC_DAMAGE))
{ {
// //
// 공격 스킬일 경우 // 공격 스킬일 경우
// //
bool bAdded = false; bool bAdded = false;
@ -1794,7 +1794,7 @@ int CHARACTER::ComputeSkillAtPosition(DWORD dwVnum, const PIXEL_POSITION& posTar
int iDur = (int) pkSk->kDurationPoly.Eval(); int iDur = (int) pkSk->kDurationPoly.Eval();
if (IsPC()) if (IsPC())
if (!(dwVnum >= GUILD_SKILL_START && dwVnum <= GUILD_SKILL_END)) // 길드 스킬은 쿨타임 처리를 하지 않는다. if (!(dwVnum >= GUILD_SKILL_START && dwVnum <= GUILD_SKILL_END)) // 길드 스킬은 쿨타임 처리를 하지 않는다.
if (!m_bDisableCooltime && !m_SkillUseInfo[dwVnum].HitOnce(dwVnum) && dwVnum != SKILL_MUYEONG) if (!m_bDisableCooltime && !m_SkillUseInfo[dwVnum].HitOnce(dwVnum) && dwVnum != SKILL_MUYEONG)
{ {
return BATTLE_NONE; return BATTLE_NONE;
@ -1884,7 +1884,7 @@ int CHARACTER::ComputeSkillAtPosition(DWORD dwVnum, const PIXEL_POSITION& posTar
if (iDur > 0) if (iDur > 0)
{ {
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS); iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
// AffectFlag가 없거나, toggle 하는 것이 아니라면.. // AffectFlag가 없거나, toggle 하는 것이 아니라면..
pkSk->kDurationSPCostPoly.SetVar("k", k/*bSkillLevel*/); pkSk->kDurationSPCostPoly.SetVar("k", k/*bSkillLevel*/);
AddAffect(pkSk->dwVnum, AddAffect(pkSk->dwVnum,
@ -1939,13 +1939,13 @@ int CHARACTER::ComputeSkillAtPosition(DWORD dwVnum, const PIXEL_POSITION& posTar
} }
} }
// bSkillLevel 인자가 0이 아닐 경우에는 m_abSkillLevels를 사용하지 않고 강제로 // bSkillLevel 인자가 0이 아닐 경우에는 m_abSkillLevels를 사용하지 않고 강제로
// bSkillLevel로 계산한다. // bSkillLevel로 계산한다.
int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel) int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel)
{ {
const bool bCanUseHorseSkill = CanUseHorseSkill(); const bool bCanUseHorseSkill = CanUseHorseSkill();
// 말을 타고있지만 스킬은 사용할 수 없는 상태라면 return // 말을 타고있지만 스킬은 사용할 수 없는 상태라면 return
if (false == bCanUseHorseSkill && true == IsRiding()) if (false == bCanUseHorseSkill && true == IsRiding())
return BATTLE_NONE; return BATTLE_NONE;
@ -1967,7 +1967,7 @@ int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel
return BATTLE_NONE; return BATTLE_NONE;
// 상대방에게 쓰는 것이 아니면 나에게 써야 한다. // 상대방에게 쓰는 것이 아니면 나에게 써야 한다.
if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY)) if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY))
pkVictim = this; pkVictim = this;
@ -2135,7 +2135,7 @@ int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel
if (IsPC()) if (IsPC())
if (!(dwVnum >= GUILD_SKILL_START && dwVnum <= GUILD_SKILL_END)) // 길드 스킬은 쿨타임 처리를 하지 않는다. if (!(dwVnum >= GUILD_SKILL_START && dwVnum <= GUILD_SKILL_END)) // 길드 스킬은 쿨타임 처리를 하지 않는다.
if (!m_bDisableCooltime && !m_SkillUseInfo[dwVnum].HitOnce(dwVnum) && dwVnum != SKILL_MUYEONG) if (!m_bDisableCooltime && !m_SkillUseInfo[dwVnum].HitOnce(dwVnum) && dwVnum != SKILL_MUYEONG)
{ {
return BATTLE_NONE; return BATTLE_NONE;
@ -2248,7 +2248,7 @@ int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel
if (iDur > 0) if (iDur > 0)
{ {
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS); iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
// AffectFlag가 없거나, toggle 하는 것이 아니라면.. // AffectFlag가 없거나, toggle 하는 것이 아니라면..
pkSk->kDurationSPCostPoly.SetVar("k", k/*bSkillLevel*/); pkSk->kDurationSPCostPoly.SetVar("k", k/*bSkillLevel*/);
if (pkSk->bPointOn2 != POINT_NONE) if (pkSk->bPointOn2 != POINT_NONE)
@ -2428,7 +2428,7 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste
return true; return true;
} }
// 말을 타고있지만 스킬은 사용할 수 없는 상태라면 return false // 말을 타고있지만 스킬은 사용할 수 없는 상태라면 return false
if (false == bCanUseHorseSkill && true == IsRiding()) if (false == bCanUseHorseSkill && true == IsRiding())
return false; return false;
@ -2474,7 +2474,7 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste
} }
m_SkillUseInfo[dwVnum].SetMainTargetVID(pkVictim->GetVID()); m_SkillUseInfo[dwVnum].SetMainTargetVID(pkVictim->GetVID());
// DASH 상태의 탄환격은 공격기술 // DASH 상태의 탄환격은 공격기술
ComputeSkill(dwVnum, pkVictim); ComputeSkill(dwVnum, pkVictim);
RemoveAffect(dwVnum); RemoveAffect(dwVnum);
return true; return true;
@ -2492,7 +2492,7 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste
return true; return true;
} }
// Toggle 할 때는 SP를 쓰지 않음 (SelfOnly로 구분) // Toggle 할 때는 SP를 쓰지 않음 (SelfOnly로 구분)
if ((0 != pkSk->dwAffectFlag || pkSk->dwVnum == SKILL_MUYEONG) && (pkSk->dwFlag & SKILL_FLAG_TOGGLE) && RemoveAffect(pkSk->dwVnum)) if ((0 != pkSk->dwAffectFlag || pkSk->dwVnum == SKILL_MUYEONG) && (pkSk->dwFlag & SKILL_FLAG_TOGGLE) && RemoveAffect(pkSk->dwVnum))
{ {
return true; return true;
@ -2506,7 +2506,7 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste
pkSk->SetPointVar("k", k); pkSk->SetPointVar("k", k);
pkSk->kSplashAroundDamageAdjustPoly.SetVar("k", k); pkSk->kSplashAroundDamageAdjustPoly.SetVar("k", k);
// 쿨타임 체크 // 쿨타임 체크
pkSk->kCooldownPoly.SetVar("k", k); pkSk->kCooldownPoly.SetVar("k", k);
int iCooltime = (int) pkSk->kCooldownPoly.Eval(); int iCooltime = (int) pkSk->kCooldownPoly.Eval();
int lMaxHit = pkSk->lMaxHit ? pkSk->lMaxHit : -1; int lMaxHit = pkSk->lMaxHit ? pkSk->lMaxHit : -1;
@ -2570,7 +2570,7 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste
if (pkSk->dwVnum == SKILL_MUYEONG || pkSk->IsChargeSkill() && !IsAffectFlag(AFF_TANHWAN_DASH) && !pkVictim) if (pkSk->dwVnum == SKILL_MUYEONG || pkSk->IsChargeSkill() && !IsAffectFlag(AFF_TANHWAN_DASH) && !pkVictim)
{ {
// 처음 사용하는 무영진은 자신에게 Affect를 붙인다. // 처음 사용하는 무영진은 자신에게 Affect를 붙인다.
pkVictim = this; pkVictim = this;
} }
@ -2643,7 +2643,7 @@ int CHARACTER::GetSkillMasterType(DWORD dwVnum) const
int CHARACTER::GetSkillPower(DWORD dwVnum, BYTE bLevel) const int CHARACTER::GetSkillPower(DWORD dwVnum, BYTE bLevel) const
{ {
// 인어반지 아이템 // 인어반지 아이템
if (dwVnum >= SKILL_LANGUAGE1 && dwVnum <= SKILL_LANGUAGE3 && IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE)) if (dwVnum >= SKILL_LANGUAGE1 && dwVnum <= SKILL_LANGUAGE3 && IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE))
{ {
return 100; return 100;
@ -2748,16 +2748,16 @@ void CHARACTER::SkillLearnWaitMoreTimeMessage(DWORD ms)
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xB8\xF6 \xBC\xD3\xC0\xCC \xB6\xDF\xB0\xCC\xB1\xBA. \xC7\xCF\xC1\xF6\xB8\xB8 \xBE\xC6\xC1\xD6 \xC6\xED\xBE\xC8\xC7\xD8. \xC0\xCC\xB4\xEB\xB7\xCE \xB1\xE2\xB8\xA6 \xBE\xC8\xC1\xA4\xBD\xC3\xC5\xB0\xC0\xDA.")); ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xB8\xF6 \xBC\xD3\xC0\xCC \xB6\xDF\xB0\xCC\xB1\xBA. \xC7\xCF\xC1\xF6\xB8\xB8 \xBE\xC6\xC1\xD6 \xC6\xED\xBE\xC8\xC7\xD8. \xC0\xCC\xB4\xEB\xB7\xCE \xB1\xE2\xB8\xA6 \xBE\xC8\xC1\xA4\xBD\xC3\xC5\xB0\xC0\xDA."));
else if (ms < 5 * 60) else if (ms < 5 * 60)
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xB1\xD7\xB7\xA1, \xC3\xB5\xC3\xB5\xC8\xF7. \xC1\xBB\xB4\xF5 \xC3\xB5\xC3\xB5\xC8\xF7, \xB1\xD7\xB7\xAF\xB3\xAA \xB8\xB7\xC8\xFB \xBE\xF8\xC0\xCC \xBA\xFC\xB8\xA3\xB0\xD4!")); ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xB1\xD7\xB7\xA1, \xC3\xB5\xC3\xB5\xC8\xF7. \xC1\xBB\xB4\xF5 \xC3\xB5\xC3\xB5\xC8\xF7, \xB1\xD7\xB7\xAF\xB3\xAA \xB8\xB7\xC8\xFB \xBE\xF8\xC0\xCC \xBA\xFC\xB8\xA3\xB0\xD4!"));
else if (ms < 10 * 60) // 10분 else if (ms < 10 * 60) // 10분
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xB1\xD7\xB7\xA1, \xC0\xCC \xB4\xC0\xB3\xA6\xC0\xCC\xBE\xDF. \xC3\xBC\xB3\xBB\xBF\xA1 \xB1\xE2\xB0\xA1 \xBE\xC6\xC1\xD6 \xC3\xE6\xB8\xB8\xC7\xD8.")); ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xB1\xD7\xB7\xA1, \xC0\xCC \xB4\xC0\xB3\xA6\xC0\xCC\xBE\xDF. \xC3\xBC\xB3\xBB\xBF\xA1 \xB1\xE2\xB0\xA1 \xBE\xC6\xC1\xD6 \xC3\xE6\xB8\xB8\xC7\xD8."));
else if (ms < 30 * 60) // 30분 else if (ms < 30 * 60) // 30분
{ {
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xB4\xD9 \xC0\xD0\xBE\xFA\xB4\xD9! \xC0\xCC\xC1\xA6 \xBA\xF1\xB1\xDE\xBF\xA1 \xC0\xFB\xC7\xF4\xC0\xD6\xB4\xC2 \xB4\xEB\xB7\xCE \xC0\xFC\xBD\xC5\xBF\xA1 \xB1\xE2\xB8\xA6 \xB5\xB9\xB8\xAE\xB1\xE2\xB8\xB8 \xC7\xCF\xB8\xE9,")); ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xB4\xD9 \xC0\xD0\xBE\xFA\xB4\xD9! \xC0\xCC\xC1\xA6 \xBA\xF1\xB1\xDE\xBF\xA1 \xC0\xFB\xC7\xF4\xC0\xD6\xB4\xC2 \xB4\xEB\xB7\xCE \xC0\xFC\xBD\xC5\xBF\xA1 \xB1\xE2\xB8\xA6 \xB5\xB9\xB8\xAE\xB1\xE2\xB8\xB8 \xC7\xCF\xB8\xE9,"));
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xB1\xD7\xB0\xCD\xC0\xB8\xB7\xCE \xBC\xF6\xB7\xC3\xC0\xBA \xB3\xA1\xB3\xAD \xB0\xC5\xBE\xDF!")); ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xB1\xD7\xB0\xCD\xC0\xB8\xB7\xCE \xBC\xF6\xB7\xC3\xC0\xBA \xB3\xA1\xB3\xAD \xB0\xC5\xBE\xDF!"));
} }
else if (ms < 1 * 3600) // 1시간 else if (ms < 1 * 3600) // 1시간
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xC0\xCC\xC1\xA6 \xC3\xA5\xC0\xC7 \xB8\xB6\xC1\xF6\xB8\xB7 \xC0\xE5\xC0\xCC\xBE\xDF! \xBC\xF6\xB7\xC3\xC0\xC7 \xB3\xA1\xC0\xCC \xB4\xAB\xBF\xA1 \xBA\xB8\xC0\xCC\xB0\xED \xC0\xD6\xBE\xEE!")); ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xC0\xCC\xC1\xA6 \xC3\xA5\xC0\xC7 \xB8\xB6\xC1\xF6\xB8\xB7 \xC0\xE5\xC0\xCC\xBE\xDF! \xBC\xF6\xB7\xC3\xC0\xC7 \xB3\xA1\xC0\xCC \xB4\xAB\xBF\xA1 \xBA\xB8\xC0\xCC\xB0\xED \xC0\xD6\xBE\xEE!"));
else if (ms < 2 * 3600) // 2시간 else if (ms < 2 * 3600) // 2시간
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xBE\xF3\xB8\xB6 \xBE\xC8 \xB3\xB2\xBE\xD2\xBE\xEE! \xC1\xB6\xB1\xDD\xB8\xB8 \xB4\xF5!")); ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xBE\xF3\xB8\xB6 \xBE\xC8 \xB3\xB2\xBE\xD2\xBE\xEE! \xC1\xB6\xB1\xDD\xB8\xB8 \xB4\xF5!"));
else if (ms < 3 * 3600) else if (ms < 3 * 3600)
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xC1\xC1\xBE\xD2\xBE\xEE! \xC1\xB6\xB1\xDD\xB8\xB8 \xB4\xF5 \xC0\xD0\xC0\xB8\xB8\xE9 \xB3\xA1\xC0\xCC\xB4\xD9!")); ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("\xC1\xC1\xBE\xD2\xBE\xEE! \xC1\xB6\xB1\xDD\xB8\xB8 \xB4\xF5 \xC0\xD0\xC0\xB8\xB8\xE9 \xB3\xA1\xC0\xCC\xB4\xD9!"));
@ -3138,10 +3138,10 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
static DWORD s_anMotion2SkillVnumList[MOTION_MAX_NUM][SKILL_LIST_MAX_COUNT] = static DWORD s_anMotion2SkillVnumList[MOTION_MAX_NUM][SKILL_LIST_MAX_COUNT] =
{ {
// 스킬수 무사스킬ID 자객스킬ID 수라스킬ID 무당스킬ID // 스킬수 무사스킬ID 자객스킬ID 수라스킬ID 무당스킬ID
{ 0, 0, 0, 0, 0 }, // 0 { 0, 0, 0, 0, 0 }, // 0
// 1번 직군 기본 스킬 // 1번 직군 기본 스킬
{ 4, 1, 31, 61, 91 }, // 1 { 4, 1, 31, 61, 91 }, // 1
{ 4, 2, 32, 62, 92 }, // 2 { 4, 2, 32, 62, 92 }, // 2
{ 4, 3, 33, 63, 93 }, // 3 { 4, 3, 33, 63, 93 }, // 3
@ -3150,9 +3150,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
{ 4, 6, 36, 66, 96 }, // 6 { 4, 6, 36, 66, 96 }, // 6
{ 0, 0, 0, 0, 0 }, // 7 { 0, 0, 0, 0, 0 }, // 7
{ 0, 0, 0, 0, 0 }, // 8 { 0, 0, 0, 0, 0 }, // 8
// 1번 직군 기본 스킬 끝 // 1번 직군 기본 스킬 끝
// 여유분 // 여유분
{ 0, 0, 0, 0, 0 }, // 9 { 0, 0, 0, 0, 0 }, // 9
{ 0, 0, 0, 0, 0 }, // 10 { 0, 0, 0, 0, 0 }, // 10
{ 0, 0, 0, 0, 0 }, // 11 { 0, 0, 0, 0, 0 }, // 11
@ -3160,9 +3160,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
{ 0, 0, 0, 0, 0 }, // 13 { 0, 0, 0, 0, 0 }, // 13
{ 0, 0, 0, 0, 0 }, // 14 { 0, 0, 0, 0, 0 }, // 14
{ 0, 0, 0, 0, 0 }, // 15 { 0, 0, 0, 0, 0 }, // 15
// 여유분 끝 // 여유분 끝
// 2번 직군 기본 스킬 // 2번 직군 기본 스킬
{ 4, 16, 46, 76, 106 }, // 16 { 4, 16, 46, 76, 106 }, // 16
{ 4, 17, 47, 77, 107 }, // 17 { 4, 17, 47, 77, 107 }, // 17
{ 4, 18, 48, 78, 108 }, // 18 { 4, 18, 48, 78, 108 }, // 18
@ -3171,14 +3171,14 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
{ 4, 21, 51, 81, 111 }, // 21 { 4, 21, 51, 81, 111 }, // 21
{ 0, 0, 0, 0, 0 }, // 22 { 0, 0, 0, 0, 0 }, // 22
{ 0, 0, 0, 0, 0 }, // 23 { 0, 0, 0, 0, 0 }, // 23
// 2번 직군 기본 스킬 끝 // 2번 직군 기본 스킬 끝
// 여유분 // 여유분
{ 0, 0, 0, 0, 0 }, // 24 { 0, 0, 0, 0, 0 }, // 24
{ 0, 0, 0, 0, 0 }, // 25 { 0, 0, 0, 0, 0 }, // 25
// 여유분 끝 // 여유분 끝
// 1번 직군 마스터 스킬 // 1번 직군 마스터 스킬
{ 4, 1, 31, 61, 91 }, // 26 { 4, 1, 31, 61, 91 }, // 26
{ 4, 2, 32, 62, 92 }, // 27 { 4, 2, 32, 62, 92 }, // 27
{ 4, 3, 33, 63, 93 }, // 28 { 4, 3, 33, 63, 93 }, // 28
@ -3187,9 +3187,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
{ 4, 6, 36, 66, 96 }, // 31 { 4, 6, 36, 66, 96 }, // 31
{ 0, 0, 0, 0, 0 }, // 32 { 0, 0, 0, 0, 0 }, // 32
{ 0, 0, 0, 0, 0 }, // 33 { 0, 0, 0, 0, 0 }, // 33
// 1번 직군 마스터 스킬 끝 // 1번 직군 마스터 스킬 끝
// 여유분 // 여유분
{ 0, 0, 0, 0, 0 }, // 34 { 0, 0, 0, 0, 0 }, // 34
{ 0, 0, 0, 0, 0 }, // 35 { 0, 0, 0, 0, 0 }, // 35
{ 0, 0, 0, 0, 0 }, // 36 { 0, 0, 0, 0, 0 }, // 36
@ -3197,9 +3197,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
{ 0, 0, 0, 0, 0 }, // 38 { 0, 0, 0, 0, 0 }, // 38
{ 0, 0, 0, 0, 0 }, // 39 { 0, 0, 0, 0, 0 }, // 39
{ 0, 0, 0, 0, 0 }, // 40 { 0, 0, 0, 0, 0 }, // 40
// 여유분 끝 // 여유분 끝
// 2번 직군 마스터 스킬 // 2번 직군 마스터 스킬
{ 4, 16, 46, 76, 106 }, // 41 { 4, 16, 46, 76, 106 }, // 41
{ 4, 17, 47, 77, 107 }, // 42 { 4, 17, 47, 77, 107 }, // 42
{ 4, 18, 48, 78, 108 }, // 43 { 4, 18, 48, 78, 108 }, // 43
@ -3208,14 +3208,14 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
{ 4, 21, 51, 81, 111 }, // 46 { 4, 21, 51, 81, 111 }, // 46
{ 0, 0, 0, 0, 0 }, // 47 { 0, 0, 0, 0, 0 }, // 47
{ 0, 0, 0, 0, 0 }, // 48 { 0, 0, 0, 0, 0 }, // 48
// 2번 직군 마스터 스킬 끝 // 2번 직군 마스터 스킬 끝
// 여유분 // 여유분
{ 0, 0, 0, 0, 0 }, // 49 { 0, 0, 0, 0, 0 }, // 49
{ 0, 0, 0, 0, 0 }, // 50 { 0, 0, 0, 0, 0 }, // 50
// 여유분 끝 // 여유분 끝
// 1번 직군 그랜드 마스터 스킬 // 1번 직군 그랜드 마스터 스킬
{ 4, 1, 31, 61, 91 }, // 51 { 4, 1, 31, 61, 91 }, // 51
{ 4, 2, 32, 62, 92 }, // 52 { 4, 2, 32, 62, 92 }, // 52
{ 4, 3, 33, 63, 93 }, // 53 { 4, 3, 33, 63, 93 }, // 53
@ -3224,9 +3224,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
{ 4, 6, 36, 66, 96 }, // 56 { 4, 6, 36, 66, 96 }, // 56
{ 0, 0, 0, 0, 0 }, // 57 { 0, 0, 0, 0, 0 }, // 57
{ 0, 0, 0, 0, 0 }, // 58 { 0, 0, 0, 0, 0 }, // 58
// 1번 직군 그랜드 마스터 스킬 끝 // 1번 직군 그랜드 마스터 스킬 끝
// 여유분 // 여유분
{ 0, 0, 0, 0, 0 }, // 59 { 0, 0, 0, 0, 0 }, // 59
{ 0, 0, 0, 0, 0 }, // 60 { 0, 0, 0, 0, 0 }, // 60
{ 0, 0, 0, 0, 0 }, // 61 { 0, 0, 0, 0, 0 }, // 61
@ -3234,9 +3234,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
{ 0, 0, 0, 0, 0 }, // 63 { 0, 0, 0, 0, 0 }, // 63
{ 0, 0, 0, 0, 0 }, // 64 { 0, 0, 0, 0, 0 }, // 64
{ 0, 0, 0, 0, 0 }, // 65 { 0, 0, 0, 0, 0 }, // 65
// 여유분 끝 // 여유분 끝
// 2번 직군 그랜드 마스터 스킬 // 2번 직군 그랜드 마스터 스킬
{ 4, 16, 46, 76, 106 }, // 66 { 4, 16, 46, 76, 106 }, // 66
{ 4, 17, 47, 77, 107 }, // 67 { 4, 17, 47, 77, 107 }, // 67
{ 4, 18, 48, 78, 108 }, // 68 { 4, 18, 48, 78, 108 }, // 68
@ -3245,14 +3245,14 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
{ 4, 21, 51, 81, 111 }, // 71 { 4, 21, 51, 81, 111 }, // 71
{ 0, 0, 0, 0, 0 }, // 72 { 0, 0, 0, 0, 0 }, // 72
{ 0, 0, 0, 0, 0 }, // 73 { 0, 0, 0, 0, 0 }, // 73
// 2번 직군 그랜드 마스터 스킬 끝 // 2번 직군 그랜드 마스터 스킬 끝
//여유분 //여유분
{ 0, 0, 0, 0, 0 }, // 74 { 0, 0, 0, 0, 0 }, // 74
{ 0, 0, 0, 0, 0 }, // 75 { 0, 0, 0, 0, 0 }, // 75
// 여유분 끝 // 여유분 끝
// 1번 직군 퍼펙트 마스터 스킬 // 1번 직군 퍼펙트 마스터 스킬
{ 4, 1, 31, 61, 91 }, // 76 { 4, 1, 31, 61, 91 }, // 76
{ 4, 2, 32, 62, 92 }, // 77 { 4, 2, 32, 62, 92 }, // 77
{ 4, 3, 33, 63, 93 }, // 78 { 4, 3, 33, 63, 93 }, // 78
@ -3261,9 +3261,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
{ 4, 6, 36, 66, 96 }, // 81 { 4, 6, 36, 66, 96 }, // 81
{ 0, 0, 0, 0, 0 }, // 82 { 0, 0, 0, 0, 0 }, // 82
{ 0, 0, 0, 0, 0 }, // 83 { 0, 0, 0, 0, 0 }, // 83
// 1번 직군 퍼펙트 마스터 스킬 끝 // 1번 직군 퍼펙트 마스터 스킬 끝
// 여유분 // 여유분
{ 0, 0, 0, 0, 0 }, // 84 { 0, 0, 0, 0, 0 }, // 84
{ 0, 0, 0, 0, 0 }, // 85 { 0, 0, 0, 0, 0 }, // 85
{ 0, 0, 0, 0, 0 }, // 86 { 0, 0, 0, 0, 0 }, // 86
@ -3271,9 +3271,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
{ 0, 0, 0, 0, 0 }, // 88 { 0, 0, 0, 0, 0 }, // 88
{ 0, 0, 0, 0, 0 }, // 89 { 0, 0, 0, 0, 0 }, // 89
{ 0, 0, 0, 0, 0 }, // 90 { 0, 0, 0, 0, 0 }, // 90
// 여유분 끝 // 여유분 끝
// 2번 직군 퍼펙트 마스터 스킬 // 2번 직군 퍼펙트 마스터 스킬
{ 4, 16, 46, 76, 106 }, // 91 { 4, 16, 46, 76, 106 }, // 91
{ 4, 17, 47, 77, 107 }, // 92 { 4, 17, 47, 77, 107 }, // 92
{ 4, 18, 48, 78, 108 }, // 93 { 4, 18, 48, 78, 108 }, // 93
@ -3282,23 +3282,23 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
{ 4, 21, 51, 81, 111 }, // 96 { 4, 21, 51, 81, 111 }, // 96
{ 0, 0, 0, 0, 0 }, // 97 { 0, 0, 0, 0, 0 }, // 97
{ 0, 0, 0, 0, 0 }, // 98 { 0, 0, 0, 0, 0 }, // 98
// 2번 직군 퍼펙트 마스터 스킬 끝 // 2번 직군 퍼펙트 마스터 스킬 끝
// 여유분 // 여유분
{ 0, 0, 0, 0, 0 }, // 99 { 0, 0, 0, 0, 0 }, // 99
{ 0, 0, 0, 0, 0 }, // 100 { 0, 0, 0, 0, 0 }, // 100
// 여유분 끝 // 여유분 끝
// 길드 스킬 // 길드 스킬
{ 1, 152, 0, 0, 0}, // 101 { 1, 152, 0, 0, 0}, // 101
{ 1, 153, 0, 0, 0}, // 102 { 1, 153, 0, 0, 0}, // 102
{ 1, 154, 0, 0, 0}, // 103 { 1, 154, 0, 0, 0}, // 103
{ 1, 155, 0, 0, 0}, // 104 { 1, 155, 0, 0, 0}, // 104
{ 1, 156, 0, 0, 0}, // 105 { 1, 156, 0, 0, 0}, // 105
{ 1, 157, 0, 0, 0}, // 106 { 1, 157, 0, 0, 0}, // 106
// 길드 스킬 끝 // 길드 스킬 끝
// 여유분 // 여유분
{ 0, 0, 0, 0, 0}, // 107 { 0, 0, 0, 0, 0}, // 107
{ 0, 0, 0, 0, 0}, // 108 { 0, 0, 0, 0, 0}, // 108
{ 0, 0, 0, 0, 0}, // 109 { 0, 0, 0, 0, 0}, // 109
@ -3313,13 +3313,13 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
{ 0, 0, 0, 0, 0}, // 118 { 0, 0, 0, 0, 0}, // 118
{ 0, 0, 0, 0, 0}, // 119 { 0, 0, 0, 0, 0}, // 119
{ 0, 0, 0, 0, 0}, // 120 { 0, 0, 0, 0, 0}, // 120
// 여유분 끝 // 여유분 끝
// 승마 스킬 // 승마 스킬
{ 2, 137, 140, 0, 0}, // 121 { 2, 137, 140, 0, 0}, // 121
{ 1, 138, 0, 0, 0}, // 122 { 1, 138, 0, 0, 0}, // 122
{ 1, 139, 0, 0, 0}, // 123 { 1, 139, 0, 0, 0}, // 123
// 승마 스킬 끝 // 승마 스킬 끝
}; };
if (dwMotionIndex >= MOTION_MAX_NUM) if (dwMotionIndex >= MOTION_MAX_NUM)
@ -3473,7 +3473,7 @@ bool CHARACTER::CanUseSkill(DWORD dwSkillVnum) const
if (true == IsRiding()) if (true == IsRiding())
{ {
//마운트 탈것중 고급말만 스킬 사용가능 //마운트 탈것중 고급말만 스킬 사용가능
if(GetMountVnum()) if(GetMountVnum())
{ {
if( GetMountVnum() < 20209 && GetMountVnum() > 20212) if( GetMountVnum() < 20209 && GetMountVnum() > 20212)

View File

@ -63,7 +63,7 @@ namespace
!pkChr->IsAffectFlag(AFF_WAR_FLAG2) && !pkChr->IsAffectFlag(AFF_WAR_FLAG2) &&
!pkChr->IsAffectFlag(AFF_WAR_FLAG3)) !pkChr->IsAffectFlag(AFF_WAR_FLAG3))
{ {
// 우리편 깃발일 경우 // 우리편 깃발일 경우
if ((DWORD) m_pkChr->GetPoint(POINT_STAT) == pkChr->GetGuild()->GetID()) if ((DWORD) m_pkChr->GetPoint(POINT_STAT) == pkChr->GetGuild()->GetID())
{ {
CWarMap * pMap = pkChr->GetWarMap(); CWarMap * pMap = pkChr->GetWarMap();
@ -72,8 +72,8 @@ namespace
if (!pMap || !pMap->GetTeamIndex(pkChr->GetGuild()->GetID(), idx)) if (!pMap || !pMap->GetTeamIndex(pkChr->GetGuild()->GetID(), idx))
return; return;
// 우리편 기지에 깃발이 없을 때만 깃발을 뽑는다. 안그러면 기지에 있는 깃발을 // 우리편 기지에 깃발이 없을 때만 깃발을 뽑는다. 안그러면 기지에 있는 깃발을
// 가만히 두고 싶은데도 뽑힐수가 있으므로.. // 가만히 두고 싶은데도 뽑힐수가 있으므로..
if (!pMap->IsFlagOnBase(idx)) if (!pMap->IsFlagOnBase(idx))
{ {
m_pkChrFind = pkChr; m_pkChrFind = pkChr;
@ -82,7 +82,7 @@ namespace
} }
else else
{ {
// 상대편 깃발인 경우 무조건 뽑는다. // 상대편 깃발인 경우 무조건 뽑는다.
m_pkChrFind = pkChr; m_pkChrFind = pkChr;
m_iMinDistance = iDist; m_iMinDistance = iDist;
} }
@ -186,7 +186,7 @@ namespace
LPCHARACTER pkChr = (LPCHARACTER) ent; LPCHARACTER pkChr = (LPCHARACTER) ent;
// 일단 PC 공격안함 // 일단 PC 공격안함
if (pkChr->IsPC()) if (pkChr->IsPC())
return; return;
@ -202,7 +202,7 @@ namespace
pkChr->IsAffectFlag(AFF_REVIVE_INVISIBLE)) pkChr->IsAffectFlag(AFF_REVIVE_INVISIBLE))
return; return;
// 왜구는 패스 // 왜구는 패스
if (pkChr->GetRaceNum() == 5001) if (pkChr->GetRaceNum() == 5001)
return; return;
@ -285,7 +285,7 @@ void CHARACTER::CowardEscape()
for (int iDistIdx = 2; iDistIdx >= 0; --iDistIdx) for (int iDistIdx = 2; iDistIdx >= 0; --iDistIdx)
for (int iTryCount = 0; iTryCount < 8; ++iTryCount) for (int iTryCount = 0; iTryCount < 8; ++iTryCount)
{ {
SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정 SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
float fx, fy; float fx, fy;
float fDist = Random::get(iDist[iDistIdx], iDist[iDistIdx+1]); float fDist = Random::get(iDist[iDistIdx], iDist[iDistIdx+1]);
@ -367,7 +367,7 @@ void CHARACTER::StateIdle()
} }
else if (IsWarp() || IsGoto()) else if (IsWarp() || IsGoto())
{ {
// 워프는 이벤트로 처리 // 워프는 이벤트로 처리
m_dwStateDuration = 60 * passes_per_sec; m_dwStateDuration = 60 * passes_per_sec;
return; return;
} }
@ -375,7 +375,7 @@ void CHARACTER::StateIdle()
if (IsPC()) if (IsPC())
return; return;
// NPC 처리 // NPC 처리
if (!IsMonster()) if (!IsMonster())
{ {
__StateIdle_NPC(); __StateIdle_NPC();
@ -506,7 +506,7 @@ void CHARACTER::__StateIdle_NPC()
MonsterChat(MONSTER_CHAT_WAIT); MonsterChat(MONSTER_CHAT_WAIT);
m_dwStateDuration = PASSES_PER_SEC(5); m_dwStateDuration = PASSES_PER_SEC(5);
// 펫 시스템의 Idle 처리는 기존 거의 모든 종류의 캐릭터들이 공유해서 사용하는 상태머신이 아닌 CPetActor::Update에서 처리함. // 펫 시스템의 Idle 처리는 기존 거의 모든 종류의 캐릭터들이 공유해서 사용하는 상태머신이 아닌 CPetActor::Update에서 처리함.
if (IsPet()) if (IsPet())
return; return;
else if (IsGuardNPC()) else if (IsGuardNPC())
@ -531,21 +531,21 @@ void CHARACTER::__StateIdle_NPC()
} }
else else
{ {
if (GetRaceNum() == xmas::MOB_SANTA_VNUM) // 산타 if (GetRaceNum() == xmas::MOB_SANTA_VNUM) // 산타
{ {
if (get_dword_time() > m_dwPlayStartTime) if (get_dword_time() > m_dwPlayStartTime)
{ {
int next_warp_time = 2 * 1000; // 2초 int next_warp_time = 2 * 1000; // 2초
m_dwPlayStartTime = get_dword_time() + next_warp_time; m_dwPlayStartTime = get_dword_time() + next_warp_time;
// 시간이 넘었으니 워프합시다. // 시간이 넘었으니 워프합시다.
/* /*
* 산타용 * 산타용
const int WARP_MAP_INDEX_NUM = 4; const int WARP_MAP_INDEX_NUM = 4;
static const int c_lWarpMapIndexs[WARP_MAP_INDEX_NUM] = {61, 62, 63, 64}; static const int c_lWarpMapIndexs[WARP_MAP_INDEX_NUM] = {61, 62, 63, 64};
*/ */
// 신선자 노해용 // 신선자 노해용
const int WARP_MAP_INDEX_NUM = 7; const int WARP_MAP_INDEX_NUM = 7;
static const int c_lWarpMapIndexs[WARP_MAP_INDEX_NUM] = { 61, 62, 63, 64, 3, 23, 43 }; static const int c_lWarpMapIndexs[WARP_MAP_INDEX_NUM] = { 61, 62, 63, 64, 3, 23, 43 };
int lNextMapIndex; int lNextMapIndex;
@ -553,7 +553,7 @@ void CHARACTER::__StateIdle_NPC()
if (map_allow_find(lNextMapIndex)) if (map_allow_find(lNextMapIndex))
{ {
// 이곳입니다. // 이곳입니다.
M2_DESTROY_CHARACTER(this); M2_DESTROY_CHARACTER(this);
int iNextSpawnDelay = 0; int iNextSpawnDelay = 0;
if (LC_IsYMIR()) if (LC_IsYMIR())
@ -565,7 +565,7 @@ void CHARACTER::__StateIdle_NPC()
} }
else else
{ {
// 다른 서버 입니다. // 다른 서버 입니다.
TPacketGGXmasWarpSanta p; TPacketGGXmasWarpSanta p;
p.bHeader = HEADER_GG_XMAS_WARP_SANTA; p.bHeader = HEADER_GG_XMAS_WARP_SANTA;
p.bChannel = g_bChannel; p.bChannel = g_bChannel;
@ -579,7 +579,7 @@ void CHARACTER::__StateIdle_NPC()
if (!IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOMOVE)) if (!IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOMOVE))
{ {
// //
// 이 곳 저 곳 이동한다. // 이 곳 저 곳 이동한다.
// //
LPCHARACTER pkChrProtege = GetProtege(); LPCHARACTER pkChrProtege = GetProtege();
@ -594,14 +594,14 @@ void CHARACTER::__StateIdle_NPC()
if (!Random::get(0, 6)) if (!Random::get(0, 6))
{ {
SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정 SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
float fx, fy; float fx, fy;
float fDist = Random::get(200, 400); float fDist = Random::get(200, 400);
GetDeltaByDegree(GetRotation(), fDist, &fx, &fy); GetDeltaByDegree(GetRotation(), fDist, &fx, &fy);
// 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다. // 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다.
if (!(SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx, GetY() + (int) fy) if (!(SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx, GetY() + (int) fy)
&& SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx / 2, GetY() + (int) fy / 2))) && SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx / 2, GetY() + (int) fy / 2)))
return; return;
@ -627,7 +627,7 @@ void CHARACTER::__StateIdle_Monster()
if (IsCoward()) if (IsCoward())
{ {
// 겁쟁이 몬스터는 도망만 다닙니다. // 겁쟁이 몬스터는 도망만 다닙니다.
if (!IsDead()) if (!IsDead())
CowardEscape(); CowardEscape();
@ -653,16 +653,16 @@ void CHARACTER::__StateIdle_Monster()
if (!victim || victim->IsBuilding()) if (!victim || victim->IsBuilding())
{ {
// 돌 보호 처리 // 돌 보호 처리
if (m_pkChrStone) if (m_pkChrStone)
{ {
victim = m_pkChrStone->GetNearestVictim(m_pkChrStone); victim = m_pkChrStone->GetNearestVictim(m_pkChrStone);
} }
// 선공 몬스터 처리 // 선공 몬스터 처리
else if (!no_wander && IsAggressive()) else if (!no_wander && IsAggressive())
{ {
if (GetMapIndex() == 61 && quest::CQuestManager::instance().GetEventFlag("xmas_tree")); if (GetMapIndex() == 61 && quest::CQuestManager::instance().GetEventFlag("xmas_tree"));
// 서한산에서 나무가 있으면 선공하지않는다. // 서한산에서 나무가 있으면 선공하지않는다.
else else
victim = FindVictim(this, m_pkMobData->m_table.wAggressiveSight); victim = FindVictim(this, m_pkMobData->m_table.wAggressiveSight);
} }
@ -683,7 +683,7 @@ void CHARACTER::__StateIdle_Monster()
LPCHARACTER pkChrProtege = GetProtege(); LPCHARACTER pkChrProtege = GetProtege();
// 보호할 것(돌, 파티장)에게로 부터 멀다면 따라간다. // 보호할 것(돌, 파티장)에게로 부터 멀다면 따라간다.
if (pkChrProtege) if (pkChrProtege)
{ {
if (DISTANCE_APPROX(GetX() - pkChrProtege->GetX(), GetY() - pkChrProtege->GetY()) > 1000) if (DISTANCE_APPROX(GetX() - pkChrProtege->GetX(), GetY() - pkChrProtege->GetY()) > 1000)
@ -697,26 +697,26 @@ void CHARACTER::__StateIdle_Monster()
} }
// //
// 그냥 왔다리 갔다리 한다. // 그냥 왔다리 갔다리 한다.
// //
if (!no_wander && !IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOMOVE)) if (!no_wander && !IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOMOVE))
{ {
if (!Random::get(0, 6)) if (!Random::get(0, 6))
{ {
SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정 SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
float fx, fy; float fx, fy;
float fDist = Random::get(300, 700); float fDist = Random::get(300, 700);
GetDeltaByDegree(GetRotation(), fDist, &fx, &fy); GetDeltaByDegree(GetRotation(), fDist, &fx, &fy);
// 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다. // 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다.
if (!(SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx, GetY() + (int) fy) if (!(SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx, GetY() + (int) fy)
&& SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx/2, GetY() + (int) fy/2))) && SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx/2, GetY() + (int) fy/2)))
return; return;
// NOTE: 몬스터가 IDLE 상태에서 주변을 서성거릴 때, 현재 무조건 뛰어가게 되어 있음. (절대로 걷지 않음) // NOTE: 몬스터가 IDLE 상태에서 주변을 서성거릴 때, 현재 무조건 뛰어가게 되어 있음. (절대로 걷지 않음)
// 그래픽 팀에서 몬스터가 걷는 모습도 보고싶다고 해서 임시로 특정확률로 걷거나 뛰게 함. (게임의 전반적인 느낌이 틀려지기 때문에 일단 테스트 모드에서만 작동) // 그래픽 팀에서 몬스터가 걷는 모습도 보고싶다고 해서 임시로 특정확률로 걷거나 뛰게 함. (게임의 전반적인 느낌이 틀려지기 때문에 일단 테스트 모드에서만 작동)
if (g_test_server) if (g_test_server)
{ {
if (Random::get(0, 100) < 60) if (Random::get(0, 100) < 60)
@ -745,13 +745,13 @@ bool __CHARACTER_GotoNearTarget(LPCHARACTER self, LPCHARACTER victim)
{ {
case BATTLE_TYPE_RANGE: case BATTLE_TYPE_RANGE:
case BATTLE_TYPE_MAGIC: case BATTLE_TYPE_MAGIC:
// 마법사나 궁수는 공격 거리의 80%까지 가서 공격을 시작한다. // 마법사나 궁수는 공격 거리의 80%까지 가서 공격을 시작한다.
if (self->Follow(victim, self->GetMobAttackRange() * 8 / 10)) if (self->Follow(victim, self->GetMobAttackRange() * 8 / 10))
return true; return true;
break; break;
default: default:
// 나머지는 90%? // 나머지는 90%?
if (self->Follow(victim, self->GetMobAttackRange() * 9 / 10)) if (self->Follow(victim, self->GetMobAttackRange() * 9 / 10))
return true; return true;
} }
@ -781,7 +781,7 @@ void CHARACTER::StateMove()
LPCHARACTER victim = GetExchange()->GetCompany()->GetOwner(); LPCHARACTER victim = GetExchange()->GetCompany()->GetOwner();
int iDist = DISTANCE_APPROX(GetX() - victim->GetX(), GetY() - victim->GetY()); int iDist = DISTANCE_APPROX(GetX() - victim->GetX(), GetY() - victim->GetY());
// 거리 체크 // 거리 체크
if (iDist >= EXCHANGE_MAX_DISTANCE) if (iDist >= EXCHANGE_MAX_DISTANCE)
{ {
GetExchange()->Cancel(); GetExchange()->Cancel();
@ -789,17 +789,17 @@ void CHARACTER::StateMove()
} }
} }
// 스테미나가 0 이상이어야 한다. // 스테미나가 0 이상이어야 한다.
if (IsPC()) if (IsPC())
{ {
if (IsWalking() && GetStamina() < GetMaxStamina()) if (IsWalking() && GetStamina() < GetMaxStamina())
{ {
// 5초 후 부터 스테미너 증가 // 5초 후 부터 스테미너 증가
if (get_dword_time() - GetWalkStartTime() > 5000) if (get_dword_time() - GetWalkStartTime() > 5000)
PointChange(POINT_STAMINA, GetMaxStamina() / 1); PointChange(POINT_STAMINA, GetMaxStamina() / 1);
} }
// 전투 중이면서 뛰는 중이면 // 전투 중이면서 뛰는 중이면
if (!IsWalking() && !IsRiding()) if (!IsWalking() && !IsRiding())
if ((get_dword_time() - GetLastAttackTime()) < 20000) if ((get_dword_time() - GetLastAttackTime()) < 20000)
{ {
@ -817,7 +817,7 @@ void CHARACTER::StateMove()
if (GetStamina() <= 0) if (GetStamina() <= 0)
{ {
// 스테미나가 모자라 걸어야함 // 스테미나가 모자라 걸어야함
SetStamina(0); SetStamina(0);
SetNowWalking(true); SetNowWalking(true);
StopStaminaConsume(); StopStaminaConsume();
@ -838,7 +838,7 @@ void CHARACTER::StateMove()
if (g_test_server) if (g_test_server)
{ {
// 몬스터가 적을 쫓아가는 것이면 무조건 뛰어간다. // 몬스터가 적을 쫓아가는 것이면 무조건 뛰어간다.
SetNowWalking(false); SetNowWalking(false);
} }
} }
@ -847,10 +847,10 @@ void CHARACTER::StateMove()
{ {
LPCHARACTER victim = GetVictim(); LPCHARACTER victim = GetVictim();
// 거대 거북 // 거대 거북
if (GetRaceNum() == 2191 && Random::get(1, 20) == 1 && get_dword_time() - m_pkMobInst->m_dwLastWarpTime > 1000) if (GetRaceNum() == 2191 && Random::get(1, 20) == 1 && get_dword_time() - m_pkMobInst->m_dwLastWarpTime > 1000)
{ {
// 워프 테스트 // 워프 테스트
float fx, fy; float fx, fy;
GetDeltaByDegree(victim->GetRotation(), 400, &fx, &fy); GetDeltaByDegree(victim->GetRotation(), 400, &fx, &fy);
int new_x = victim->GetX() + (int)fx; int new_x = victim->GetX() + (int)fx;
@ -864,7 +864,7 @@ void CHARACTER::StateMove()
return; return;
} }
// TODO 방향전환을 해서 덜 바보가 되자! // TODO 방향전환을 해서 덜 바보가 되자!
if (Random::get(0, 3) == 0) if (Random::get(0, 3) == 0)
{ {
if (__CHARACTER_GotoNearTarget(this, victim)) if (__CHARACTER_GotoNearTarget(this, victim))
@ -1005,7 +1005,7 @@ void CHARACTER::StateBattle()
{ {
if (!GetParty()) if (!GetParty())
{ {
// 서몬해서 채워둘 파티를 만들어 둡니다. // 서몬해서 채워둘 파티를 만들어 둡니다.
CPartyManager::instance().CreateParty(this); CPartyManager::instance().CreateParty(this);
} }
@ -1015,7 +1015,7 @@ void CHARACTER::StateBattle()
if (bPct && pParty->CountMemberByVnum(GetSummonVnum()) < SUMMON_MONSTER_COUNT) if (bPct && pParty->CountMemberByVnum(GetSummonVnum()) < SUMMON_MONSTER_COUNT)
{ {
MonsterLog("\xBA\xCE\xC7\xCF \xB8\xF3\xBD\xBA\xC5\xCD \xBC\xD2\xC8\xAF!"); MonsterLog("\xBA\xCE\xC7\xCF \xB8\xF3\xBD\xBA\xC5\xCD \xBC\xD2\xC8\xAF!");
// 모자라는 녀석을 불러내 채웁시다. // 모자라는 녀석을 불러내 채웁시다.
int sx = GetX() - 300; int sx = GetX() - 300;
int sy = GetY() - 300; int sy = GetY() - 300;
int ex = GetX() + 300; int ex = GetX() + 300;
@ -1035,12 +1035,12 @@ void CHARACTER::StateBattle()
float fDist = DISTANCE_APPROX(GetX() - victim->GetX(), GetY() - victim->GetY()); float fDist = DISTANCE_APPROX(GetX() - victim->GetX(), GetY() - victim->GetY());
if (fDist >= 4000.0f) // 40미터 이상 멀어지면 포기 if (fDist >= 4000.0f) // 40미터 이상 멀어지면 포기
{ {
MonsterLog("\xC5\xB8\xB0\xD9\xC0\xCC \xB8\xD6\xBE\xEE\xBC\xAD \xC6\xF7\xB1\xE2"); MonsterLog("\xC5\xB8\xB0\xD9\xC0\xCC \xB8\xD6\xBE\xEE\xBC\xAD \xC6\xF7\xB1\xE2");
SetVictim(NULL); SetVictim(NULL);
// 보호할 것(돌, 파티장) 주변으로 간다. // 보호할 것(돌, 파티장) 주변으로 간다.
if (pkChrProtege) if (pkChrProtege)
if (DISTANCE_APPROX(GetX() - pkChrProtege->GetX(), GetY() - pkChrProtege->GetY()) > 1000) if (DISTANCE_APPROX(GetX() - pkChrProtege->GetX(), GetY() - pkChrProtege->GetY()) > 1000)
Follow(pkChrProtege, Random::get(150, 400)); Follow(pkChrProtege, Random::get(150, 400));
@ -1059,7 +1059,7 @@ void CHARACTER::StateBattle()
if (2493 == m_pkMobData->m_table.dwVnum) if (2493 == m_pkMobData->m_table.dwVnum)
{ {
// 수룡(2493) 특수 처리 // 수룡(2493) 특수 처리
m_dwStateDuration = BlueDragon_StateBattle(this); m_dwStateDuration = BlueDragon_StateBattle(this);
return; return;
} }
@ -1067,7 +1067,7 @@ void CHARACTER::StateBattle()
DWORD dwCurTime = get_dword_time(); DWORD dwCurTime = get_dword_time();
DWORD dwDuration = CalculateDuration(GetLimitPoint(POINT_ATT_SPEED), 2000); DWORD dwDuration = CalculateDuration(GetLimitPoint(POINT_ATT_SPEED), 2000);
if ((dwCurTime - m_dwLastAttackTime) < dwDuration) // 2초 마다 공격해야 한다. if ((dwCurTime - m_dwLastAttackTime) < dwDuration) // 2초 마다 공격해야 한다.
{ {
m_dwStateDuration = std::max<int>(1, (passes_per_sec * (dwDuration - (dwCurTime - m_dwLastAttackTime)) / 1000)); m_dwStateDuration = std::max<int>(1, (passes_per_sec * (dwDuration - (dwCurTime - m_dwLastAttackTime)) / 1000));
return; return;
@ -1084,7 +1084,7 @@ void CHARACTER::StateBattle()
SetGodSpeed(true); SetGodSpeed(true);
// //
// 몹 스킬 처리 // 몹 스킬 처리
// //
if (HasMobSkill()) if (HasMobSkill())
{ {
@ -1109,11 +1109,11 @@ void CHARACTER::StateBattle()
} }
} }
if (!Attack(victim)) // 공격 실패라면? 왜 실패했지? TODO if (!Attack(victim)) // 공격 실패라면? 왜 실패했지? TODO
m_dwStateDuration = passes_per_sec / 2; m_dwStateDuration = passes_per_sec / 2;
else else
{ {
// 적을 바라보게 만든다. // 적을 바라보게 만든다.
SetRotationToXY(victim->GetX(), victim->GetY()); SetRotationToXY(victim->GetX(), victim->GetY());
SendMovePacket(FUNC_ATTACK, 0, GetX(), GetY(), 0, dwCurTime); SendMovePacket(FUNC_ATTACK, 0, GetX(), GetY(), 0, dwCurTime);
@ -1166,15 +1166,15 @@ void CHARACTER::StateFlagBase()
void CHARACTER::StateHorse() void CHARACTER::StateHorse()
{ {
float START_FOLLOW_DISTANCE = 400.0f; // 이 거리 이상 떨어지면 쫓아가기 시작함 float START_FOLLOW_DISTANCE = 400.0f; // 이 거리 이상 떨어지면 쫓아가기 시작함
float START_RUN_DISTANCE = 700.0f; // 이 거리 이상 떨어지면 뛰어서 쫓아감. float START_RUN_DISTANCE = 700.0f; // 이 거리 이상 떨어지면 뛰어서 쫓아감.
int MIN_APPROACH = 150; // 최소 접근 거리 int MIN_APPROACH = 150; // 최소 접근 거리
int MAX_APPROACH = 300; // 최대 접근 거리 int MAX_APPROACH = 300; // 최대 접근 거리
DWORD STATE_DURATION = (DWORD)PASSES_PER_SEC(0.5); // 상태 지속 시간 DWORD STATE_DURATION = (DWORD)PASSES_PER_SEC(0.5); // 상태 지속 시간
bool bDoMoveAlone = true; // 캐릭터와 가까이 있을 때 혼자 여기저기 움직일건지 여부 -_-; bool bDoMoveAlone = true; // 캐릭터와 가까이 있을 때 혼자 여기저기 움직일건지 여부 -_-;
bool bRun = true; // 뛰어야 하나? bool bRun = true; // 뛰어야 하나?
if (IsDead()) if (IsDead())
return; return;
@ -1183,7 +1183,7 @@ void CHARACTER::StateHorse()
LPCHARACTER victim = GetRider(); LPCHARACTER victim = GetRider();
// ! 아님 // 대상이 없는 경우 소환자가 직접 나를 클리어할 것임 // ! 아님 // 대상이 없는 경우 소환자가 직접 나를 클리어할 것임
if (!victim) if (!victim)
{ {
M2_DESTROY_CHARACTER(this); M2_DESTROY_CHARACTER(this);
@ -1197,7 +1197,7 @@ void CHARACTER::StateHorse()
if (fDist >= START_FOLLOW_DISTANCE) if (fDist >= START_FOLLOW_DISTANCE)
{ {
if (fDist > START_RUN_DISTANCE) if (fDist > START_RUN_DISTANCE)
SetNowWalking(!bRun); // NOTE: 함수 이름보고 멈추는건줄 알았는데 SetNowWalking(false) 하면 뛰는거임.. -_-; SetNowWalking(!bRun); // NOTE: 함수 이름보고 멈추는건줄 알았는데 SetNowWalking(false) 하면 뛰는거임.. -_-;
Follow(victim, Random::get(MIN_APPROACH, MAX_APPROACH)); Follow(victim, Random::get(MIN_APPROACH, MAX_APPROACH));
@ -1208,14 +1208,14 @@ void CHARACTER::StateHorse()
// wondering-.- // wondering-.-
m_dwLastAttackTime = get_dword_time() + Random::get(5000, 12000); m_dwLastAttackTime = get_dword_time() + Random::get(5000, 12000);
SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정 SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
float fx, fy; float fx, fy;
float fDist = Random::get(200, 400); float fDist = Random::get(200, 400);
GetDeltaByDegree(GetRotation(), fDist, &fx, &fy); GetDeltaByDegree(GetRotation(), fDist, &fx, &fy);
// 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다. // 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다.
if (!(SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx, GetY() + (int) fy) if (!(SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx, GetY() + (int) fy)
&& SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx/2, GetY() + (int) fy/2))) && SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx/2, GetY() + (int) fy/2)))
return; return;

View File

@ -187,7 +187,7 @@ ACMD(do_effect);
ACMD(do_threeway_war_info ); ACMD(do_threeway_war_info );
ACMD(do_threeway_war_myinfo ); ACMD(do_threeway_war_myinfo );
// //
//군주 전용기능 //군주 전용기능
ACMD(do_monarch_warpto); ACMD(do_monarch_warpto);
ACMD(do_monarch_transfer); ACMD(do_monarch_transfer);
ACMD(do_monarch_info); ACMD(do_monarch_info);
@ -196,7 +196,7 @@ ACMD(do_monarch_tax);
ACMD(do_monarch_mob); ACMD(do_monarch_mob);
ACMD(do_monarch_notice); ACMD(do_monarch_notice);
//군주 관리 기능 //군주 관리 기능
ACMD(do_rmcandidacy); ACMD(do_rmcandidacy);
ACMD(do_setmonarch); ACMD(do_setmonarch);
ACMD(do_rmmonarch); ACMD(do_rmmonarch);
@ -204,10 +204,10 @@ ACMD(do_rmmonarch);
ACMD(do_hair); ACMD(do_hair);
//gift notify quest command //gift notify quest command
ACMD(do_gift); ACMD(do_gift);
// 큐브관련 // 큐브관련
ACMD(do_inventory); ACMD(do_inventory);
ACMD(do_cube); ACMD(do_cube);
// 공성전 // 공성전
ACMD(do_siege); ACMD(do_siege);
ACMD(do_temp); ACMD(do_temp);
ACMD(do_frog); ACMD(do_frog);
@ -235,7 +235,7 @@ ACMD(do_ride);
ACMD(do_get_item_id_list); ACMD(do_get_item_id_list);
ACMD(do_set_socket); ACMD(do_set_socket);
#ifdef __AUCTION__ #ifdef __AUCTION__
// temp_auction 임시 // temp_auction 임시
ACMD(do_get_auction_list); ACMD(do_get_auction_list);
ACMD (do_get_my_auction_list); ACMD (do_get_my_auction_list);
ACMD (do_get_my_purchase_list); ACMD (do_get_my_purchase_list);
@ -255,21 +255,21 @@ ACMD (do_cancel_sale);
ACMD (do_rebid); ACMD (do_rebid);
ACMD (do_bid_cancel); ACMD (do_bid_cancel);
#endif #endif
// 코스츔 상태보기 및 벗기 // 코스츔 상태보기 및 벗기
ACMD(do_costume); ACMD(do_costume);
ACMD(do_set_stat); ACMD(do_set_stat);
// 무적 // 무적
ACMD (do_can_dead); ACMD (do_can_dead);
ACMD (do_full_set); ACMD (do_full_set);
// 직군과 레벨에 따른 최고 아이템 // 직군과 레벨에 따른 최고 아이템
ACMD (do_item_full_set); ACMD (do_item_full_set);
// 직군에 따른 최고 옵션의 속성 셋팅 // 직군에 따른 최고 옵션의 속성 셋팅
ACMD (do_attr_full_set); ACMD (do_attr_full_set);
// 모든 스킬 마스터 // 모든 스킬 마스터
ACMD (do_all_skill_master); ACMD (do_all_skill_master);
// 아이템 착용. icon이 없어 클라에서 확인 할 수 없는 아이템 착용을 위해 만듦. // 아이템 착용. icon이 없어 클라에서 확인 할 수 없는 아이템 착용을 위해 만듦.
ACMD (do_use_item); ACMD (do_use_item);
ACMD (do_dragon_soul); ACMD (do_dragon_soul);
ACMD (do_ds_list); ACMD (do_ds_list);
@ -277,7 +277,7 @@ ACMD (do_clear_affect);
struct command_info cmd_info[] = struct command_info cmd_info[] =
{ {
{ "!RESERVED!", NULL, 0, POS_DEAD, GM_IMPLEMENTOR }, /* 반드시 이 것이 처음이어야 한다. */ { "!RESERVED!", NULL, 0, POS_DEAD, GM_IMPLEMENTOR }, /* 반드시 이 것이 처음이어야 한다. */
{ "who", do_who, 0, POS_DEAD, GM_IMPLEMENTOR }, { "who", do_who, 0, POS_DEAD, GM_IMPLEMENTOR },
{ "war", do_war, 0, POS_DEAD, GM_PLAYER }, { "war", do_war, 0, POS_DEAD, GM_PLAYER },
{ "warp", do_warp, 0, POS_DEAD, GM_LOW_WIZARD }, { "warp", do_warp, 0, POS_DEAD, GM_LOW_WIZARD },
@ -298,7 +298,7 @@ struct command_info cmd_info[] =
{ "item", do_item, 0, POS_DEAD, GM_GOD }, { "item", do_item, 0, POS_DEAD, GM_GOD },
{ "mob", do_mob, 0, POS_DEAD, GM_HIGH_WIZARD }, { "mob", do_mob, 0, POS_DEAD, GM_HIGH_WIZARD },
{ "mob_ld", do_mob_ld, 0, POS_DEAD, GM_HIGH_WIZARD }, /* 몹의 위치와 방향을 설정해 소환 /mob_ld vnum x y dir */ { "mob_ld", do_mob_ld, 0, POS_DEAD, GM_HIGH_WIZARD }, /* 몹의 위치와 방향을 설정해 소환 /mob_ld vnum x y dir */
{ "ma", do_mob_aggresive, 0, POS_DEAD, GM_HIGH_WIZARD }, { "ma", do_mob_aggresive, 0, POS_DEAD, GM_HIGH_WIZARD },
{ "mc", do_mob_coward, 0, POS_DEAD, GM_HIGH_WIZARD }, { "mc", do_mob_coward, 0, POS_DEAD, GM_HIGH_WIZARD },
{ "mm", do_mob_map, 0, POS_DEAD, GM_HIGH_WIZARD }, { "mm", do_mob_map, 0, POS_DEAD, GM_HIGH_WIZARD },
@ -546,7 +546,7 @@ struct command_info cmd_info[] =
{ "item_id_list", do_get_item_id_list, 0, POS_DEAD, GM_LOW_WIZARD }, { "item_id_list", do_get_item_id_list, 0, POS_DEAD, GM_LOW_WIZARD },
{ "set_socket", do_set_socket, 0, POS_DEAD, GM_LOW_WIZARD }, { "set_socket", do_set_socket, 0, POS_DEAD, GM_LOW_WIZARD },
#ifdef __AUCTION__ #ifdef __AUCTION__
// auction 임시 // auction 임시
{ "auction_list", do_get_auction_list, 0, POS_DEAD, GM_PLAYER }, { "auction_list", do_get_auction_list, 0, POS_DEAD, GM_PLAYER },
{ "my_auction_list", do_get_my_auction_list, 0, POS_DEAD, GM_PLAYER }, { "my_auction_list", do_get_my_auction_list, 0, POS_DEAD, GM_PLAYER },
{ "my_purchase_list", do_get_my_purchase_list, 0, POS_DEAD, GM_PLAYER }, { "my_purchase_list", do_get_my_purchase_list, 0, POS_DEAD, GM_PLAYER },
@ -586,7 +586,7 @@ struct command_info cmd_info[] =
{ "ds_list", do_ds_list, 0, POS_DEAD, GM_PLAYER }, { "ds_list", do_ds_list, 0, POS_DEAD, GM_PLAYER },
{ "do_clear_affect", do_clear_affect, 0, POS_DEAD, GM_LOW_WIZARD}, { "do_clear_affect", do_clear_affect, 0, POS_DEAD, GM_LOW_WIZARD},
{ "\n", NULL, 0, POS_DEAD, GM_IMPLEMENTOR } /* 반드시 이 것이 마지막이어야 한다. */ { "\n", NULL, 0, POS_DEAD, GM_IMPLEMENTOR } /* 반드시 이 것이 마지막이어야 한다. */
}; };
void interpreter_set_privilege(const char *cmd, int lvl) void interpreter_set_privilege(const char *cmd, int lvl)
@ -609,7 +609,7 @@ void double_dollar(const char *src, size_t src_len, char *dest, size_t dest_len)
const char * tmp = src; const char * tmp = src;
size_t cur_len = 0; size_t cur_len = 0;
// \0 넣을 자리 확보 // \0 넣을 자리 확보
dest_len -= 1; dest_len -= 1;
while (src_len-- && *tmp) while (src_len-- && *tmp)
@ -644,7 +644,7 @@ void interpret_command(LPCHARACTER ch, const char * argument, size_t len)
return ; return ;
} }
char cmd[128 + 1]; // buffer overflow 문제가 생기지 않도록 일부러 길이를 짧게 잡음 char cmd[128 + 1]; // buffer overflow 문제가 생기지 않도록 일부러 길이를 짧게 잡음
char new_line[256 + 1]; char new_line[256 + 1];
const char * line; const char * line;
int icmd; int icmd;
@ -661,7 +661,7 @@ void interpret_command(LPCHARACTER ch, const char * argument, size_t len)
{ {
if (cmd_info[icmd].command_pointer == do_cmd) if (cmd_info[icmd].command_pointer == do_cmd)
{ {
if (!strcmp(cmd_info[icmd].command, cmd)) // do_cmd는 모든 명령어를 쳐야 할 수 있다. if (!strcmp(cmd_info[icmd].command, cmd)) // do_cmd는 모든 명령어를 쳐야 할 수 있다.
break; break;
} }
else if (!strncmp(cmd_info[icmd].command, cmd, cmdlen)) else if (!strncmp(cmd_info[icmd].command, cmd, cmdlen))
@ -713,7 +713,7 @@ void interpret_command(LPCHARACTER ch, const char * argument, size_t len)
return; return;
} }
if (strncmp("phase", cmd_info[icmd].command, 5) != 0) // 히든 명령어 처리 if (strncmp("phase", cmd_info[icmd].command, 5) != 0) // 히든 명령어 처리
SPDLOG_DEBUG("COMMAND: {}: {}", ch->GetName(), cmd_info[icmd].command); SPDLOG_DEBUG("COMMAND: {}: {}", ch->GetName(), cmd_info[icmd].command);
((*cmd_info[icmd].command_pointer) (ch, line, icmd, cmd_info[icmd].subcmd)); ((*cmd_info[icmd].command_pointer) (ch, line, icmd, cmd_info[icmd].subcmd));

View File

@ -108,11 +108,11 @@ ACMD(do_emotion_allow)
bool CHARACTER_CanEmotion(CHARACTER& rch) bool CHARACTER_CanEmotion(CHARACTER& rch)
{ {
// <EFBFBD><EFBFBD>ȥ<EFBFBD><EFBFBD> <20>ʿ<EFBFBD><CABF><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20>ִ<EFBFBD>. // 결혼식 맵에서는 사용할 수 있다.
if (marriage::WeddingManager::instance().IsWeddingMap(rch.GetMapIndex())) if (marriage::WeddingManager::instance().IsWeddingMap(rch.GetMapIndex()))
return true; return true;
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20>ִ<EFBFBD>. // 열정의 가면 착용시 사용할 수 있다.
if (rch.IsEquipUniqueItem(UNIQUE_ITEM_EMOTION_MASK)) if (rch.IsEquipUniqueItem(UNIQUE_ITEM_EMOTION_MASK))
return true; return true;
@ -246,7 +246,7 @@ ACMD(do_emotion)
if (len < 0 || len >= (int) sizeof(chatbuf)) if (len < 0 || len >= (int) sizeof(chatbuf))
len = sizeof(chatbuf) - 1; len = sizeof(chatbuf) - 1;
++len; // \0 <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> ++len; // \0 문자 포함
TPacketGCChat pack_chat; TPacketGCChat pack_chat;
pack_chat.header = HEADER_GC_CHAT; pack_chat.header = HEADER_GC_CHAT;

View File

@ -46,7 +46,7 @@ ACMD(do_user_horse_ride)
if (ch->IsHorseRiding() == false) if (ch->IsHorseRiding() == false)
{ {
// 말이 아닌 다른탈것을 타고있다. // 말이 아닌 다른탈것을 타고있다.
if (ch->GetMountVnum()) if (ch->GetMountVnum())
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xC0\xCC\xB9\xCC \xC5\xBB\xB0\xCD\xC0\xBB \xC0\xCC\xBF\xEB\xC1\xDF\xC0\xD4\xB4\xCF\xB4\xD9.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xC0\xCC\xB9\xCC \xC5\xBB\xB0\xCD\xC0\xBB \xC0\xCC\xBF\xEB\xC1\xDF\xC0\xD4\xB4\xCF\xB4\xD9."));
@ -86,7 +86,7 @@ ACMD(do_user_horse_back)
ACMD(do_user_horse_feed) ACMD(do_user_horse_feed)
{ {
// 개인상점을 연 상태에서는 말 먹이를 줄 수 없다. // 개인상점을 연 상태에서는 말 먹이를 줄 수 없다.
if (ch->GetMyShop()) if (ch->GetMyShop())
return; return;
@ -397,7 +397,7 @@ ACMD(do_mount)
char arg1[256]; char arg1[256];
struct action_mount_param param; struct action_mount_param param;
// 이미 타고 있으면 // 이미 타고 있으면
if (ch->GetMountingChr()) if (ch->GetMountingChr())
{ {
char arg2[256]; char arg2[256];
@ -488,7 +488,7 @@ ACMD(do_restart)
{ {
if (ch->IsHack()) if (ch->IsHack())
{ {
//성지 맵일경우에는 체크 하지 않는다. //성지 맵일경우에는 체크 하지 않는다.
if (false == CThreeWayWar::instance().IsSungZiMapIndex(ch->GetMapIndex())) if (false == CThreeWayWar::instance().IsSungZiMapIndex(ch->GetMapIndex()))
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xBE\xC6\xC1\xF7 \xC0\xE7\xBD\xC3\xC0\xDB \xC7\xD2 \xBC\xF6 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9. (%d\xC3\xCA \xB3\xB2\xC0\xBD)"), iTimeToDead - (180 - g_nPortalLimitTime)); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xBE\xC6\xC1\xF7 \xC0\xE7\xBD\xC3\xC0\xDB \xC7\xD2 \xBC\xF6 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9. (%d\xC3\xCA \xB3\xB2\xC0\xBD)"), iTimeToDead - (180 - g_nPortalLimitTime));
@ -505,13 +505,13 @@ ACMD(do_restart)
} }
//PREVENT_HACK //PREVENT_HACK
//DESC : 창고, 교환 창 후 포탈을 사용하는 버그에 이용될수 있어서 //DESC : 창고, 교환 창 후 포탈을 사용하는 버그에 이용될수 있어서
// 쿨타임을 추가 // 쿨타임을 추가
if (subcmd == SCMD_RESTART_TOWN) if (subcmd == SCMD_RESTART_TOWN)
{ {
if (ch->IsHack()) if (ch->IsHack())
{ {
//길드맵, 성지맵에서는 체크 하지 않는다. //길드맵, 성지맵에서는 체크 하지 않는다.
if ((!ch->GetWarMap() || ch->GetWarMap()->GetType() == GUILD_WAR_TYPE_FLAG) || if ((!ch->GetWarMap() || ch->GetWarMap()->GetType() == GUILD_WAR_TYPE_FLAG) ||
false == CThreeWayWar::instance().IsSungZiMapIndex(ch->GetMapIndex())) false == CThreeWayWar::instance().IsSungZiMapIndex(ch->GetMapIndex()))
{ {
@ -535,7 +535,7 @@ ACMD(do_restart)
ch->StartRecoveryEvent(); ch->StartRecoveryEvent();
//FORKED_LOAD //FORKED_LOAD
//DESC: 삼거리 전투시 부활을 할경우 맵의 입구가 아닌 삼거리 전투의 시작지점으로 이동하게 된다. //DESC: 삼거리 전투시 부활을 할경우 맵의 입구가 아닌 삼거리 전투의 시작지점으로 이동하게 된다.
if (1 == quest::CQuestManager::instance().GetEventFlag("threeway_war")) if (1 == quest::CQuestManager::instance().GetEventFlag("threeway_war"))
{ {
if (subcmd == SCMD_RESTART_TOWN || subcmd == SCMD_RESTART_HERE) if (subcmd == SCMD_RESTART_TOWN || subcmd == SCMD_RESTART_HERE)
@ -552,7 +552,7 @@ ACMD(do_restart)
return; return;
} }
//성지 //성지
if (true == CThreeWayWar::instance().IsSungZiMapIndex(ch->GetMapIndex())) if (true == CThreeWayWar::instance().IsSungZiMapIndex(ch->GetMapIndex()))
{ {
if (CThreeWayWar::instance().GetReviveTokenForPlayer(ch->GetPlayerID()) <= 0) if (CThreeWayWar::instance().GetReviveTokenForPlayer(ch->GetPlayerID()) <= 0)
@ -867,7 +867,7 @@ ACMD(do_skillup)
} }
// //
// @version 05/06/20 Bang2ni - 커맨드 처리 Delegate to CHARACTER class // @version 05/06/20 Bang2ni - 커맨드 처리 Delegate to CHARACTER class
// //
ACMD(do_safebox_close) ACMD(do_safebox_close)
{ {
@ -875,7 +875,7 @@ ACMD(do_safebox_close)
} }
// //
// @version 05/06/20 Bang2ni - 커맨드 처리 Delegate to CHARACTER class // @version 05/06/20 Bang2ni - 커맨드 처리 Delegate to CHARACTER class
// //
ACMD(do_safebox_password) ACMD(do_safebox_password)
{ {
@ -946,7 +946,7 @@ ACMD(do_mall_password)
return; return;
} }
if (iPulse - ch->GetMallLoadTime() < passes_per_sec * 10) // 10초에 한번만 요청 가능 if (iPulse - ch->GetMallLoadTime() < passes_per_sec * 10) // 10초에 한번만 요청 가능
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<\xC3\xA2\xB0\xED> \xC3\xA2\xB0\xED\xB8\xA6 \xB4\xDD\xC0\xBA\xC1\xF6 10\xC3\xCA \xBE\xC8\xBF\xA1\xB4\xC2 \xBF\xAD \xBC\xF6 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<\xC3\xA2\xB0\xED> \xC3\xA2\xB0\xED\xB8\xA6 \xB4\xDD\xC0\xBA\xC1\xF6 10\xC3\xCA \xBE\xC8\xBF\xA1\xB4\xC2 \xBF\xAD \xBC\xF6 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9."));
return; return;
@ -1028,20 +1028,20 @@ ACMD(do_set_run_mode)
ACMD(do_war) ACMD(do_war)
{ {
//내 길드 정보를 얻어오고 //내 길드 정보를 얻어오고
CGuild * g = ch->GetGuild(); CGuild * g = ch->GetGuild();
if (!g) if (!g)
return; return;
//전쟁중인지 체크한번! //전쟁중인지 체크한번!
if (g->UnderAnyWar()) if (g->UnderAnyWar())
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<\xB1\xE6\xB5\xE5> \xC0\xCC\xB9\xCC \xB4\xD9\xB8\xA5 \xC0\xFC\xC0\xEF\xBF\xA1 \xC2\xFC\xC0\xFC \xC1\xDF \xC0\xD4\xB4\xCF\xB4\xD9.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<\xB1\xE6\xB5\xE5> \xC0\xCC\xB9\xCC \xB4\xD9\xB8\xA5 \xC0\xFC\xC0\xEF\xBF\xA1 \xC2\xFC\xC0\xFC \xC1\xDF \xC0\xD4\xB4\xCF\xB4\xD9."));
return; return;
} }
//파라메터를 두배로 나누고 //파라메터를 두배로 나누고
char arg1[256], arg2[256]; char arg1[256], arg2[256];
int type = GUILD_WAR_TYPE_FIELD; int type = GUILD_WAR_TYPE_FIELD;
two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2)); two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2));
@ -1057,17 +1057,17 @@ ACMD(do_war)
type = GUILD_WAR_TYPE_FIELD; type = GUILD_WAR_TYPE_FIELD;
} }
//길드의 마스터 아이디를 얻어온뒤 //길드의 마스터 아이디를 얻어온뒤
DWORD gm_pid = g->GetMasterPID(); DWORD gm_pid = g->GetMasterPID();
//마스터인지 체크(길전은 길드장만이 가능) //마스터인지 체크(길전은 길드장만이 가능)
if (gm_pid != ch->GetPlayerID()) if (gm_pid != ch->GetPlayerID())
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<\xB1\xE6\xB5\xE5> \xB1\xE6\xB5\xE5\xC0\xFC\xBF\xA1 \xB4\xEB\xC7\xD1 \xB1\xC7\xC7\xD1\xC0\xCC \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<\xB1\xE6\xB5\xE5> \xB1\xE6\xB5\xE5\xC0\xFC\xBF\xA1 \xB4\xEB\xC7\xD1 \xB1\xC7\xC7\xD1\xC0\xCC \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9."));
return; return;
} }
//상대 길드를 얻어오고 //상대 길드를 얻어오고
CGuild * opp_g = CGuildManager::instance().FindGuildByName(arg1); CGuild * opp_g = CGuildManager::instance().FindGuildByName(arg1);
if (!opp_g) if (!opp_g)
@ -1076,7 +1076,7 @@ ACMD(do_war)
return; return;
} }
//상대길드와의 상태 체크 //상대길드와의 상태 체크
switch (g->GetGuildWarState(opp_g->GetID())) switch (g->GetGuildWarState(opp_g->GetID()))
{ {
case GUILD_WAR_NONE: case GUILD_WAR_NONE:
@ -1139,7 +1139,7 @@ ACMD(do_war)
if (!g->CanStartWar(type)) if (!g->CanStartWar(type))
{ {
// 길드전을 할 수 있는 조건을 만족하지않는다. // 길드전을 할 수 있는 조건을 만족하지않는다.
if (g->GetLadderPoint() == 0) if (g->GetLadderPoint() == 0)
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<\xB1\xE6\xB5\xE5> \xB7\xB9\xB4\xF5 \xC1\xA1\xBC\xF6\xB0\xA1 \xB8\xF0\xC0\xDA\xB6\xF3\xBC\xAD \xB1\xE6\xB5\xE5\xC0\xFC\xC0\xBB \xC7\xD2 \xBC\xF6 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<\xB1\xE6\xB5\xE5> \xB7\xB9\xB4\xF5 \xC1\xA1\xBC\xF6\xB0\xA1 \xB8\xF0\xC0\xDA\xB6\xF3\xBC\xAD \xB1\xE6\xB5\xE5\xC0\xFC\xC0\xBB \xC7\xD2 \xBC\xF6 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9."));
@ -1157,7 +1157,7 @@ ACMD(do_war)
return; return;
} }
// 필드전 체크만 하고 세세한 체크는 상대방이 승낙할때 한다. // 필드전 체크만 하고 세세한 체크는 상대방이 승낙할때 한다.
if (!opp_g->CanStartWar(GUILD_WAR_TYPE_FIELD)) if (!opp_g->CanStartWar(GUILD_WAR_TYPE_FIELD))
{ {
if (opp_g->GetLadderPoint() == 0) if (opp_g->GetLadderPoint() == 0)
@ -1452,17 +1452,17 @@ ACMD(do_monarch_warpto)
return; return;
} }
//군주 쿨타임 검사 //군주 쿨타임 검사
if (!ch->IsMCOK(CHARACTER::MI_WARP)) if (!ch->IsMCOK(CHARACTER::MI_WARP))
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d \xC3\xCA\xB0\xA3 \xC4\xF0\xC5\xB8\xC0\xD3\xC0\xCC \xC0\xFB\xBF\xEB\xC1\xDF\xC0\xD4\xB4\xCF\xB4\xD9."), ch->GetMCLTime(CHARACTER::MI_WARP)); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d \xC3\xCA\xB0\xA3 \xC4\xF0\xC5\xB8\xC0\xD3\xC0\xCC \xC0\xFB\xBF\xEB\xC1\xDF\xC0\xD4\xB4\xCF\xB4\xD9."), ch->GetMCLTime(CHARACTER::MI_WARP));
return; return;
} }
//군주 몹 소환 비용 //군주 몹 소환 비용
const int WarpPrice = 10000; const int WarpPrice = 10000;
//군주 국고 검사 //군주 국고 검사
if (!CMonarch::instance().IsMoneyOk(WarpPrice, ch->GetEmpire())) if (!CMonarch::instance().IsMoneyOk(WarpPrice, ch->GetEmpire()))
{ {
int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire());
@ -1516,10 +1516,10 @@ ACMD(do_monarch_warpto)
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s \xBF\xA1\xB0\xD4\xB7\xCE \xC0\xCC\xB5\xBF\xC7\xD5\xB4\xCF\xB4\xD9"), arg1); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s \xBF\xA1\xB0\xD4\xB7\xCE \xC0\xCC\xB5\xBF\xC7\xD5\xB4\xCF\xB4\xD9"), arg1);
ch->WarpSet(pos.x, pos.y); ch->WarpSet(pos.x, pos.y);
//군주 돈 삭감 //군주 돈 삭감
CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch);
//쿨타임 초기화 //쿨타임 초기화
ch->SetMC(CHARACTER::MI_WARP); ch->SetMC(CHARACTER::MI_WARP);
} }
} }
@ -1550,10 +1550,10 @@ ACMD(do_monarch_warpto)
ch->WarpSet(x, y); ch->WarpSet(x, y);
ch->Stop(); ch->Stop();
//군주 돈 삭감 //군주 돈 삭감
CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch);
//쿨타임 초기화 //쿨타임 초기화
ch->SetMC(CHARACTER::MI_WARP); ch->SetMC(CHARACTER::MI_WARP);
} }
@ -1577,17 +1577,17 @@ ACMD(do_monarch_transfer)
return; return;
} }
//군주 쿨타임 검사 //군주 쿨타임 검사
if (!ch->IsMCOK(CHARACTER::MI_TRANSFER)) if (!ch->IsMCOK(CHARACTER::MI_TRANSFER))
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d \xC3\xCA\xB0\xA3 \xC4\xF0\xC5\xB8\xC0\xD3\xC0\xCC \xC0\xFB\xBF\xEB\xC1\xDF\xC0\xD4\xB4\xCF\xB4\xD9."), ch->GetMCLTime(CHARACTER::MI_TRANSFER)); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d \xC3\xCA\xB0\xA3 \xC4\xF0\xC5\xB8\xC0\xD3\xC0\xCC \xC0\xFB\xBF\xEB\xC1\xDF\xC0\xD4\xB4\xCF\xB4\xD9."), ch->GetMCLTime(CHARACTER::MI_TRANSFER));
return; return;
} }
//군주 워프 비용 //군주 워프 비용
const int WarpPrice = 10000; const int WarpPrice = 10000;
//군주 국고 검사 //군주 국고 검사
if (!CMonarch::instance().IsMoneyOk(WarpPrice, ch->GetEmpire())) if (!CMonarch::instance().IsMoneyOk(WarpPrice, ch->GetEmpire()))
{ {
int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire());
@ -1635,9 +1635,9 @@ ACMD(do_monarch_transfer)
P2P_MANAGER::instance().Send(&pgg, sizeof(TPacketGGTransfer)); P2P_MANAGER::instance().Send(&pgg, sizeof(TPacketGGTransfer));
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s \xB4\xD4\xC0\xBB \xBC\xD2\xC8\xAF\xC7\xCF\xBF\xB4\xBD\xC0\xB4\xCF\xB4\xD9."), arg1); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s \xB4\xD4\xC0\xBB \xBC\xD2\xC8\xAF\xC7\xCF\xBF\xB4\xBD\xC0\xB4\xCF\xB4\xD9."), arg1);
//군주 돈 삭감 //군주 돈 삭감
CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch);
//쿨타임 초기화 //쿨타임 초기화
ch->SetMC(CHARACTER::MI_TRANSFER); ch->SetMC(CHARACTER::MI_TRANSFER);
} }
else else
@ -1674,9 +1674,9 @@ ACMD(do_monarch_transfer)
//tch->Show(ch->GetMapIndex(), ch->GetX(), ch->GetY(), ch->GetZ()); //tch->Show(ch->GetMapIndex(), ch->GetX(), ch->GetY(), ch->GetZ());
tch->WarpSet(ch->GetX(), ch->GetY(), ch->GetMapIndex()); tch->WarpSet(ch->GetX(), ch->GetY(), ch->GetMapIndex());
//군주 돈 삭감 //군주 돈 삭감
CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch);
//쿨타임 초기화 //쿨타임 초기화
ch->SetMC(CHARACTER::MI_TRANSFER); ch->SetMC(CHARACTER::MI_TRANSFER);
} }
@ -1766,14 +1766,14 @@ ACMD(do_monarch_tax)
return; return;
} }
// 군주 검사 // 군주 검사
if (!ch->IsMonarch()) if (!ch->IsMonarch())
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB1\xBA\xC1\xD6\xB8\xB8\xC0\xCC \xBB\xE7\xBF\xEB\xC7\xD2\xBC\xF6 \xC0\xD6\xB4\xC2 \xB1\xE2\xB4\xC9\xC0\xD4\xB4\xCF\xB4\xD9")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB1\xBA\xC1\xD6\xB8\xB8\xC0\xCC \xBB\xE7\xBF\xEB\xC7\xD2\xBC\xF6 \xC0\xD6\xB4\xC2 \xB1\xE2\xB4\xC9\xC0\xD4\xB4\xCF\xB4\xD9"));
return; return;
} }
// 세금설정 // 세금설정
int tax = 0; int tax = 0;
str_to_number(tax, arg1); str_to_number(tax, arg1);
@ -1782,10 +1782,10 @@ ACMD(do_monarch_tax)
quest::CQuestManager::instance().SetEventFlag("trade_tax", tax); quest::CQuestManager::instance().SetEventFlag("trade_tax", tax);
// 군주에게 메세지 하나 // 군주에게 메세지 하나
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xBC\xBC\xB1\xDD\xC0\xCC %d %\xB7\xCE \xBC\xB3\xC1\xA4\xB5\xC7\xBE\xFA\xBD\xC0\xB4\xCF\xB4\xD9")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xBC\xBC\xB1\xDD\xC0\xCC %d %\xB7\xCE \xBC\xB3\xC1\xA4\xB5\xC7\xBE\xFA\xBD\xC0\xB4\xCF\xB4\xD9"));
// 공지 // 공지
char szMsg[1024]; char szMsg[1024];
snprintf(szMsg, sizeof(szMsg), "\xB1\xBA\xC1\xD6\xC0\xC7 \xB8\xED\xC0\xB8\xB7\xCE \xBC\xBC\xB1\xDD\xC0\xCC %d %% \xB7\xCE \xBA\xAF\xB0\xE6\xB5\xC7\xBE\xFA\xBD\xC0\xB4\xCF\xB4\xD9", tax); snprintf(szMsg, sizeof(szMsg), "\xB1\xBA\xC1\xD6\xC0\xC7 \xB8\xED\xC0\xB8\xB7\xCE \xBC\xBC\xB1\xDD\xC0\xCC %d %% \xB7\xCE \xBA\xAF\xB0\xE6\xB5\xC7\xBE\xFA\xBD\xC0\xB4\xCF\xB4\xD9", tax);
@ -1794,32 +1794,32 @@ ACMD(do_monarch_tax)
snprintf(szMsg, sizeof(szMsg), "\xBE\xD5\xC0\xB8\xB7\xCE\xB4\xC2 \xB0\xC5\xB7\xA1 \xB1\xDD\xBE\xD7\xC0\xC7 %d %% \xB0\xA1 \xB1\xB9\xB0\xED\xB7\xCE \xB5\xE9\xBE\xEE\xB0\xA1\xB0\xD4\xB5\xCB\xB4\xCF\xB4\xD9.", tax); snprintf(szMsg, sizeof(szMsg), "\xBE\xD5\xC0\xB8\xB7\xCE\xB4\xC2 \xB0\xC5\xB7\xA1 \xB1\xDD\xBE\xD7\xC0\xC7 %d %% \xB0\xA1 \xB1\xB9\xB0\xED\xB7\xCE \xB5\xE9\xBE\xEE\xB0\xA1\xB0\xD4\xB5\xCB\xB4\xCF\xB4\xD9.", tax);
BroadcastNotice(szMsg); BroadcastNotice(szMsg);
// 쿨타임 초기화 // 쿨타임 초기화
ch->SetMC(CHARACTER::MI_TAX); ch->SetMC(CHARACTER::MI_TAX);
} }
static const DWORD cs_dwMonarchMobVnums[] = static const DWORD cs_dwMonarchMobVnums[] =
{ {
191, // 산견신 191, // 산견신
192, // 저신 192, // 저신
193, // 웅신 193, // 웅신
194, // 호신 194, // 호신
391, // 미정 391, // 미정
392, // 은정 392, // 은정
393, // 세랑 393, // 세랑
394, // 진희 394, // 진희
491, // 맹환 491, // 맹환
492, // 보우 492, // 보우
493, // 구패 493, // 구패
494, // 추흔 494, // 추흔
591, // 비류단대장 591, // 비류단대장
691, // 웅귀 족장 691, // 웅귀 족장
791, // 밀교교주 791, // 밀교교주
1304, // 누렁범귀 1304, // 누렁범귀
1901, // 구미호 1901, // 구미호
2091, // 여왕거미 2091, // 여왕거미
2191, // 거대사막거북 2191, // 거대사막거북
2206, // 화염왕i 2206, // 화염왕i
0, 0,
}; };
@ -1854,17 +1854,17 @@ ACMD(do_monarch_mob)
} }
} }
// 군주 몹 소환 비용 // 군주 몹 소환 비용
const int SummonPrice = 5000000; const int SummonPrice = 5000000;
// 군주 쿨타임 검사 // 군주 쿨타임 검사
if (!ch->IsMCOK(CHARACTER::MI_SUMMON)) if (!ch->IsMCOK(CHARACTER::MI_SUMMON))
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d \xC3\xCA\xB0\xA3 \xC4\xF0\xC5\xB8\xC0\xD3\xC0\xCC \xC0\xFB\xBF\xEB\xC1\xDF\xC0\xD4\xB4\xCF\xB4\xD9."), ch->GetMCLTime(CHARACTER::MI_SUMMON)); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d \xC3\xCA\xB0\xA3 \xC4\xF0\xC5\xB8\xC0\xD3\xC0\xCC \xC0\xFB\xBF\xEB\xC1\xDF\xC0\xD4\xB4\xCF\xB4\xD9."), ch->GetMCLTime(CHARACTER::MI_SUMMON));
return; return;
} }
// 군주 국고 검사 // 군주 국고 검사
if (!CMonarch::instance().IsMoneyOk(SummonPrice, ch->GetEmpire())) if (!CMonarch::instance().IsMoneyOk(SummonPrice, ch->GetEmpire()))
{ {
int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire());
@ -1892,7 +1892,7 @@ ACMD(do_monarch_mob)
DWORD count; DWORD count;
// 소환 가능 몹 검사 // 소환 가능 몹 검사
for (count = 0; cs_dwMonarchMobVnums[count] != 0; ++count) for (count = 0; cs_dwMonarchMobVnums[count] != 0; ++count)
if (cs_dwMonarchMobVnums[count] == vnum) if (cs_dwMonarchMobVnums[count] == vnum)
break; break;
@ -1915,10 +1915,10 @@ ACMD(do_monarch_mob)
if (tch) if (tch)
{ {
// 군주 돈 삭감 // 군주 돈 삭감
CMonarch::instance().SendtoDBDecMoney(SummonPrice, ch->GetEmpire(), ch); CMonarch::instance().SendtoDBDecMoney(SummonPrice, ch->GetEmpire(), ch);
// 쿨타임 초기화 // 쿨타임 초기화
ch->SetMC(CHARACTER::MI_SUMMON); ch->SetMC(CHARACTER::MI_SUMMON);
} }
} }
@ -2185,11 +2185,11 @@ ACMD(do_cube)
const std::string& strArg1 = std::string(arg1); const std::string& strArg1 = std::string(arg1);
// r_info (request information) // r_info (request information)
// /cube r_info ==> (Client -> Server) 현재 NPC가 만들 수 있는 레시피 요청 // /cube r_info ==> (Client -> Server) 현재 NPC가 만들 수 있는 레시피 요청
// (Server -> Client) /cube r_list npcVNUM resultCOUNT 123,1/125,1/128,1/130,5 // (Server -> Client) /cube r_list npcVNUM resultCOUNT 123,1/125,1/128,1/130,5
// //
// /cube r_info 3 ==> (Client -> Server) 현재 NPC가 만들수 있는 레시피 중 3번째 아이템을 만드는 데 필요한 정보를 요청 // /cube r_info 3 ==> (Client -> Server) 현재 NPC가 만들수 있는 레시피 중 3번째 아이템을 만드는 데 필요한 정보를 요청
// /cube r_info 3 5 ==> (Client -> Server) 현재 NPC가 만들수 있는 레시피 중 3번째 아이템부터 이후 5개의 아이템을 만드는 데 필요한 재료 정보를 요청 // /cube r_info 3 5 ==> (Client -> Server) 현재 NPC가 만들수 있는 레시피 중 3번째 아이템부터 이후 5개의 아이템을 만드는 데 필요한 재료 정보를 요청
// (Server -> Client) /cube m_info startIndex count 125,1|126,2|127,2|123,5&555,5&555,4/120000@125,1|126,2|127,2|123,5&555,5&555,4/120000 // (Server -> Client) /cube m_info startIndex count 125,1|126,2|127,2|123,5&555,5&555,4/120000@125,1|126,2|127,2|123,5&555,5&555,4/120000
// //
if (strArg1 == "r_info") if (strArg1 == "r_info")
@ -2278,7 +2278,7 @@ ACMD(do_in_game_mall)
return; return;
} }
// ㅠ_ㅠ 쾌도서버 아이템몰 URL 하드코딩 추가 // ㅠ_ㅠ 쾌도서버 아이템몰 URL 하드코딩 추가
if (true == LC_IsWE_Korea()) if (true == LC_IsWE_Korea())
{ {
ch->ChatPacket(CHAT_TYPE_COMMAND, "mall http://metin2.co.kr/50_we_mall/mall/login.htm"); ch->ChatPacket(CHAT_TYPE_COMMAND, "mall http://metin2.co.kr/50_we_mall/mall/login.htm");
@ -2354,7 +2354,7 @@ ACMD(do_in_game_mall)
} }
} }
// 주사위 // 주사위
ACMD(do_dice) ACMD(do_dice)
{ {
char arg1[256], arg2[256]; char arg1[256], arg2[256];
@ -2395,7 +2395,7 @@ ACMD(do_ride)
if (ch->IsDead() || ch->IsStun()) if (ch->IsDead() || ch->IsStun())
return; return;
// 내리기 // 내리기
{ {
if (ch->IsHorseRiding()) if (ch->IsHorseRiding())
{ {
@ -2412,7 +2412,7 @@ ACMD(do_ride)
} }
} }
// 타기 // 타기
{ {
if (ch->GetHorse() != NULL) if (ch->GetHorse() != NULL)
{ {
@ -2427,7 +2427,7 @@ ACMD(do_ride)
if (NULL == item) if (NULL == item)
continue; continue;
// 유니크 탈것 아이템 // 유니크 탈것 아이템
if (item->IsRideItem()) if (item->IsRideItem())
{ {
if (NULL==ch->GetWear(WEAR_UNIQUE1) || NULL==ch->GetWear(WEAR_UNIQUE2)) if (NULL==ch->GetWear(WEAR_UNIQUE1) || NULL==ch->GetWear(WEAR_UNIQUE2))
@ -2439,20 +2439,20 @@ ACMD(do_ride)
} }
} }
// 일반 탈것 아이템 // 일반 탈것 아이템
// TODO : 탈것용 SubType 추가 // TODO : 탈것용 SubType 추가
switch (item->GetVnum()) switch (item->GetVnum())
{ {
case 71114: // 저신이용권 case 71114: // 저신이용권
case 71116: // 산견신이용권 case 71116: // 산견신이용권
case 71118: // 투지범이용권 case 71118: // 투지범이용권
case 71120: // 사자왕이용권 case 71120: // 사자왕이용권
SPDLOG_TRACE("[DO_RIDE] USE QUEST ITEM"); SPDLOG_TRACE("[DO_RIDE] USE QUEST ITEM");
ch->UseItem(TItemPos (INVENTORY, i)); ch->UseItem(TItemPos (INVENTORY, i));
return; return;
} }
// GF mantis #113524, 52001~52090 번 탈것 // GF mantis #113524, 52001~52090 번 탈것
if( (item->GetVnum() > 52000) && (item->GetVnum() < 52091) ) { if( (item->GetVnum() > 52000) && (item->GetVnum() < 52091) ) {
SPDLOG_TRACE("[DO_RIDE] USE QUEST ITEM"); SPDLOG_TRACE("[DO_RIDE] USE QUEST ITEM");
ch->UseItem(TItemPos (INVENTORY, i)); ch->UseItem(TItemPos (INVENTORY, i));
@ -2462,7 +2462,7 @@ ACMD(do_ride)
} }
// 타거나 내릴 수 없을때 // 타거나 내릴 수 없을때
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB8\xBB\xC0\xBB \xB8\xD5\xC0\xFA \xBC\xD2\xC8\xAF\xC7\xD8\xC1\xD6\xBC\xBC\xBF\xE4.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB8\xBB\xC0\xBB \xB8\xD5\xC0\xFA \xBC\xD2\xC8\xAF\xC7\xD8\xC1\xD6\xBC\xBC\xBF\xE4."));
} }
@ -2533,7 +2533,7 @@ ACMD(do_enroll_sale)
} }
// temp_auction // temp_auction
// packet으로 통신하게 하고, 이건 삭제해야한다. // packet으로 통신하게 하고, 이건 삭제해야한다.
ACMD(do_get_auction_list) ACMD(do_get_auction_list)
{ {
char arg1[256]; char arg1[256];

View File

@ -337,12 +337,12 @@ bool CHARACTER_GoToName(LPCHARACTER ch, BYTE empire, int mapIndex, const char* g
{ "Three|\xBD\xC2\xB7\xE6\xB0\xEE", 2, 64, 2704, 7399 }, { "Three|\xBD\xC2\xB7\xE6\xB0\xEE", 2, 64, 2704, 7399 },
{ "Three|\xBD\xC2\xB7\xE6\xB0\xEE", 3, 64, 3213, 8080 }, { "Three|\xBD\xC2\xB7\xE6\xB0\xEE", 3, 64, 3213, 8080 },
// 밀교사원 // 밀교사원
{ "Milgyo|\xB9\xD0\xB1\xB3\xBB\xE7\xBF\xF8", 1, 65, 5536, 1436 }, { "Milgyo|\xB9\xD0\xB1\xB3\xBB\xE7\xBF\xF8", 1, 65, 5536, 1436 },
{ "Milgyo|\xB9\xD0\xB1\xB3\xBB\xE7\xBF\xF8", 2, 65, 5536, 1436 }, { "Milgyo|\xB9\xD0\xB1\xB3\xBB\xE7\xBF\xF8", 2, 65, 5536, 1436 },
{ "Milgyo|\xB9\xD0\xB1\xB3\xBB\xE7\xBF\xF8", 3, 65, 5536, 1436 }, { "Milgyo|\xB9\xD0\xB1\xB3\xBB\xE7\xBF\xF8", 3, 65, 5536, 1436 },
// 사귀타워입구 // 사귀타워입구
{ "\xBB\xE7\xB1\xCD\xC5\xB8\xBF\xF6\xC0\xD4\xB1\xB8", 1, 65, 5905, 1108 }, { "\xBB\xE7\xB1\xCD\xC5\xB8\xBF\xF6\xC0\xD4\xB1\xB8", 1, 65, 5905, 1108 },
{ "\xBB\xE7\xB1\xCD\xC5\xB8\xBF\xF6\xC0\xD4\xB1\xB8", 2, 65, 5905, 1108 }, { "\xBB\xE7\xB1\xCD\xC5\xB8\xBF\xF6\xC0\xD4\xB1\xB8", 2, 65, 5905, 1108 },
{ "\xBB\xE7\xB1\xCD\xC5\xB8\xBF\xF6\xC0\xD4\xB1\xB8", 3, 65, 5905, 1108 }, { "\xBB\xE7\xB1\xCD\xC5\xB8\xBF\xF6\xC0\xD4\xB1\xB8", 3, 65, 5905, 1108 },
@ -888,7 +888,7 @@ struct FuncPurge
int iDist = DISTANCE_APPROX(pkChr->GetX() - m_pkGM->GetX(), pkChr->GetY() - m_pkGM->GetY()); int iDist = DISTANCE_APPROX(pkChr->GetX() - m_pkGM->GetX(), pkChr->GetY() - m_pkGM->GetY());
if (!m_bAll && iDist >= 1000) // 10미터 이상에 있는 것들은 purge 하지 않는다. if (!m_bAll && iDist >= 1000) // 10미터 이상에 있는 것들은 purge 하지 않는다.
return; return;
SPDLOG_DEBUG("PURGE: {} {}", pkChr->GetName(), iDist); SPDLOG_DEBUG("PURGE: {} {}", pkChr->GetName(), iDist);
@ -1812,7 +1812,7 @@ LPCHARACTER chHori, chForge, chLib, chTemple, chTraining, chTree, chPortal, chBa
ACMD(do_b1) ACMD(do_b1)
{ {
//호리병 478 579 //호리병 478 579
chHori = CHARACTER_MANAGER::instance().SpawnMobRange(14017, ch->GetMapIndex(), 304222, 742858, 304222, 742858, true, false); chHori = CHARACTER_MANAGER::instance().SpawnMobRange(14017, ch->GetMapIndex(), 304222, 742858, 304222, 742858, true, false);
chHori->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_BUILDING_CONSTRUCTION_SMALL, 65535, 0, true); chHori->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_BUILDING_CONSTRUCTION_SMALL, 65535, 0, true);
chHori->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true); chHori->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
@ -1859,25 +1859,25 @@ ACMD(do_b2)
ACMD(do_b3) ACMD(do_b3)
{ {
// 포지 492 547 // 포지 492 547
chForge = CHARACTER_MANAGER::instance().SpawnMobRange(14003, ch->GetMapIndex(), 307500, 746300, 307500, 746300, true, false); chForge = CHARACTER_MANAGER::instance().SpawnMobRange(14003, ch->GetMapIndex(), 307500, 746300, 307500, 746300, true, false);
chForge->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true); chForge->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
//높은탑 509 589 -> 도서관 //높은탑 509 589 -> 도서관
chLib = CHARACTER_MANAGER::instance().SpawnMobRange(14007, ch->GetMapIndex(), 307900, 744500, 307900, 744500, true, false); chLib = CHARACTER_MANAGER::instance().SpawnMobRange(14007, ch->GetMapIndex(), 307900, 744500, 307900, 744500, true, false);
chLib->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true); chLib->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
//욕조 513 606 -> 힘의신전 //욕조 513 606 -> 힘의신전
chTemple = CHARACTER_MANAGER::instance().SpawnMobRange(14004, ch->GetMapIndex(), 307700, 741600, 307700, 741600, true, false); chTemple = CHARACTER_MANAGER::instance().SpawnMobRange(14004, ch->GetMapIndex(), 307700, 741600, 307700, 741600, true, false);
chTemple->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true); chTemple->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
//권투장 490 625 //권투장 490 625
chTraining= CHARACTER_MANAGER::instance().SpawnMobRange(14010, ch->GetMapIndex(), 307100, 739500, 307100, 739500, true, false); chTraining= CHARACTER_MANAGER::instance().SpawnMobRange(14010, ch->GetMapIndex(), 307100, 739500, 307100, 739500, true, false);
chTraining->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true); chTraining->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
//나무 466 614 //나무 466 614
chTree= CHARACTER_MANAGER::instance().SpawnMobRange(14013, ch->GetMapIndex(), 300800, 741600, 300800, 741600, true, false); chTree= CHARACTER_MANAGER::instance().SpawnMobRange(14013, ch->GetMapIndex(), 300800, 741600, 300800, 741600, true, false);
chTree->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true); chTree->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
//포탈 439 615 //포탈 439 615
chPortal= CHARACTER_MANAGER::instance().SpawnMobRange(14001, ch->GetMapIndex(), 300900, 744500, 300900, 744500, true, false); chPortal= CHARACTER_MANAGER::instance().SpawnMobRange(14001, ch->GetMapIndex(), 300900, 744500, 300900, 744500, true, false);
chPortal->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true); chPortal->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
// 구슬 436 600 // 구슬 436 600
chBall = CHARACTER_MANAGER::instance().SpawnMobRange(14012, ch->GetMapIndex(), 302500, 746600, 302500, 746600, true, false); chBall = CHARACTER_MANAGER::instance().SpawnMobRange(14012, ch->GetMapIndex(), 302500, 746600, 302500, 746600, true, false);
chBall->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true); chBall->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
} }
@ -2121,7 +2121,7 @@ ACMD(do_reload)
break; break;
//END_RELOAD_ADMIN //END_RELOAD_ADMIN
case 'c': // cube case 'c': // cube
// 로컬 프로세스만 갱산한다. // 로컬 프로세스만 갱산한다.
Cube_init (); Cube_init ();
break; break;
} }
@ -2245,7 +2245,7 @@ struct FuncWeaken
int iDist = DISTANCE_APPROX(pkChr->GetX() - m_pkGM->GetX(), pkChr->GetY() - m_pkGM->GetY()); int iDist = DISTANCE_APPROX(pkChr->GetX() - m_pkGM->GetX(), pkChr->GetY() - m_pkGM->GetY());
if (!m_bAll && iDist >= 1000) // 10미터 이상에 있는 것들은 purge 하지 않는다. if (!m_bAll && iDist >= 1000) // 10미터 이상에 있는 것들은 purge 하지 않는다.
return; return;
if (pkChr->IsNPC()) if (pkChr->IsNPC())
@ -2527,7 +2527,7 @@ ACMD(do_priv_empire)
if (duration < 0) if (duration < 0)
goto USAGE; goto USAGE;
// 시간 단위로 변경 // 시간 단위로 변경
duration = duration * (60*60); duration = duration * (60*60);
SPDLOG_DEBUG("_give_empire_privileage(empire={}, type={}, value={}, duration={}) by command", SPDLOG_DEBUG("_give_empire_privileage(empire={}, type={}, value={}, duration={}) by command",
@ -2631,7 +2631,7 @@ ACMD(do_xmas)
// BLOCK_CHAT // BLOCK_CHAT
ACMD(do_block_chat_list) ACMD(do_block_chat_list)
{ {
// GM이 아니거나 block_chat_privilege가 없는 사람은 명령어 사용 불가 // GM이 아니거나 block_chat_privilege가 없는 사람은 명령어 사용 불가
if (!ch || (ch->GetGMLevel() < GM_HIGH_WIZARD && ch->GetQuestFlag("chat_privilege.block") <= 0)) if (!ch || (ch->GetGMLevel() < GM_HIGH_WIZARD && ch->GetQuestFlag("chat_privilege.block") <= 0))
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB1\xD7\xB7\xB1 \xB8\xED\xB7\xC9\xBE\xEE\xB4\xC2 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB1\xD7\xB7\xB1 \xB8\xED\xB7\xC9\xBE\xEE\xB4\xC2 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9"));
@ -2697,7 +2697,7 @@ ACMD(do_vote_block_chat)
ACMD(do_block_chat) ACMD(do_block_chat)
{ {
// GM이 아니거나 block_chat_privilege가 없는 사람은 명령어 사용 불가 // GM이 아니거나 block_chat_privilege가 없는 사람은 명령어 사용 불가
if (ch && (ch->GetGMLevel() < GM_HIGH_WIZARD && ch->GetQuestFlag("chat_privilege.block") <= 0)) if (ch && (ch->GetGMLevel() < GM_HIGH_WIZARD && ch->GetQuestFlag("chat_privilege.block") <= 0))
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB1\xD7\xB7\xB1 \xB8\xED\xB7\xC9\xBE\xEE\xB4\xC2 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB1\xD7\xB7\xB1 \xB8\xED\xB7\xC9\xBE\xEE\xB4\xC2 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9"));
@ -2776,8 +2776,8 @@ ACMD(do_build)
CLand * pkLand = CManager::instance().FindLand(ch->GetMapIndex(), ch->GetX(), ch->GetY()); CLand * pkLand = CManager::instance().FindLand(ch->GetMapIndex(), ch->GetX(), ch->GetY());
// NOTE: 조건 체크들은 클라이언트와 서버가 함께 하기 때문에 문제가 있을 때는 // NOTE: 조건 체크들은 클라이언트와 서버가 함께 하기 때문에 문제가 있을 때는
// 메세지를 전송하지 않고 에러를 출력한다. // 메세지를 전송하지 않고 에러를 출력한다.
if (!pkLand) if (!pkLand)
{ {
SPDLOG_ERROR("{} trying to build on not buildable area.", ch->GetName()); SPDLOG_ERROR("{} trying to build on not buildable area.", ch->GetName());
@ -2790,17 +2790,17 @@ ACMD(do_build)
return; return;
} }
// 건설 권한 체크 // 건설 권한 체크
if (GMLevel == GM_PLAYER) if (GMLevel == GM_PLAYER)
{ {
// 플레이어가 집을 지을 때는 땅이 내껀지 확인해야 한다. // 플레이어가 집을 지을 때는 땅이 내껀지 확인해야 한다.
if ((!ch->GetGuild() || ch->GetGuild()->GetID() != pkLand->GetOwner())) if ((!ch->GetGuild() || ch->GetGuild()->GetID() != pkLand->GetOwner()))
{ {
SPDLOG_ERROR("{} trying to build on not owned land.", ch->GetName()); SPDLOG_ERROR("{} trying to build on not owned land.", ch->GetName());
return; return;
} }
// 내가 길마인가? // 내가 길마인가?
if (ch->GetGuild()->GetMasterPID() != ch->GetPlayerID()) if (ch->GetGuild()->GetMasterPID() != ch->GetPlayerID())
{ {
SPDLOG_ERROR("{} trying to build while not the guild master.", ch->GetName()); SPDLOG_ERROR("{} trying to build while not the guild master.", ch->GetName());
@ -2846,13 +2846,13 @@ ACMD(do_build)
} }
} }
// 건물 종속성 체크 (이 건물이 지어져 있어야함) // 건물 종속성 체크 (이 건물이 지어져 있어야함)
if (t->dwDependOnGroupVnum) if (t->dwDependOnGroupVnum)
{ {
// const TObjectProto * dependent = CManager::instance().GetObjectProto(dwVnum); // const TObjectProto * dependent = CManager::instance().GetObjectProto(dwVnum);
// if (dependent) // if (dependent)
{ {
// 지어져있는가? // 지어져있는가?
if (!pkLand->FindObjectByGroup(t->dwDependOnGroupVnum)) if (!pkLand->FindObjectByGroup(t->dwDependOnGroupVnum))
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB0\xC7\xBC\xB3\xBF\xA1 \xC7\xCA\xBF\xE4\xC7\xD1 \xB0\xC7\xB9\xB0\xC0\xCC \xC1\xF6\xBE\xEE\xC1\xAE \xC0\xD6\xC1\xF6 \xBE\xCA\xBD\xC0\xB4\xCF\xB4\xD9.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB0\xC7\xBC\xB3\xBF\xA1 \xC7\xCA\xBF\xE4\xC7\xD1 \xB0\xC7\xB9\xB0\xC0\xCC \xC1\xF6\xBE\xEE\xC1\xAE \xC0\xD6\xC1\xF6 \xBE\xCA\xBD\xC0\xB4\xCF\xB4\xD9."));
@ -2863,8 +2863,8 @@ ACMD(do_build)
if (test_server || GMLevel == GM_PLAYER) if (test_server || GMLevel == GM_PLAYER)
{ {
// GM이 아닐경우만 (테섭에서는 GM도 소모) // GM이 아닐경우만 (테섭에서는 GM도 소모)
// 건설 비용 체크 // 건설 비용 체크
if (t->dwPrice > BUILDING_MAX_PRICE) if (t->dwPrice > BUILDING_MAX_PRICE)
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB0\xC7\xB9\xB0 \xBA\xF1\xBF\xEB \xC1\xA4\xBA\xB8 \xC0\xCC\xBB\xF3\xC0\xB8\xB7\xCE \xB0\xC7\xBC\xB3 \xC0\xDB\xBE\xF7\xBF\xA1 \xBD\xC7\xC6\xD0\xC7\xDF\xBD\xC0\xB4\xCF\xB4\xD9.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB0\xC7\xB9\xB0 \xBA\xF1\xBF\xEB \xC1\xA4\xBA\xB8 \xC0\xCC\xBB\xF3\xC0\xB8\xB7\xCE \xB0\xC7\xBC\xB3 \xC0\xDB\xBE\xF7\xBF\xA1 \xBD\xC7\xC6\xD0\xC7\xDF\xBD\xC0\xB4\xCF\xB4\xD9."));
@ -2877,7 +2877,7 @@ ACMD(do_build)
return; return;
} }
// 아이템 자재 개수 체크 // 아이템 자재 개수 체크
int i; int i;
for (i = 0; i < OBJECT_MATERIAL_MAX_NUM; ++i) for (i = 0; i < OBJECT_MATERIAL_MAX_NUM; ++i)
@ -2899,7 +2899,7 @@ ACMD(do_build)
float x_rot = atof(arg4); float x_rot = atof(arg4);
float y_rot = atof(arg5); float y_rot = atof(arg5);
float z_rot = atof(arg6); float z_rot = atof(arg6);
// 20050811.myevan.건물 회전 기능 봉인 해제 // 20050811.myevan.건물 회전 기능 봉인 해제
/* /*
if (x_rot != 0.0f || y_rot != 0.0f || z_rot != 0.0f) if (x_rot != 0.0f || y_rot != 0.0f || z_rot != 0.0f)
{ {
@ -2929,12 +2929,12 @@ ACMD(do_build)
} }
if (test_server || GMLevel == GM_PLAYER) if (test_server || GMLevel == GM_PLAYER)
// 건설 재료 소모하기 (테섭에서는 GM도 소모) // 건설 재료 소모하기 (테섭에서는 GM도 소모)
{ {
// 건설 비용 소모 // 건설 비용 소모
ch->PointChange(POINT_GOLD, -t->dwPrice); ch->PointChange(POINT_GOLD, -t->dwPrice);
// 아이템 자재 사용하기 // 아이템 자재 사용하기
{ {
int i; int i;
for (i = 0; i < OBJECT_MATERIAL_MAX_NUM; ++i) for (i = 0; i < OBJECT_MATERIAL_MAX_NUM; ++i)
@ -3013,8 +3013,8 @@ ACMD(do_build)
break; break;
case 'W' : case 'W' :
// 담장 세우기 // 담장 세우기
// build (w)all 담장번호 담장크기 대문동 대문서 대문남 대문북 // build (w)all 담장번호 담장크기 대문동 대문서 대문남 대문북
if (GMLevel > GM_PLAYER) if (GMLevel > GM_PLAYER)
{ {
@ -3048,8 +3048,8 @@ ACMD(do_build)
break; break;
case 'E' : case 'E' :
// 담장 지우기 // 담장 지우기
// build (e)rase 담장셋ID // build (e)rase 담장셋ID
if (GMLevel > GM_PLAYER) if (GMLevel > GM_PLAYER)
{ {
one_argument(line, arg1, sizeof(arg1)); one_argument(line, arg1, sizeof(arg1));
@ -3323,7 +3323,7 @@ ACMD(do_duel)
if (!str_to_number(minute, szMinute)) if (!str_to_number(minute, szMinute))
{ {
// 캐나다는 기본 10분. // 캐나다는 기본 10분.
if (LC_IsCanada() == true) if (LC_IsCanada() == true)
{ {
minute = 10; minute = 10;
@ -3430,28 +3430,28 @@ ACMD(do_stat_plus_amount)
switch (subcmd) switch (subcmd)
{ {
case POINT_HT : // 체력 case POINT_HT : // 체력
if (nPoint + ch->GetPoint(POINT_HT) > 90) if (nPoint + ch->GetPoint(POINT_HT) > 90)
{ {
nPoint = 90 - ch->GetPoint(POINT_HT); nPoint = 90 - ch->GetPoint(POINT_HT);
} }
break; break;
case POINT_IQ : // 지능 case POINT_IQ : // 지능
if (nPoint + ch->GetPoint(POINT_IQ) > 90) if (nPoint + ch->GetPoint(POINT_IQ) > 90)
{ {
nPoint = 90 - ch->GetPoint(POINT_IQ); nPoint = 90 - ch->GetPoint(POINT_IQ);
} }
break; break;
case POINT_ST : // 근력 case POINT_ST : // 근력
if (nPoint + ch->GetPoint(POINT_ST) > 90) if (nPoint + ch->GetPoint(POINT_ST) > 90)
{ {
nPoint = 90 - ch->GetPoint(POINT_ST); nPoint = 90 - ch->GetPoint(POINT_ST);
} }
break; break;
case POINT_DX : // 민첩 case POINT_DX : // 민첩
if (nPoint + ch->GetPoint(POINT_DX) > 90) if (nPoint + ch->GetPoint(POINT_DX) > 90)
{ {
nPoint = 90 - ch->GetPoint(POINT_DX); nPoint = 90 - ch->GetPoint(POINT_DX);
@ -4208,8 +4208,8 @@ ACMD (do_attr_full_set)
case JOB_SURA: case JOB_SURA:
case JOB_SHAMAN: case JOB_SHAMAN:
{ {
// 무사 몸빵 셋팅. // 무사 몸빵 셋팅.
// 이것만 나와 있어서 임시로 모든 직군 다 이런 속성 따름. // 이것만 나와 있어서 임시로 모든 직군 다 이런 속성 따름.
item = ch->GetWear(WEAR_HEAD); item = ch->GetWear(WEAR_HEAD);
if (item != NULL) if (item != NULL)
{ {

View File

@ -102,17 +102,17 @@ int SPEEDHACK_LIMIT_COUNT = 50;
int SPEEDHACK_LIMIT_BONUS = 80; int SPEEDHACK_LIMIT_BONUS = 80;
int g_iSyncHackLimitCount = 20; // 10 -> 20 2013 09 11 CYH int g_iSyncHackLimitCount = 20; // 10 -> 20 2013 09 11 CYH
//<EFBFBD>þ<EFBFBD> = VIEW_RANGE + VIEW_BONUS_RANGE //시야 = VIEW_RANGE + VIEW_BONUS_RANGE
//VIEW_BONUSE_RANGE : Ŭ<EFBFBD><EFBFBD><EFBFBD>̾<EFBFBD>Ʈ<EFBFBD><EFBFBD> <20>þ<EFBFBD> ó<><C3B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>߻<EFBFBD><DFBB>Ҽ<EFBFBD><D2BC>־<EFBFBD> 500CM<43><4D> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>׻<EFBFBD><D7BB>ش<EFBFBD>. //VIEW_BONUSE_RANGE : 클라이언트와 시야 처리에서너무 딱 떨어질경우 문제가 발생할수있어 500CM의 여분을 항상준다.
int VIEW_RANGE = 5000; int VIEW_RANGE = 5000;
int VIEW_BONUS_RANGE = 500; int VIEW_BONUS_RANGE = 500;
int g_server_id = 0; int g_server_id = 0;
string g_strWebMallURL = "www.metin2.de"; string g_strWebMallURL = "www.metin2.de";
unsigned int g_uiSpamBlockDuration = 60 * 15; // <EFBFBD>⺻ 15<31><35> unsigned int g_uiSpamBlockDuration = 60 * 15; // 기본 15분
unsigned int g_uiSpamBlockScore = 100; // <EFBFBD>⺻ 100<30><30> unsigned int g_uiSpamBlockScore = 100; // 기본 100점
unsigned int g_uiSpamReloadCycle = 60 * 10; // <EFBFBD>⺻ 10<31><30> unsigned int g_uiSpamReloadCycle = 60 * 10; // 기본 10분
bool g_bCheckMultiHack = true; bool g_bCheckMultiHack = true;
@ -121,8 +121,8 @@ int g_iSpamBlockMaxLevel = 10;
void LoadStateUserCount(); void LoadStateUserCount();
void LoadValidCRCList(); void LoadValidCRCList();
bool LoadClientVersion(); bool LoadClientVersion();
bool g_protectNormalPlayer = false; // <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڰ<EFBFBD> "<22><>ȭ<EFBFBD><C8AD><EFBFBD>" <20><> <20>Ϲ<EFBFBD><CFB9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> bool g_protectNormalPlayer = false; // 범법자가 "평화모드" 인 일반유저를 공격하지 못함
bool g_noticeBattleZone = false; // <EFBFBD>߸<EFBFBD><EFBFBD><EFBFBD><EFBFBD>뿡 <20><><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD> <20>ȳ<EFBFBD><C8B3>޼<EFBFBD><DEBC><EFBFBD><EFBFBD><EFBFBD> <20>˷<EFBFBD><CBB7><EFBFBD> bool g_noticeBattleZone = false; // 중립지대에 입장하면 안내메세지를 알려줌
int gPlayerMaxLevel = 99; int gPlayerMaxLevel = 99;
@ -318,7 +318,7 @@ void config_init(const string& st_localeServiceName)
} }
char db_host[2][64], db_user[2][64], db_pwd[2][64], db_db[2][64]; char db_host[2][64], db_user[2][64], db_pwd[2][64], db_db[2][64];
// ... <EFBFBD><EFBFBD>... db_port<72><74> <20>̹<EFBFBD> <20>ִµ<D6B4>... <20><><EFBFBD>̹<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ؾ<EFBFBD><D8BE><EFBFBD>... // ... 아... db_port는 이미 있는데... 네이밍 어찌해야함...
int mysql_db_port[2]; int mysql_db_port[2];
for (int n = 0; n < 2; ++n) for (int n = 0; n < 2; ++n)
@ -339,9 +339,9 @@ void config_init(const string& st_localeServiceName)
*log_db = '\0'; *log_db = '\0';
// DB<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϱ<EFBFBD><CFB1><EFBFBD><EFBFBD>ؼ<EFBFBD><D8BC><EFBFBD> <20>ٸ<EFBFBD> <20><><EFBFBD>ð<EFBFBD><C3B0><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>Ǿ // DB에서 로케일정보를 세팅하기위해서는 다른 세팅값보다 선행되어서
// DB<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>о<EFBFBD><D0BE> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ٸ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѿ<EFBFBD><D1BE>Ѵ<EFBFBD>. // DB정보만 읽어와 로케일 세팅을 한후 다른 세팅을 적용시켜야한다.
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϰ<EFBFBD><CFB0>õ<EFBFBD> <20>ʱ<EFBFBD>ȭ <20><>ƾ<EFBFBD><C6BE> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϱ<EFBFBD> <20><><EFBFBD><EFBFBD>. // 이유는 로케일관련된 초기화 루틴이 곳곳에 존재하기 때문.
bool isCommonSQL = false; bool isCommonSQL = false;
bool isPlayerSQL = false; bool isPlayerSQL = false;
@ -477,7 +477,7 @@ void config_init(const string& st_localeServiceName)
} }
} }
//ó<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>. //처리가 끝났으니 파일을 닫자.
fclose(fpOnlyForDB); fclose(fpOnlyForDB);
// CONFIG_SQL_INFO_ERROR // CONFIG_SQL_INFO_ERROR
@ -503,7 +503,7 @@ void config_init(const string& st_localeServiceName)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Common DB <EFBFBD><EFBFBD> Locale <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ֱ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ؾ<EFBFBD> <20>Ѵ<EFBFBD>. // Common DB 가 Locale 정보를 가지고 있기 때문에 가장 먼저 접속해야 한다.
AccountDB::instance().Connect(db_host[1], mysql_db_port[1], db_user[1], db_pwd[1], db_db[1]); AccountDB::instance().Connect(db_host[1], mysql_db_port[1], db_user[1], db_pwd[1], db_db[1]);
if (false == AccountDB::instance().IsConnected()) if (false == AccountDB::instance().IsConnected())
@ -514,8 +514,8 @@ void config_init(const string& st_localeServiceName)
SPDLOG_INFO("CommonSQL connected"); SPDLOG_INFO("CommonSQL connected");
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 로케일 정보를 가져오자
// <<EFBFBD><EFBFBD><EFBFBD>> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ǹ<EFBFBD>(WHERE) <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. (<28>ٸ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20>ֽ<EFBFBD><D6BD>ϴ<EFBFBD>) // <경고> 쿼리문에 절대 조건문(WHERE) 달지 마세요. (다른 지역에서 문제가 생길수 있습니다)
{ {
char szQuery[512]; char szQuery[512];
snprintf(szQuery, sizeof(szQuery), "SELECT mKey, mValue FROM locale"); snprintf(szQuery, sizeof(szQuery), "SELECT mKey, mValue FROM locale");
@ -532,7 +532,7 @@ void config_init(const string& st_localeServiceName)
while (NULL != (row = mysql_fetch_row(pMsg->Get()->pSQLResult))) while (NULL != (row = mysql_fetch_row(pMsg->Get()->pSQLResult)))
{ {
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> // 로케일 세팅
if (strcasecmp(row[0], "LOCALE") == 0) if (strcasecmp(row[0], "LOCALE") == 0)
{ {
if (LocaleService_Init(row[1]) == false) if (LocaleService_Init(row[1]) == false)
@ -544,15 +544,15 @@ void config_init(const string& st_localeServiceName)
} }
} }
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> COMMON SQL<51><4C> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ش<EFBFBD>. // 로케일 정보를 COMMON SQL에 세팅해준다.
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> g_stLocale <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> LocaleService_Init() <20><><EFBFBD>ο<EFBFBD><CEBF><EFBFBD> <20><><EFBFBD>õȴ<C3B5>. // 참고로 g_stLocale 정보는 LocaleService_Init() 내부에서 세팅된다.
SPDLOG_INFO("Setting DB to locale {}", g_stLocale.c_str()); SPDLOG_INFO("Setting DB to locale {}", g_stLocale.c_str());
AccountDB::instance().SetLocale(g_stLocale); AccountDB::instance().SetLocale(g_stLocale);
AccountDB::instance().ConnectAsync(db_host[1], mysql_db_port[1], db_user[1], db_pwd[1], db_db[1], g_stLocale.c_str()); AccountDB::instance().ConnectAsync(db_host[1], mysql_db_port[1], db_user[1], db_pwd[1], db_db[1], g_stLocale.c_str());
// Player DB <EFBFBD><EFBFBD><EFBFBD><EFBFBD> // Player DB 접속
DBManager::instance().Connect(db_host[0], mysql_db_port[0], db_user[0], db_pwd[0], db_db[0]); DBManager::instance().Connect(db_host[0], mysql_db_port[0], db_user[0], db_pwd[0], db_db[0]);
if (!DBManager::instance().IsConnected()) if (!DBManager::instance().IsConnected())
@ -563,9 +563,9 @@ void config_init(const string& st_localeServiceName)
SPDLOG_INFO("PlayerSQL connected"); SPDLOG_INFO("PlayerSQL connected");
if (false == g_bAuthServer) // <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ƴ<EFBFBD> <20><><EFBFBD> if (false == g_bAuthServer) // 인증 서버가 아닐 경우
{ {
// Log DB <EFBFBD><EFBFBD><EFBFBD><EFBFBD> // Log DB 접속
LogManager::instance().Connect(log_host, log_port, log_user, log_pwd, log_db); LogManager::instance().Connect(log_host, log_port, log_user, log_pwd, log_db);
if (!LogManager::instance().IsConnected()) if (!LogManager::instance().IsConnected())
@ -580,8 +580,8 @@ void config_init(const string& st_localeServiceName)
} }
// SKILL_POWER_BY_LEVEL // SKILL_POWER_BY_LEVEL
// <EFBFBD><EFBFBD>Ʈ<EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>ؼ<EFBFBD> AccountDB::instance().SetLocale(g_stLocale) <20>ĺ<EFBFBD><C4BA><EFBFBD> <20>Ѵ<EFBFBD>. // 스트링 비교의 문제로 인해서 AccountDB::instance().SetLocale(g_stLocale) 후부터 한다.
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ȵȴ<C8B5>(<28>ؿܰ<D8BF> <20><><EFBFBD><EFBFBD>) // 물론 국내는 별로 문제가 안된다(해외가 문제)
{ {
char szQuery[256]; char szQuery[256];
snprintf(szQuery, sizeof(szQuery), "SELECT mValue FROM locale WHERE mKey='SKILL_POWER_BY_LEVEL'"); snprintf(szQuery, sizeof(szQuery), "SELECT mValue FROM locale WHERE mKey='SKILL_POWER_BY_LEVEL'");
@ -621,13 +621,13 @@ void config_init(const string& st_localeServiceName)
} }
} }
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ų <20><><EFBFBD><EFBFBD> // 종족별 스킬 세팅
for (int job = 0; job < JOB_MAX_NUM * 2; ++job) for (int job = 0; job < JOB_MAX_NUM * 2; ++job)
{ {
snprintf(szQuery, sizeof(szQuery), "SELECT mValue from locale where mKey='SKILL_POWER_BY_LEVEL_TYPE%d' ORDER BY CAST(mValue AS unsigned)", job); snprintf(szQuery, sizeof(szQuery), "SELECT mValue from locale where mKey='SKILL_POWER_BY_LEVEL_TYPE%d' ORDER BY CAST(mValue AS unsigned)", job);
std::unique_ptr<SQLMsg> pMsg(AccountDB::instance().DirectQuery(szQuery)); std::unique_ptr<SQLMsg> pMsg(AccountDB::instance().DirectQuery(szQuery));
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ȵǾ<C8B5><C7BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>⺻<EFBFBD><E2BABB><EFBFBD>̺<EFBFBD><CCBA><EFBFBD> <20><><EFBFBD><EFBFBD>Ѵ<EFBFBD>. // 세팅이 안되어있으면 기본테이블을 사용한다.
if (pMsg->Get()->uiNumRows == 0) if (pMsg->Get()->uiNumRows == 0)
{ {
CTableBySkill::instance().SetSkillPowerByLevelFromType(job, aiBaseSkillPowerByLevelTable); CTableBySkill::instance().SetSkillPowerByLevelFromType(job, aiBaseSkillPowerByLevelTable);
@ -1002,7 +1002,7 @@ void config_init(const string& st_localeServiceName)
TOKEN("spam_block_reload_cycle") TOKEN("spam_block_reload_cycle")
{ {
str_to_number(g_uiSpamReloadCycle, value_string); str_to_number(g_uiSpamReloadCycle, value_string);
g_uiSpamReloadCycle = std::max<int>(60, g_uiSpamReloadCycle); // <EFBFBD>ּ<EFBFBD> 1<><31> g_uiSpamReloadCycle = std::max<int>(60, g_uiSpamReloadCycle); // 최소 1분
} }
TOKEN("check_multihack") TOKEN("check_multihack")

View File

@ -14,7 +14,7 @@ TJobInitialPoints JobInitialPoints[JOB_MAX_NUM] =
} }
*/ */
{ {
// str con dex int 초기HP 초기SP CON/HP INT/SP HP랜덤/lv MP랜덤/lv 초기stam stam/con stam/lv // str con dex int 초기HP 초기SP CON/HP INT/SP HP랜덤/lv MP랜덤/lv 초기stam stam/con stam/lv
{ 6, 4, 3, 3, 600, 200, 40, 20, 36, 44, 18, 22, 800, 5, 1, 3 }, // JOB_WARRIOR 16 { 6, 4, 3, 3, 600, 200, 40, 20, 36, 44, 18, 22, 800, 5, 1, 3 }, // JOB_WARRIOR 16
{ 4, 3, 6, 3, 650, 200, 40, 20, 36, 44, 18, 22, 800, 5, 1, 3 }, // JOB_ASSASSIN 16 { 4, 3, 6, 3, 650, 200, 40, 20, 36, 44, 18, 22, 800, 5, 1, 3 }, // JOB_ASSASSIN 16
{ 5, 3, 3, 5, 650, 200, 40, 20, 36, 44, 18, 22, 800, 5, 1, 3 }, // JOB_SURA 16 { 5, 3, 3, 5, 650, 200, 40, 20, 36, 44, 18, 22, 800, 5, 1, 3 }, // JOB_SURA 16
@ -162,7 +162,7 @@ const DWORD exp_table_euckr[PLAYER_EXP_TABLE_MAX + 1] =
1676898443, 1676898443,
1844588288, 1844588288,
2029047116, 2029047116,
2100000000, // 99 99레벨일 때 필요경험치 (100레벨이 되기 위한) 2100000000, // 99 99레벨일 때 필요경험치 (100레벨이 되기 위한)
2100000000, // 100 2100000000, // 100
2100000000, 2100000000,
2100000000, 2100000000,
@ -287,7 +287,7 @@ const DWORD exp_table_common[PLAYER_EXP_TABLE_MAX + 1] =
1676898443, 1676898443,
1844588288, 1844588288,
2029047116, 2029047116,
2050000000, // 99레벨 일 때 필요경험치 (100레벨이 되기 위한) 2050000000, // 99레벨 일 때 필요경험치 (100레벨이 되기 위한)
2150000000, // 100 2150000000, // 100
2210000000, 2210000000,
2250000000, 2250000000,
@ -412,7 +412,7 @@ const DWORD exp_table_newcibn[PLAYER_EXP_TABLE_MAX + 1 ] =
2000000000, 2000000000,
2000000000, 2000000000,
2000000000, 2000000000,
2000000000, // 99 99레벨일 때 필요경험치 (100레벨이 되기 위한).. 현재 CIBN이 어떻게 운영하고 있는 지 모르니 신규 테이블을 쓰지 않고 기존값 계속 연장 유지 2000000000, // 99 99레벨일 때 필요경험치 (100레벨이 되기 위한).. 현재 CIBN이 어떻게 운영하고 있는 지 모르니 신규 테이블을 쓰지 않고 기존값 계속 연장 유지
2000000000, // 100 2000000000, // 100
2000000000, 2000000000,
2000000000, 2000000000,
@ -439,8 +439,8 @@ const DWORD exp_table_newcibn[PLAYER_EXP_TABLE_MAX + 1 ] =
const int * aiPercentByDeltaLev = NULL; const int * aiPercentByDeltaLev = NULL;
const int * aiPercentByDeltaLevForBoss = NULL; const int * aiPercentByDeltaLevForBoss = NULL;
// 적과 나와의 레벨차이에 의한 계산에 사용되는 테이블 // 적과 나와의 레벨차이에 의한 계산에 사용되는 테이블
// MIN(MAX_EXP_DELTA_OF_LEV - 1, (적렙 + 15) - 내렙)) // MIN(MAX_EXP_DELTA_OF_LEV - 1, (적렙 + 15) - 내렙))
const int aiPercentByDeltaLevForBoss_euckr[MAX_EXP_DELTA_OF_LEV] = const int aiPercentByDeltaLevForBoss_euckr[MAX_EXP_DELTA_OF_LEV] =
{ {
1, // -15 0 1, // -15 0
@ -720,7 +720,7 @@ const DWORD guild_exp_table[GUILD_MAX_LEVEL+1] =
42000000UL 42000000UL
}; };
// INTERNATIONAL_VERSION 길드경험치 // INTERNATIONAL_VERSION 길드경험치
const DWORD guild_exp_table2[GUILD_MAX_LEVEL+1] = const DWORD guild_exp_table2[GUILD_MAX_LEVEL+1] =
{ {
0, 0,
@ -745,7 +745,7 @@ const DWORD guild_exp_table2[GUILD_MAX_LEVEL+1] =
4000000UL, 4000000UL,
16800000UL 16800000UL
}; };
// END_OF_INTERNATIONAL_VERSION 길드경험치 // END_OF_INTERNATIONAL_VERSION 길드경험치
const int aiMobEnchantApplyIdx[MOB_ENCHANTS_MAX_NUM] = const int aiMobEnchantApplyIdx[MOB_ENCHANTS_MAX_NUM] =
{ {
@ -898,16 +898,16 @@ const TApplyInfo aApplyInfo[MAX_APPLY_NUM] =
{ POINT_PC_BANG_DROP_BONUS }, // 76 { POINT_PC_BANG_DROP_BONUS }, // 76
// END_PC_BANG_ITEM_ADD // END_PC_BANG_ITEM_ADD
{ POINT_NONE, }, // 77 사용시 HP 소모 APPLY_EXTRACT_HP_PCT { POINT_NONE, }, // 77 사용시 HP 소모 APPLY_EXTRACT_HP_PCT
{ POINT_RESIST_WARRIOR, }, // 78 무사에게 저항 APPLY_RESIST_WARRIOR { POINT_RESIST_WARRIOR, }, // 78 무사에게 저항 APPLY_RESIST_WARRIOR
{ POINT_RESIST_ASSASSIN, }, // 79 자객에게 저항 APPLY_RESIST_ASSASSIN { POINT_RESIST_ASSASSIN, }, // 79 자객에게 저항 APPLY_RESIST_ASSASSIN
{ POINT_RESIST_SURA, }, // 80 수라에게 저항 APPLY_RESIST_SURA { POINT_RESIST_SURA, }, // 80 수라에게 저항 APPLY_RESIST_SURA
{ POINT_RESIST_SHAMAN, }, // 81 무당에게 저항 APPLY_RESIST_SHAMAN { POINT_RESIST_SHAMAN, }, // 81 무당에게 저항 APPLY_RESIST_SHAMAN
{ POINT_ENERGY }, // 82 기력 { POINT_ENERGY }, // 82 기력
{ POINT_DEF_GRADE }, // 83 방어력. DEF_GRADE_BONUS는 클라에서 두배로 보여지는 의도된 버그(...)가 있다. { POINT_DEF_GRADE }, // 83 방어력. DEF_GRADE_BONUS는 클라에서 두배로 보여지는 의도된 버그(...)가 있다.
{ POINT_COSTUME_ATTR_BONUS }, // 84 코스튬에 붙은 속성에 대해서만 보너스를 주는 기력 { POINT_COSTUME_ATTR_BONUS }, // 84 코스튬에 붙은 속성에 대해서만 보너스를 주는 기력
{ POINT_MAGIC_ATT_BONUS_PER }, // 85 마법 공격력 +x% { POINT_MAGIC_ATT_BONUS_PER }, // 85 마법 공격력 +x%
{ POINT_MELEE_MAGIC_ATT_BONUS_PER }, // 86 APPLY_MELEE_MAGIC_ATTBONUS_PER { POINT_MELEE_MAGIC_ATT_BONUS_PER }, // 86 APPLY_MELEE_MAGIC_ATTBONUS_PER
{ POINT_RESIST_ICE, }, // APPLY_RESIST_ICE, 87 { POINT_RESIST_ICE, }, // APPLY_RESIST_ICE, 87
{ POINT_RESIST_EARTH, }, // APPLY_RESIST_EARTH, 88 { POINT_RESIST_EARTH, }, // APPLY_RESIST_EARTH, 88
@ -1153,28 +1153,28 @@ TGuildWarInfo KOR_aGuildWarInfo[GUILD_WAR_TYPE_MAX_NUM] =
}; };
// //
// 악세서리 소켓용 수치들 // 악세서리 소켓용 수치들
// //
// 다이아몬드로 소켓을 추가할 때 확률 // 다이아몬드로 소켓을 추가할 때 확률
const int aiAccessorySocketAddPct[ITEM_ACCESSORY_SOCKET_MAX_NUM] = const int aiAccessorySocketAddPct[ITEM_ACCESSORY_SOCKET_MAX_NUM] =
{ {
50, 50, 50 50, 50, 50
}; };
// 악세서리 수치 값의 몇%만큼의 성능을 추가하는지 // 악세서리 수치 값의 몇%만큼의 성능을 추가하는지
const int aiAccessorySocketEffectivePct[ITEM_ACCESSORY_SOCKET_MAX_NUM + 1] = const int aiAccessorySocketEffectivePct[ITEM_ACCESSORY_SOCKET_MAX_NUM + 1] =
{ {
0, 10, 20, 40 0, 10, 20, 40
}; };
// 소켓 지속시간 24, 12, 6 // 소켓 지속시간 24, 12, 6
const int aiAccessorySocketDegradeTime[ITEM_ACCESSORY_SOCKET_MAX_NUM + 1] = const int aiAccessorySocketDegradeTime[ITEM_ACCESSORY_SOCKET_MAX_NUM + 1] =
{ {
0, 3600 * 24, 3600 * 12, 3600 * 6 0, 3600 * 24, 3600 * 12, 3600 * 6
}; };
// 소켓 장착 성공률 // 소켓 장착 성공률
const int aiAccessorySocketPutPct[ITEM_ACCESSORY_SOCKET_MAX_NUM + 1] = const int aiAccessorySocketPutPct[ITEM_ACCESSORY_SOCKET_MAX_NUM + 1] =
{ {
90, 80, 70, 0 90, 80, 70, 0
@ -1274,10 +1274,10 @@ TValueName c_aApplyTypeNames[] =
{ "RESIST_ASSASSIN", APPLY_RESIST_ASSASSIN}, { "RESIST_ASSASSIN", APPLY_RESIST_ASSASSIN},
{ "RESIST_SURA", APPLY_RESIST_SURA}, { "RESIST_SURA", APPLY_RESIST_SURA},
{ "RESIST_SHAMAN", APPLY_RESIST_SHAMAN}, { "RESIST_SHAMAN", APPLY_RESIST_SHAMAN},
// by mhh game/affect.h 정의되어있음. INFINITE_AFFECT_DURATION = 0x1FFFFFFF // by mhh game/affect.h 정의되어있음. INFINITE_AFFECT_DURATION = 0x1FFFFFFF
{ "INFINITE_AFFECT_DURATION", 0x1FFFFFFF }, { "INFINITE_AFFECT_DURATION", 0x1FFFFFFF },
{ "ENERGY", APPLY_ENERGY }, // 기력 { "ENERGY", APPLY_ENERGY }, // 기력
{ "COSTUME_ATTR_BONUS", APPLY_COSTUME_ATTR_BONUS }, // 기력 { "COSTUME_ATTR_BONUS", APPLY_COSTUME_ATTR_BONUS }, // 기력
{ "MAGIC_ATTBONUS_PER", APPLY_MAGIC_ATTBONUS_PER }, { "MAGIC_ATTBONUS_PER", APPLY_MAGIC_ATTBONUS_PER },
{ "MELEE_MAGIC_ATTBONUS_PER", APPLY_MELEE_MAGIC_ATTBONUS_PER }, { "MELEE_MAGIC_ATTBONUS_PER", APPLY_MELEE_MAGIC_ATTBONUS_PER },

View File

@ -37,11 +37,11 @@ static bool s_isInitializedCubeMaterialInformation = false;
/*--------------------------------------------------------*/ /*--------------------------------------------------------*/
enum ECubeResultCategory enum ECubeResultCategory
{ {
CUBE_CATEGORY_POTION, // 약초, 진액 등등.. (포션으로 특정할 수 없으니 사용 안 함. 약초같은건 다 걍 기타) CUBE_CATEGORY_POTION, // 약초, 진액 등등.. (포션으로 특정할 수 없으니 사용 안 함. 약초같은건 다 걍 기타)
CUBE_CATEGORY_WEAPON, // 무기 CUBE_CATEGORY_WEAPON, // 무기
CUBE_CATEGORY_ARMOR, // 방어구 CUBE_CATEGORY_ARMOR, // 방어구
CUBE_CATEGORY_ACCESSORY, // 장신구 CUBE_CATEGORY_ACCESSORY, // 장신구
CUBE_CATEGORY_ETC, // 기타 등등... CUBE_CATEGORY_ETC, // 기타 등등...
}; };
typedef std::vector<CUBE_VALUE> TCubeValueVector; typedef std::vector<CUBE_VALUE> TCubeValueVector;
@ -53,12 +53,12 @@ struct SCubeMaterialInfo
bHaveComplicateMaterial = false; bHaveComplicateMaterial = false;
}; };
CUBE_VALUE reward; // 보상이 뭐냐 CUBE_VALUE reward; // 보상이 뭐냐
TCubeValueVector material; // 재료들은 뭐냐 TCubeValueVector material; // 재료들은 뭐냐
DWORD gold; // 돈은 얼마드냐 DWORD gold; // 돈은 얼마드냐
TCubeValueVector complicateMaterial; // 복잡한-_- 재료들 TCubeValueVector complicateMaterial; // 복잡한-_- 재료들
// .. 클라이언트에서 재료를 보여주기 위하여 약속한 포맷 // .. 클라이언트에서 재료를 보여주기 위하여 약속한 포맷
// 72723,1&72724,2&72730,1 // 72723,1&72724,2&72730,1
// 52001,1|52002,1|52003,1&72723,1&72724,5 // 52001,1|52002,1|52003,1&72723,1&72724,5
// => ( 52001,1 or 52002,1 or 52003,1 ) and 72723,1 and 72724,5 // => ( 52001,1 or 52002,1 or 52003,1 ) and 72723,1 and 72724,5
@ -75,13 +75,13 @@ struct SItemNameAndLevel
}; };
// 자료구조나 이런거 병신인건 이해좀... 누구땜에 영혼이 없는 상태에서 만들었씀 // 자료구조나 이런거 병신인건 이해좀... 누구땜에 영혼이 없는 상태에서 만들었씀
typedef std::vector<SCubeMaterialInfo> TCubeResultList; typedef std::vector<SCubeMaterialInfo> TCubeResultList;
typedef std::unordered_map<DWORD, TCubeResultList> TCubeMapByNPC; // 각각의 NPC별로 어떤 걸 만들 수 있고 재료가 뭔지... typedef std::unordered_map<DWORD, TCubeResultList> TCubeMapByNPC; // 각각의 NPC별로 어떤 걸 만들 수 있고 재료가 뭔지...
typedef std::unordered_map<DWORD, std::string> TCubeResultInfoTextByNPC; // 각각의 NPC별로 만들 수 있는 목록을 정해진 포맷으로 정리한 정보 typedef std::unordered_map<DWORD, std::string> TCubeResultInfoTextByNPC; // 각각의 NPC별로 만들 수 있는 목록을 정해진 포맷으로 정리한 정보
TCubeMapByNPC cube_info_map; TCubeMapByNPC cube_info_map;
TCubeResultInfoTextByNPC cube_result_info_map_by_npc; // 네이밍 존나 병신같다 ㅋㅋㅋ TCubeResultInfoTextByNPC cube_result_info_map_by_npc; // 네이밍 존나 병신같다 ㅋㅋㅋ
class CCubeMaterialInfoHelper class CCubeMaterialInfoHelper
{ {
@ -92,7 +92,7 @@ public:
/*--------------------------------------------------------*/ /*--------------------------------------------------------*/
/* STATIC FUNCTIONS */ /* STATIC FUNCTIONS */
/*--------------------------------------------------------*/ /*--------------------------------------------------------*/
// 필요한 아이템 개수를 가지고있는가? // 필요한 아이템 개수를 가지고있는가?
static bool FN_check_item_count (LPITEM *items, DWORD item_vnum, int need_count) static bool FN_check_item_count (LPITEM *items, DWORD item_vnum, int need_count)
{ {
int count = 0; int count = 0;
@ -111,7 +111,7 @@ static bool FN_check_item_count (LPITEM *items, DWORD item_vnum, int need_count)
return (count>=need_count); return (count>=need_count);
} }
// 큐브내의 재료를 지운다. // 큐브내의 재료를 지운다.
static void FN_remove_material (LPITEM *items, DWORD item_vnum, int need_count) static void FN_remove_material (LPITEM *items, DWORD item_vnum, int need_count)
{ {
int count = 0; int count = 0;
@ -170,7 +170,7 @@ static bool FN_check_valid_npc( WORD vnum )
return false; return false;
} }
// 큐브데이타가 올바르게 초기화 되었는지 체크한다. // 큐브데이타가 올바르게 초기화 되었는지 체크한다.
static bool FN_check_cube_data (CUBE_DATA *cube_data) static bool FN_check_cube_data (CUBE_DATA *cube_data)
{ {
DWORD i = 0; DWORD i = 0;
@ -204,10 +204,10 @@ CUBE_DATA::CUBE_DATA()
this->gold = 0; this->gold = 0;
} }
// 필요한 재료의 수량을 만족하는지 체크한다. // 필요한 재료의 수량을 만족하는지 체크한다.
bool CUBE_DATA::can_make_item (LPITEM *items, WORD npc_vnum) bool CUBE_DATA::can_make_item (LPITEM *items, WORD npc_vnum)
{ {
// 필요한 재료, 수량을 만족하는지 체크한다. // 필요한 재료, 수량을 만족하는지 체크한다.
DWORD i, end_index; DWORD i, end_index;
DWORD need_vnum; DWORD need_vnum;
int need_count; int need_count;
@ -235,7 +235,7 @@ bool CUBE_DATA::can_make_item (LPITEM *items, WORD npc_vnum)
return true; return true;
} }
// 큐브를 돌렸을때 나오는 아이템의 종류를 결정함 // 큐브를 돌렸을때 나오는 아이템의 종류를 결정함
CUBE_VALUE* CUBE_DATA::reward_value () CUBE_VALUE* CUBE_DATA::reward_value ()
{ {
int end_index = 0; int end_index = 0;
@ -248,7 +248,7 @@ CUBE_VALUE* CUBE_DATA::reward_value ()
return &this->reward[reward_index]; return &this->reward[reward_index];
} }
// 큐브에 들어있는 재료를 지운다 // 큐브에 들어있는 재료를 지운다
void CUBE_DATA::remove_material (LPCHARACTER ch) void CUBE_DATA::remove_material (LPCHARACTER ch)
{ {
DWORD i, end_index; DWORD i, end_index;
@ -281,7 +281,7 @@ void Cube_clean_item (LPCHARACTER ch)
} }
} }
// 큐브창 열기 // 큐브창 열기
void Cube_open (LPCHARACTER ch) void Cube_open (LPCHARACTER ch)
{ {
if (false == s_isInitializedCubeMaterialInformation) if (false == s_isInitializedCubeMaterialInformation)
@ -331,7 +331,7 @@ void Cube_open (LPCHARACTER ch)
ch->ChatPacket(CHAT_TYPE_COMMAND, "cube open %d", npc->GetRaceNum()); ch->ChatPacket(CHAT_TYPE_COMMAND, "cube open %d", npc->GetRaceNum());
} }
// 큐브 캔슬 // 큐브 캔슬
void Cube_close (LPCHARACTER ch) void Cube_close (LPCHARACTER ch)
{ {
RETURN_IF_CUBE_IS_NOT_OPENED(ch); RETURN_IF_CUBE_IS_NOT_OPENED(ch);
@ -426,7 +426,7 @@ bool Cube_load (const char *file)
} }
else TOKEN("gold") else TOKEN("gold")
{ {
// 제조에 필요한 금액 // 제조에 필요한 금액
cube_data->gold = value1; cube_data->gold = value1;
} }
else TOKEN("end") else TOKEN("end")
@ -504,10 +504,10 @@ static bool FN_update_cube_status(LPCHARACTER ch)
// return new item // return new item
bool Cube_make (LPCHARACTER ch) bool Cube_make (LPCHARACTER ch)
{ {
// 주어진 아이템을 필요로하는 조합을 찾는다. (큐브데이타로 칭함) // 주어진 아이템을 필요로하는 조합을 찾는다. (큐브데이타로 칭함)
// 큐브 데이타가 있다면 아이템의 재료를 체크한다. // 큐브 데이타가 있다면 아이템의 재료를 체크한다.
// 새로운 아이템을 만든다. // 새로운 아이템을 만든다.
// 새로운 아이템 지급 // 새로운 아이템 지급
LPCHARACTER npc; LPCHARACTER npc;
int percent_number = 0; int percent_number = 0;
@ -538,23 +538,23 @@ bool Cube_make (LPCHARACTER ch)
if (ch->GetGold() < cube_proto->gold) if (ch->GetGold() < cube_proto->gold)
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB5\xB7\xC0\xCC \xBA\xCE\xC1\xB7\xC7\xCF\xB0\xC5\xB3\xAA \xBE\xC6\xC0\xCC\xC5\xDB\xC0\xCC \xC1\xA6\xC0\xDA\xB8\xAE\xBF\xA1 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9.")); // 이 텍스트는 이미 널리 쓰이는거라 추가번역 필요 없음 ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB5\xB7\xC0\xCC \xBA\xCE\xC1\xB7\xC7\xCF\xB0\xC5\xB3\xAA \xBE\xC6\xC0\xCC\xC5\xDB\xC0\xCC \xC1\xA6\xC0\xDA\xB8\xAE\xBF\xA1 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9.")); // 이 텍스트는 이미 널리 쓰이는거라 추가번역 필요 없음
return false; return false;
} }
CUBE_VALUE *reward_value = cube_proto->reward_value(); CUBE_VALUE *reward_value = cube_proto->reward_value();
// 사용되었던 재료아이템 삭제 // 사용되었던 재료아이템 삭제
cube_proto->remove_material (ch); cube_proto->remove_material (ch);
// 제조시 필요한 골드 차감 // 제조시 필요한 골드 차감
if (0 < cube_proto->gold) if (0 < cube_proto->gold)
ch->PointChange(POINT_GOLD, -(cube_proto->gold), false); ch->PointChange(POINT_GOLD, -(cube_proto->gold), false);
percent_number = Random::get(1,100); percent_number = Random::get(1,100);
if ( percent_number<=cube_proto->percent) if ( percent_number<=cube_proto->percent)
{ {
// 성공 // 성공
ch->ChatPacket(CHAT_TYPE_COMMAND, "cube success %d %d", reward_value->vnum, reward_value->count); ch->ChatPacket(CHAT_TYPE_COMMAND, "cube success %d %d", reward_value->vnum, reward_value->count);
new_item = ch->AutoGiveItem(reward_value->vnum, reward_value->count); new_item = ch->AutoGiveItem(reward_value->vnum, reward_value->count);
@ -564,8 +564,8 @@ bool Cube_make (LPCHARACTER ch)
} }
else else
{ {
// 실패 // 실패
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xC1\xA6\xC1\xB6\xBF\xA1 \xBD\xC7\xC6\xD0\xC7\xCF\xBF\xB4\xBD\xC0\xB4\xCF\xB4\xD9.")); // 2012.11.12 새로 추가된 메세지 (locale_string.txt 에 추가해야 함) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xC1\xA6\xC1\xB6\xBF\xA1 \xBD\xC7\xC6\xD0\xC7\xCF\xBF\xB4\xBD\xC0\xB4\xCF\xB4\xD9.")); // 2012.11.12 새로 추가된 메세지 (locale_string.txt 에 추가해야 함)
ch->ChatPacket(CHAT_TYPE_COMMAND, "cube fail"); ch->ChatPacket(CHAT_TYPE_COMMAND, "cube fail");
LogManager::instance().CubeLog(ch->GetPlayerID(), ch->GetX(), ch->GetY(), LogManager::instance().CubeLog(ch->GetPlayerID(), ch->GetX(), ch->GetY(),
reward_value->vnum, 0, 0, 0); reward_value->vnum, 0, 0, 0);
@ -576,7 +576,7 @@ bool Cube_make (LPCHARACTER ch)
} }
// 큐브에 있는 아이템들을 표시 // 큐브에 있는 아이템들을 표시
void Cube_show_list (LPCHARACTER ch) void Cube_show_list (LPCHARACTER ch)
{ {
LPITEM *cube_item; LPITEM *cube_item;
@ -597,13 +597,13 @@ void Cube_show_list (LPCHARACTER ch)
} }
// 인벤토리에 있는 아이템을 큐브에 등록 // 인벤토리에 있는 아이템을 큐브에 등록
void Cube_add_item (LPCHARACTER ch, int cube_index, int inven_index) void Cube_add_item (LPCHARACTER ch, int cube_index, int inven_index)
{ {
// 아이템이 있는가? // 아이템이 있는가?
// 큐브내의 빈자리 찾기 // 큐브내의 빈자리 찾기
// 큐브세팅 // 큐브세팅
// 메시지 전송 // 메시지 전송
LPITEM item; LPITEM item;
LPITEM *cube_item; LPITEM *cube_item;
@ -620,7 +620,7 @@ void Cube_add_item (LPCHARACTER ch, int cube_index, int inven_index)
cube_item = ch->GetCubeItem(); cube_item = ch->GetCubeItem();
// 이미 다른위치에 등록되었던 아이템이면 기존 indext삭제 // 이미 다른위치에 등록되었던 아이템이면 기존 indext삭제
for (int i=0; i<CUBE_MAX_NUM; ++i) for (int i=0; i<CUBE_MAX_NUM; ++i)
{ {
if (item==cube_item[i]) if (item==cube_item[i])
@ -636,14 +636,14 @@ void Cube_add_item (LPCHARACTER ch, int cube_index, int inven_index)
ch->ChatPacket(CHAT_TYPE_INFO, "cube[%d]: inventory[%d]: %s added", ch->ChatPacket(CHAT_TYPE_INFO, "cube[%d]: inventory[%d]: %s added",
cube_index, inven_index, item->GetName()); cube_index, inven_index, item->GetName());
// 현재 상자에 올라온 아이템들로 무엇을 만들 수 있는지 클라이언트에 정보 전달 // 현재 상자에 올라온 아이템들로 무엇을 만들 수 있는지 클라이언트에 정보 전달
// 을 하고싶었으나 그냥 필요한 골드가 얼마인지 전달 // 을 하고싶었으나 그냥 필요한 골드가 얼마인지 전달
FN_update_cube_status(ch); FN_update_cube_status(ch);
return; return;
} }
// 큐브에있는 아이템을 제거 // 큐브에있는 아이템을 제거
void Cube_delete_item (LPCHARACTER ch, int cube_index) void Cube_delete_item (LPCHARACTER ch, int cube_index)
{ {
LPITEM item; LPITEM item;
@ -664,14 +664,14 @@ void Cube_delete_item (LPCHARACTER ch, int cube_index)
ch->ChatPacket(CHAT_TYPE_INFO, "cube[%d]: cube[%d]: %s deleted", ch->ChatPacket(CHAT_TYPE_INFO, "cube[%d]: cube[%d]: %s deleted",
cube_index, item->GetCell(), item->GetName()); cube_index, item->GetCell(), item->GetName());
// 현재 상자에 올라온 아이템들로 무엇을 만들 수 있는지 클라이언트에 정보 전달 // 현재 상자에 올라온 아이템들로 무엇을 만들 수 있는지 클라이언트에 정보 전달
// 을 하고싶었으나 그냥 필요한 골드가 얼마인지 전달 // 을 하고싶었으나 그냥 필요한 골드가 얼마인지 전달
FN_update_cube_status(ch); FN_update_cube_status(ch);
return; return;
} }
// 아이템 이름을 통해서 순수 이름과 강화레벨을 분리하는 함수 (무쌍검+5 -> 무쌍검, 5) // 아이템 이름을 통해서 순수 이름과 강화레벨을 분리하는 함수 (무쌍검+5 -> 무쌍검, 5)
SItemNameAndLevel SplitItemNameAndLevelFromName(const std::string& name) SItemNameAndLevel SplitItemNameAndLevelFromName(const std::string& name)
{ {
int level = 0; int level = 0;
@ -705,7 +705,7 @@ bool FIsLessCubeValue(const CUBE_VALUE& a, const CUBE_VALUE& b)
void Cube_MakeCubeInformationText() void Cube_MakeCubeInformationText()
{ {
// 이제 정리된 큐브 결과 및 재료들의 정보로 클라이언트에 보내 줄 정보로 변환함. // 이제 정리된 큐브 결과 및 재료들의 정보로 클라이언트에 보내 줄 정보로 변환함.
for (TCubeMapByNPC::iterator iter = cube_info_map.begin(); cube_info_map.end() != iter; ++iter) for (TCubeMapByNPC::iterator iter = cube_info_map.begin(); cube_info_map.end() != iter; ++iter)
{ {
const DWORD& npcVNUM = iter->first; const DWORD& npcVNUM = iter->first;
@ -717,13 +717,13 @@ void Cube_MakeCubeInformationText()
std::string& infoText = materialInfo.infoText; std::string& infoText = materialInfo.infoText;
// 이놈이 나쁜놈이야 // 이놈이 나쁜놈이야
if (0 < materialInfo.complicateMaterial.size()) if (0 < materialInfo.complicateMaterial.size())
{ {
std::sort(materialInfo.complicateMaterial.begin(), materialInfo.complicateMaterial.end(), FIsLessCubeValue); std::sort(materialInfo.complicateMaterial.begin(), materialInfo.complicateMaterial.end(), FIsLessCubeValue);
std::sort(materialInfo.material.begin(), materialInfo.material.end(), FIsLessCubeValue); std::sort(materialInfo.material.begin(), materialInfo.material.end(), FIsLessCubeValue);
//// 중복되는 재료들을 지움 //// 중복되는 재료들을 지움
for (TCubeValueVector::iterator iter = materialInfo.complicateMaterial.begin(); materialInfo.complicateMaterial.end() != iter; ++iter) for (TCubeValueVector::iterator iter = materialInfo.complicateMaterial.begin(); materialInfo.complicateMaterial.end() != iter; ++iter)
{ {
for (TCubeValueVector::iterator targetIter = materialInfo.material.begin(); materialInfo.material.end() != targetIter; ++targetIter) for (TCubeValueVector::iterator targetIter = materialInfo.material.begin(); materialInfo.material.end() != targetIter; ++targetIter)
@ -735,7 +735,7 @@ void Cube_MakeCubeInformationText()
} }
} }
// 72723,1 or 72725,1 or ... 이런 식의 약속된 포맷을 지키는 텍스트를 생성 // 72723,1 or 72725,1 or ... 이런 식의 약속된 포맷을 지키는 텍스트를 생성
for (TCubeValueVector::iterator iter = materialInfo.complicateMaterial.begin(); materialInfo.complicateMaterial.end() != iter; ++iter) for (TCubeValueVector::iterator iter = materialInfo.complicateMaterial.begin(); materialInfo.complicateMaterial.end() != iter; ++iter)
{ {
char tempBuffer[128]; char tempBuffer[128];
@ -750,7 +750,7 @@ void Cube_MakeCubeInformationText()
infoText.push_back('&'); infoText.push_back('&');
} }
// 중복되지 않는 일반 재료들도 포맷 생성 // 중복되지 않는 일반 재료들도 포맷 생성
for (TCubeValueVector::iterator iter = materialInfo.material.begin(); materialInfo.material.end() != iter; ++iter) for (TCubeValueVector::iterator iter = materialInfo.material.begin(); materialInfo.material.end() != iter; ++iter)
{ {
char tempBuffer[128]; char tempBuffer[128];
@ -760,7 +760,7 @@ void Cube_MakeCubeInformationText()
infoText.erase(infoText.size() - 1); infoText.erase(infoText.size() - 1);
// 만들 때 골드가 필요하다면 골드정보 추가 // 만들 때 골드가 필요하다면 골드정보 추가
if (0 < materialInfo.gold) if (0 < materialInfo.gold)
{ {
char temp[128]; char temp[128];
@ -779,7 +779,7 @@ bool Cube_InformationInitialize()
const std::vector<CUBE_VALUE>& rewards = cubeData->reward; const std::vector<CUBE_VALUE>& rewards = cubeData->reward;
// 하드코딩 ㅈㅅ // 하드코딩 ㅈㅅ
if (1 != rewards.size()) if (1 != rewards.size())
{ {
SPDLOG_ERROR("[CubeInfo] WARNING! Does not support multiple rewards (count: {})", rewards.size()); SPDLOG_ERROR("[CubeInfo] WARNING! Does not support multiple rewards (count: {})", rewards.size());
@ -807,13 +807,13 @@ bool Cube_InformationInitialize()
{ {
SCubeMaterialInfo& existInfo = *iter; SCubeMaterialInfo& existInfo = *iter;
// 이미 중복되는 보상이 등록되어 있다면 아예 다른 조합으로 만드는 것인지, // 이미 중복되는 보상이 등록되어 있다면 아예 다른 조합으로 만드는 것인지,
// 거의 같은 조합인데 특정 부분만 틀린 것인지 구분함. // 거의 같은 조합인데 특정 부분만 틀린 것인지 구분함.
// 예를들면 특정 부분만 틀린 아이템들은 아래처럼 하나로 묶어서 하나의 결과로 보여주기 위함임: // 예를들면 특정 부분만 틀린 아이템들은 아래처럼 하나로 묶어서 하나의 결과로 보여주기 위함임:
// 용신지검: // 용신지검:
// 무쌍검+5 ~ +9 x 1 // 무쌍검+5 ~ +9 x 1
// 붉은 칼자루 조각 x1 // 붉은 칼자루 조각 x1
// 녹색 검장식 조각 x1 // 녹색 검장식 조각 x1
if (reward.vnum == existInfo.reward.vnum) if (reward.vnum == existInfo.reward.vnum)
{ {
for (TCubeValueVector::iterator existMaterialIter = existInfo.material.begin(); existInfo.material.end() != existMaterialIter; ++existMaterialIter) for (TCubeValueVector::iterator existMaterialIter = existInfo.material.begin(); existInfo.material.end() != existMaterialIter; ++existMaterialIter)
@ -828,8 +828,8 @@ bool Cube_InformationInitialize()
if (0 < existItemInfo.level) if (0 < existItemInfo.level)
{ {
// 지금 추가하는 큐브 결과물의 재료와, 기존에 등록되어있던 큐브 결과물의 재료 중 // 지금 추가하는 큐브 결과물의 재료와, 기존에 등록되어있던 큐브 결과물의 재료 중
// 중복되는 부분이 있는지 검색한다 // 중복되는 부분이 있는지 검색한다
for (TCubeValueVector::iterator currentMaterialIter = materialInfo.material.begin(); materialInfo.material.end() != currentMaterialIter; ++currentMaterialIter) for (TCubeValueVector::iterator currentMaterialIter = materialInfo.material.begin(); materialInfo.material.end() != currentMaterialIter; ++currentMaterialIter)
{ {
TItemTable* currentMaterialProto = ITEM_MANAGER::Instance().GetTable(currentMaterialIter->vnum); TItemTable* currentMaterialProto = ITEM_MANAGER::Instance().GetTable(currentMaterialIter->vnum);
@ -845,7 +845,7 @@ bool Cube_InformationInitialize()
//currentMaterialIter = materialInfo.material.erase(currentMaterialIter); //currentMaterialIter = materialInfo.material.erase(currentMaterialIter);
// TODO: 중복되는 아이템 두 개 이상 검출해야 될 수도 있음 // TODO: 중복되는 아이템 두 개 이상 검출해야 될 수도 있음
break; break;
} }
} // for currentMaterialIter } // for currentMaterialIter
@ -865,7 +865,7 @@ bool Cube_InformationInitialize()
return true; return true;
} }
// 클라이언트에서 서버로 : 현재 NPC가 만들 수 있는 아이템들의 정보(목록)를 요청 // 클라이언트에서 서버로 : 현재 NPC가 만들 수 있는 아이템들의 정보(목록)를 요청
void Cube_request_result_list(LPCHARACTER ch) void Cube_request_result_list(LPCHARACTER ch)
{ {
RETURN_IF_CUBE_IS_NOT_OPENED(ch); RETURN_IF_CUBE_IS_NOT_OPENED(ch);
@ -879,7 +879,7 @@ void Cube_request_result_list(LPCHARACTER ch)
std::string& resultText = cube_result_info_map_by_npc[npcVNUM]; std::string& resultText = cube_result_info_map_by_npc[npcVNUM];
// 해당 NPC가 만들 수 있는 목록이 정리된 게 없다면 캐시를 생성 // 해당 NPC가 만들 수 있는 목록이 정리된 게 없다면 캐시를 생성
if (resultText.length() == 0) if (resultText.length() == 0)
{ {
resultText.clear(); resultText.clear();
@ -898,7 +898,7 @@ void Cube_request_result_list(LPCHARACTER ch)
resultText.erase(resultText.size() - 1); resultText.erase(resultText.size() - 1);
// 채팅 패킷의 한계를 넘어가면 에러 남김... 기획자 분들 께 조정해달라고 요청하거나, 나중에 다른 방식으로 바꾸거나... // 채팅 패킷의 한계를 넘어가면 에러 남김... 기획자 분들 께 조정해달라고 요청하거나, 나중에 다른 방식으로 바꾸거나...
if (resultText.size() - 20 >= CHAT_MAX_LEN) if (resultText.size() - 20 >= CHAT_MAX_LEN)
{ {
SPDLOG_ERROR("[CubeInfo] Too long cube result list text. (NPC: {}, length: {})", npcVNUM, resultText.size()); SPDLOG_ERROR("[CubeInfo] Too long cube result list text. (NPC: {}, length: {})", npcVNUM, resultText.size());
@ -908,7 +908,7 @@ void Cube_request_result_list(LPCHARACTER ch)
} }
// 현재 NPC가 만들 수 있는 아이템들의 목록을 아래 포맷으로 전송한다. // 현재 NPC가 만들 수 있는 아이템들의 목록을 아래 포맷으로 전송한다.
// (Server -> Client) /cube r_list npcVNUM resultCount vnum1,count1/vnum2,count2,/vnum3,count3/... // (Server -> Client) /cube r_list npcVNUM resultCount vnum1,count1/vnum2,count2,/vnum3,count3/...
// (Server -> Client) /cube r_list 20383 4 123,1/125,1/128,1/130,5 // (Server -> Client) /cube r_list 20383 4 123,1/125,1/128,1/130,5

View File

@ -399,7 +399,7 @@ void DBManager::FlushBilling(bool bForce)
void DBManager::CheckBilling() void DBManager::CheckBilling()
{ {
std::vector<DWORD> vec; std::vector<DWORD> vec;
vec.push_back(0); // 카운트를 위해 미리 비워둔다. vec.push_back(0); // 카운트를 위해 미리 비워둔다.
itertype(m_map_pkLoginData) it = m_map_pkLoginData.begin(); itertype(m_map_pkLoginData) it = m_map_pkLoginData.begin();
@ -414,7 +414,7 @@ void DBManager::CheckBilling()
} }
} }
vec[0] = vec.size() - 1; // 비워둔 곳에 사이즈를 넣는다, 사이즈 자신은 제외해야 하므로 -1 vec[0] = vec.size() - 1; // 비워둔 곳에 사이즈를 넣는다, 사이즈 자신은 제외해야 하므로 -1
db_clientdesc->DBPacket(HEADER_GD_BILLING_CHECK, 0, &vec[0], sizeof(DWORD) * vec.size()); db_clientdesc->DBPacket(HEADER_GD_BILLING_CHECK, 0, &vec[0], sizeof(DWORD) * vec.size());
} }
@ -632,7 +632,7 @@ void DBManager::AnalyzeReturnQuery(SQLMsg * pMsg)
M2_DELETE(pinfo); M2_DELETE(pinfo);
break; break;
} }
//위치 변경 - By SeMinZ //위치 변경 - By SeMinZ
d->SetLogin(pinfo->login); d->SetLogin(pinfo->login);
SPDLOG_DEBUG("QID_AUTH_LOGIN: START {} {}", qi->dwIdent, (void*) get_pointer(d)); SPDLOG_DEBUG("QID_AUTH_LOGIN: START {} {}", qi->dwIdent, (void*) get_pointer(d));
@ -758,7 +758,7 @@ void DBManager::AnalyzeReturnQuery(SQLMsg * pMsg)
if (true == LC_IsBrazil()) if (true == LC_IsBrazil())
{ {
nPasswordDiff = 0; // 브라질 버전에서는 비밀번호 체크를 하지 않는다. nPasswordDiff = 0; // 브라질 버전에서는 비밀번호 체크를 하지 않는다.
} }
if (nPasswordDiff) if (nPasswordDiff)
@ -789,7 +789,7 @@ void DBManager::AnalyzeReturnQuery(SQLMsg * pMsg)
{ {
if (LC_IsEurope()) if (LC_IsEurope())
{ {
//stBlockData >= 0 == 날짜가 BlockDate 보다 미래 //stBlockData >= 0 == 날짜가 BlockDate 보다 미래
if (strncmp(szCreateDate, g_stBlockDate.c_str(), 8) >= 0) if (strncmp(szCreateDate, g_stBlockDate.c_str(), 8) >= 0)
{ {
LoginFailure(d, "BLKLOGIN"); LoginFailure(d, "BLKLOGIN");
@ -1315,7 +1315,7 @@ enum EAccountQID
QID_SPAM_DB, QID_SPAM_DB,
}; };
// 10분마다 리로드 // 10분마다 리로드
static LPEVENT s_pkReloadSpamEvent = NULL; static LPEVENT s_pkReloadSpamEvent = NULL;
EVENTINFO(reload_spam_event_info) EVENTINFO(reload_spam_event_info)

View File

@ -318,12 +318,12 @@ void DESC::Packet(const void * c_pvData, int iSize)
{ {
assert(iSize > 0); assert(iSize > 0);
if (m_iPhase == PHASE_CLOSE) // 끊는 상태면 보내지 않는다. if (m_iPhase == PHASE_CLOSE) // 끊는 상태면 보내지 않는다.
return; return;
if (m_stRelayName.length() != 0) if (m_stRelayName.length() != 0)
{ {
// Relay 패킷은 암호화하지 않는다. // Relay 패킷은 암호화하지 않는다.
TPacketGGRelay p; TPacketGGRelay p;
p.bHeader = HEADER_GG_RELAY; p.bHeader = HEADER_GG_RELAY;
@ -369,7 +369,7 @@ void DESC::SetPhase(int _phase)
switch (m_iPhase) switch (m_iPhase)
{ {
case PHASE_CLOSE: case PHASE_CLOSE:
// 메신저가 캐릭터단위가 되면서 삭제 // 메신저가 캐릭터단위가 되면서 삭제
//MessengerManager::instance().Logout(GetAccountTable().login); //MessengerManager::instance().Logout(GetAccountTable().login);
m_pInputProcessor = &m_inputClose; m_pInputProcessor = &m_inputClose;
break; break;
@ -379,8 +379,8 @@ void DESC::SetPhase(int _phase)
break; break;
case PHASE_SELECT: case PHASE_SELECT:
// 메신저가 캐릭터단위가 되면서 삭제 // 메신저가 캐릭터단위가 되면서 삭제
//MessengerManager::instance().Logout(GetAccountTable().login); // 의도적으로 break 안검 //MessengerManager::instance().Logout(GetAccountTable().login); // 의도적으로 break 안검
case PHASE_LOGIN: case PHASE_LOGIN:
case PHASE_LOADING: case PHASE_LOADING:
m_pInputProcessor = &m_inputLogin; m_pInputProcessor = &m_inputLogin;

View File

@ -97,7 +97,7 @@ bool CLIENT_DESC::Connect(int iPhaseWhenSucceed)
if (iPhaseWhenSucceed != 0) if (iPhaseWhenSucceed != 0)
m_iPhaseWhenSucceed = iPhaseWhenSucceed; m_iPhaseWhenSucceed = iPhaseWhenSucceed;
if (get_global_time() - m_LastTryToConnectTime < 3) // 3초 if (get_global_time() - m_LastTryToConnectTime < 3) // 3초
return false; return false;
m_LastTryToConnectTime = get_global_time(); m_LastTryToConnectTime = get_global_time();
@ -220,7 +220,7 @@ void CLIENT_DESC::SetPhase(int iPhase)
SPDLOG_DEBUG("DB_SETUP current user {} size {}", p.dwLoginCount, buf.size()); SPDLOG_DEBUG("DB_SETUP current user {} size {}", p.dwLoginCount, buf.size());
// 파티를 처리할 수 있게 됨. // 파티를 처리할 수 있게 됨.
CPartyManager::instance().EnablePCParty(); CPartyManager::instance().EnablePCParty();
//CPartyManager::instance().SendPartyToDB(); //CPartyManager::instance().SendPartyToDB();
} }
@ -301,7 +301,7 @@ void CLIENT_DESC::Update(DWORD t)
void CLIENT_DESC::UpdateChannelStatus(DWORD t, bool fForce) void CLIENT_DESC::UpdateChannelStatus(DWORD t, bool fForce)
{ {
enum { enum {
CHANNELSTATUS_UPDATE_PERIOD = 5*60*1000, // 5분마다 CHANNELSTATUS_UPDATE_PERIOD = 5*60*1000, // 5분마다
}; };
if (fForce || m_tLastChannelStatusUpdateTime+CHANNELSTATUS_UPDATE_PERIOD < t) { if (fForce || m_tLastChannelStatusUpdateTime+CHANNELSTATUS_UPDATE_PERIOD < t) {
int iTotal; int iTotal;

View File

@ -53,7 +53,7 @@ int IsValidIP(struct valid_ip* ip_table, const char *host)
DESC_MANAGER::DESC_MANAGER() : m_bDestroyed(false) DESC_MANAGER::DESC_MANAGER() : m_bDestroyed(false)
{ {
Initialize(); Initialize();
//NOTE : Destroy 끝에서 Initialize 를 부르는건 또 무슨 짓이냐..-_-; 정말 //NOTE : Destroy 끝에서 Initialize 를 부르는건 또 무슨 짓이냐..-_-; 정말
m_pPackageCrypt = new CClientPackageCryptInfo; m_pPackageCrypt = new CClientPackageCryptInfo;
} }
@ -146,7 +146,7 @@ RETRY:
LPDESC DESC_MANAGER::AcceptDesc(evconnlistener* listener, evutil_socket_t fd, sockaddr* address) LPDESC DESC_MANAGER::AcceptDesc(evconnlistener* listener, evutil_socket_t fd, sockaddr* address)
{ {
if (!IsValidIP(admin_ip, GetSocketHost(address).c_str())) // admin_ip 에 등록된 IP 는 최대 사용자 수에 구애받지 않는다. if (!IsValidIP(admin_ip, GetSocketHost(address).c_str())) // admin_ip 에 등록된 IP 는 최대 사용자 수에 구애받지 않는다.
{ {
if (m_iSocketsConnected >= MAX_ALLOW_USER) if (m_iSocketsConnected >= MAX_ALLOW_USER)
{ {

View File

@ -172,7 +172,7 @@ bool DragonSoulTable::ReadBasicApplys()
TVecApplys vecApplys; TVecApplys vecApplys;
int n = pChild->GetRowCount(); int n = pChild->GetRowCount();
// BasicApply Group은 Key가 1부터 시작함. // BasicApply Group은 Key가 1부터 시작함.
for (int j = 1; j <= n; j++) for (int j = 1; j <= n; j++)
{ {
std::stringstream ss; std::stringstream ss;
@ -655,7 +655,7 @@ bool DragonSoulTable::GetWeight(BYTE ds_type, BYTE grade_idx, BYTE step_index, B
return true; return true;
} }
} }
// default group을 살펴봄. // default group을 살펴봄.
pDragonSoulGroup = m_pWeightTableNode->GetChildNode("default"); pDragonSoulGroup = m_pWeightTableNode->GetChildNode("default");
if (NULL != pDragonSoulGroup) if (NULL != pDragonSoulGroup)
{ {

View File

@ -1122,7 +1122,7 @@ struct FExitDungeonToStartPosition
{ {
PIXEL_POSITION posWarp; PIXEL_POSITION posWarp;
// 현재 맵 인덱스를 넣는 것이 아니라 시작하는 맵 인덱스를 넣는다. // 현재 맵 인덱스를 넣는 것이 아니라 시작하는 맵 인덱스를 넣는다.
if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(g_start_map[ch->GetEmpire()], ch->GetEmpire(), posWarp)) if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(g_start_map[ch->GetEmpire()], ch->GetEmpire(), posWarp))
ch->WarpSet(posWarp.x, posWarp.y); ch->WarpSet(posWarp.x, posWarp.y);
else else
@ -1272,7 +1272,7 @@ void CDungeon::JumpToEliminateLocation()
} }
else else
{ {
// 일반 맵으로 워프 // 일반 맵으로 워프
LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex); LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (!pMap) if (!pMap)

View File

@ -97,7 +97,7 @@ void CEntity::PacketView(const void * data, int bytes, LPENTITY except)
FuncPacketView f(data, bytes, except); FuncPacketView f(data, bytes, except);
// 옵저버 상태에선 내 패킷은 나만 받는다. // 옵저버 상태에선 내 패킷은 나만 받는다.
if (!m_bIsObserver) if (!m_bIsObserver)
for_each(m_map_view.begin(), m_map_view.end(), f); for_each(m_map_view.begin(), m_map_view.end(), f);

View File

@ -98,21 +98,21 @@ class CFuncViewInsert
void operator () (LPENTITY ent) void operator () (LPENTITY ent)
{ {
// 오브젝트가 아닌 것은 거리를 계산하여 거리가 멀면 추가하지 않는다. // 오브젝트가 아닌 것은 거리를 계산하여 거리가 멀면 추가하지 않는다.
if (!ent->IsType(ENTITY_OBJECT)) if (!ent->IsType(ENTITY_OBJECT))
if (DISTANCE_APPROX(ent->GetX() - m_me->GetX(), ent->GetY() - m_me->GetY()) > dwViewRange) if (DISTANCE_APPROX(ent->GetX() - m_me->GetX(), ent->GetY() - m_me->GetY()) > dwViewRange)
return; return;
// 나를 대상에 추가 // 나를 대상에 추가
m_me->ViewInsert(ent); m_me->ViewInsert(ent);
// 둘다 캐릭터면 // 둘다 캐릭터면
if (ent->IsType(ENTITY_CHARACTER) && m_me->IsType(ENTITY_CHARACTER)) if (ent->IsType(ENTITY_CHARACTER) && m_me->IsType(ENTITY_CHARACTER))
{ {
LPCHARACTER chMe = (LPCHARACTER) m_me; LPCHARACTER chMe = (LPCHARACTER) m_me;
LPCHARACTER chEnt = (LPCHARACTER) ent; LPCHARACTER chEnt = (LPCHARACTER) ent;
// 대상이 NPC면 StateMachine을 킨다. // 대상이 NPC면 StateMachine을 킨다.
if (chMe->IsPC() && !chEnt->IsPC() && !chEnt->IsWarp() && !chEnt->IsGoto()) if (chMe->IsPC() && !chEnt->IsPC() && !chEnt->IsWarp() && !chEnt->IsGoto())
chEnt->StartStateMachine(); chEnt->StartStateMachine();
} }
@ -134,13 +134,13 @@ void CEntity::UpdateSectree()
++m_iViewAge; ++m_iViewAge;
CFuncViewInsert f(this); // 나를 섹트리에 있는 사람들에게 추가 CFuncViewInsert f(this); // 나를 섹트리에 있는 사람들에게 추가
GetSectree()->ForEachAround(f); GetSectree()->ForEachAround(f);
ENTITY_MAP::iterator it, this_it; ENTITY_MAP::iterator it, this_it;
// //
// m_map_view에서 필요 없는 녀석들 지우기 // m_map_view에서 필요 없는 녀석들 지우기
// //
if (m_bObserverModeChange) if (m_bObserverModeChange)
{ {
@ -155,11 +155,11 @@ void CEntity::UpdateSectree()
{ {
LPENTITY ent = this_it->first; LPENTITY ent = this_it->first;
// 나로 부터 상대방을 지운다. // 나로 부터 상대방을 지운다.
ent->EncodeRemovePacket(this); ent->EncodeRemovePacket(this);
m_map_view.erase(this_it); m_map_view.erase(this_it);
// 상대로 부터 나를 지운다. // 상대로 부터 나를 지운다.
ent->ViewRemove(this, false); ent->ViewRemove(this, false);
} }
else else
@ -167,11 +167,11 @@ void CEntity::UpdateSectree()
LPENTITY ent = this_it->first; LPENTITY ent = this_it->first;
// 나로 부터 상대방을 지운다. // 나로 부터 상대방을 지운다.
//ent->EncodeRemovePacket(this); //ent->EncodeRemovePacket(this);
//m_map_view.erase(this_it); //m_map_view.erase(this_it);
// 상대로 부터 나를 지운다. // 상대로 부터 나를 지운다.
//ent->ViewRemove(this, false); //ent->ViewRemove(this, false);
EncodeRemovePacket(ent); EncodeRemovePacket(ent);
} }
@ -189,11 +189,11 @@ void CEntity::UpdateSectree()
{ {
LPENTITY ent = this_it->first; LPENTITY ent = this_it->first;
// 나로 부터 상대방을 지운다. // 나로 부터 상대방을 지운다.
ent->EncodeRemovePacket(this); ent->EncodeRemovePacket(this);
m_map_view.erase(this_it); m_map_view.erase(this_it);
// 상대로 부터 나를 지운다. // 상대로 부터 나를 지운다.
ent->ViewRemove(this, false); ent->ViewRemove(this, false);
} }
else else
@ -223,11 +223,11 @@ void CEntity::UpdateSectree()
{ {
LPENTITY ent = this_it->first; LPENTITY ent = this_it->first;
// 나로 부터 상대방을 지운다. // 나로 부터 상대방을 지운다.
ent->EncodeRemovePacket(this); ent->EncodeRemovePacket(this);
m_map_view.erase(this_it); m_map_view.erase(this_it);
// 상대로 부터 나를 지운다. // 상대로 부터 나를 지운다.
ent->ViewRemove(this, false); ent->ViewRemove(this, false);
} }
} }

View File

@ -1,8 +1,8 @@
/* /*
* Filename: event.c * Filename: event.c
* Description: 이벤트 관련 (timed event) * Description: 이벤트 관련 (timed event)
* *
* Author: 김한주 (aka. 비엽, Cronan), 송영진 (aka. myevan, 빗자루) * Author: 김한주 (aka. 비엽, Cronan), 송영진 (aka. myevan, 빗자루)
*/ */
#include "stdafx.h" #include "stdafx.h"
@ -18,12 +18,12 @@ static ObjectPool<EVENT> event_pool;
static CEventQueue cxx_q; static CEventQueue cxx_q;
/* 이벤트를 생성하고 리턴한다 */ /* 이벤트를 생성하고 리턴한다 */
LPEVENT event_create_ex(TEVENTFUNC func, event_info_data* info, int when) LPEVENT event_create_ex(TEVENTFUNC func, event_info_data* info, int when)
{ {
LPEVENT new_event = NULL; LPEVENT new_event = NULL;
/* 반드시 다음 pulse 이상의 시간이 지난 후에 부르도록 한다. */ /* 반드시 다음 pulse 이상의 시간이 지난 후에 부르도록 한다. */
if (when < 1) if (when < 1)
when = 1; when = 1;
@ -44,7 +44,7 @@ LPEVENT event_create_ex(TEVENTFUNC func, event_info_data* info, int when)
return (new_event); return (new_event);
} }
/* 시스템으로 부터 이벤트를 제거한다 */ /* 시스템으로 부터 이벤트를 제거한다 */
void event_cancel(LPEVENT * ppevent) void event_cancel(LPEVENT * ppevent)
{ {
LPEVENT event; LPEVENT event;
@ -69,7 +69,7 @@ void event_cancel(LPEVENT * ppevent)
return; return;
} }
// 이미 취소 되었는가? // 이미 취소 되었는가?
if (!event->q_el) if (!event->q_el)
{ {
*ppevent = NULL; *ppevent = NULL;
@ -98,14 +98,14 @@ void event_reset_time(LPEVENT event, int when)
} }
} }
/* 이벤트를 실행할 시간에 도달한 이벤트들을 실행한다 */ /* 이벤트를 실행할 시간에 도달한 이벤트들을 실행한다 */
int event_process(int pulse) int event_process(int pulse)
{ {
int new_time; int new_time;
int num_events = 0; int num_events = 0;
// event_q 즉 이벤트 큐의 헤드의 시간보다 현재의 pulse 가 적으면 루프문이 // event_q 즉 이벤트 큐의 헤드의 시간보다 현재의 pulse 가 적으면 루프문이
// 돌지 않게 된다. // 돌지 않게 된다.
while (pulse >= cxx_q.GetTopKey()) while (pulse >= cxx_q.GetTopKey())
{ {
TQueueElement * pElem = cxx_q.Dequeue(); TQueueElement * pElem = cxx_q.Dequeue();
@ -123,9 +123,9 @@ int event_process(int pulse)
cxx_q.Delete(pElem); cxx_q.Delete(pElem);
/* /*
* 리턴 값은 새로운 시간이며 리턴 값이 0 보다 클 경우 이벤트를 다시 추가한다. * 리턴 값은 새로운 시간이며 리턴 값이 0 보다 클 경우 이벤트를 다시 추가한다.
* 리턴 값을 0 이상으로 할 경우 event 에 할당된 메모리 정보를 삭제하지 않도록 * 리턴 값을 0 이상으로 할 경우 event 에 할당된 메모리 정보를 삭제하지 않도록
* 주의한다. * 주의한다.
*/ */
the_event->is_processing = true; the_event->is_processing = true;
@ -155,7 +155,7 @@ int event_process(int pulse)
return num_events; return num_events;
} }
/* 이벤트가 수행시간을 pulse 단위로 리턴해 준다 */ /* 이벤트가 수행시간을 pulse 단위로 리턴해 준다 */
int event_processing_time(LPEVENT event) int event_processing_time(LPEVENT event)
{ {
int start_time; int start_time;
@ -167,7 +167,7 @@ int event_processing_time(LPEVENT event)
return (thecore_heart->pulse - start_time); return (thecore_heart->pulse - start_time);
} }
/* 이벤트가 남은 시간을 pulse 단위로 리턴해 준다 */ /* 이벤트가 남은 시간을 pulse 단위로 리턴해 준다 */
int event_time(LPEVENT event) int event_time(LPEVENT event)
{ {
int when; int when;
@ -179,7 +179,7 @@ int event_time(LPEVENT event)
return (when - thecore_heart->pulse); return (when - thecore_heart->pulse);
} }
/* 모든 이벤트를 제거한다 */ /* 모든 이벤트를 제거한다 */
void event_destroy(void) void event_destroy(void)
{ {
TQueueElement * pElem; TQueueElement * pElem;

View File

@ -1,8 +1,8 @@
/* /*
* Filename: queue.c * Filename: queue.c
* Description: 큐 처리 * Description: 큐 처리
* *
* Author: 김한주 (aka. 비엽, Cronan), 송영진 (aka. myevan, 빗자루) * Author: 김한주 (aka. 비엽, Cronan), 송영진 (aka. myevan, 빗자루)
*/ */
#include "stdafx.h" #include "stdafx.h"

View File

@ -16,7 +16,7 @@
void exchange_packet(LPCHARACTER ch, BYTE sub_header, bool is_me, DWORD arg1, TItemPos arg2, DWORD arg3, void * pvData = NULL); void exchange_packet(LPCHARACTER ch, BYTE sub_header, bool is_me, DWORD arg1, TItemPos arg2, DWORD arg3, void * pvData = NULL);
// 교환 패킷 // 교환 패킷
void exchange_packet(LPCHARACTER ch, BYTE sub_header, bool is_me, DWORD arg1, TItemPos arg2, DWORD arg3, void * pvData) void exchange_packet(LPCHARACTER ch, BYTE sub_header, bool is_me, DWORD arg1, TItemPos arg2, DWORD arg3, void * pvData)
{ {
if (!ch->GetDesc()) if (!ch->GetDesc())
@ -45,10 +45,10 @@ void exchange_packet(LPCHARACTER ch, BYTE sub_header, bool is_me, DWORD arg1, TI
ch->GetDesc()->Packet(&pack_exchg, sizeof(pack_exchg)); ch->GetDesc()->Packet(&pack_exchg, sizeof(pack_exchg));
} }
// 교환을 시작 // 교환을 시작
bool CHARACTER::ExchangeStart(LPCHARACTER victim) bool CHARACTER::ExchangeStart(LPCHARACTER victim)
{ {
if (this == victim) // 자기 자신과는 교환을 못한다. if (this == victim) // 자기 자신과는 교환을 못한다.
return false; return false;
if (IsObserverMode()) if (IsObserverMode())
@ -75,7 +75,7 @@ bool CHARACTER::ExchangeStart(LPCHARACTER victim)
//END_PREVENT_TRADE_WINDOW //END_PREVENT_TRADE_WINDOW
int iDist = DISTANCE_APPROX(GetX() - victim->GetX(), GetY() - victim->GetY()); int iDist = DISTANCE_APPROX(GetX() - victim->GetX(), GetY() - victim->GetY());
// 거리 체크 // 거리 체크
if (iDist >= EXCHANGE_MAX_DISTANCE) if (iDist >= EXCHANGE_MAX_DISTANCE)
return false; return false;
@ -143,7 +143,7 @@ bool CExchange::AddItem(TItemPos item_pos, BYTE display_pos)
if (!item_pos.IsValidItemPosition()) if (!item_pos.IsValidItemPosition())
return false; return false;
// 장비는 교환할 수 없음 // 장비는 교환할 수 없음
if (item_pos.IsEquipPosition()) if (item_pos.IsEquipPosition())
return false; return false;
@ -163,7 +163,7 @@ bool CExchange::AddItem(TItemPos item_pos, BYTE display_pos)
return false; return false;
} }
// 이미 교환창에 추가된 아이템인가? // 이미 교환창에 추가된 아이템인가?
if (item->IsExchanging()) if (item->IsExchanging())
{ {
SPDLOG_DEBUG("EXCHANGE under exchanging"); SPDLOG_DEBUG("EXCHANGE under exchanging");
@ -212,7 +212,7 @@ bool CExchange::AddItem(TItemPos item_pos, BYTE display_pos)
return true; return true;
} }
// 추가할 공간이 없음 // 추가할 공간이 없음
return false; return false;
} }
@ -248,7 +248,7 @@ bool CExchange::AddGold(int gold)
if (GetOwner()->GetGold() < gold) if (GetOwner()->GetGold() < gold)
{ {
// 가지고 있는 돈이 부족. // 가지고 있는 돈이 부족.
exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_LESS_GOLD, 0, 0, NPOS, 0); exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_LESS_GOLD, 0, 0, NPOS, 0);
return false; return false;
} }
@ -271,7 +271,7 @@ bool CExchange::AddGold(int gold)
return true; return true;
} }
// 돈이 충분히 있는지, 교환하려는 아이템이 실제로 있는지 확인 한다. // 돈이 충분히 있는지, 교환하려는 아이템이 실제로 있는지 확인 한다.
bool CExchange::Check(int * piItemCount) bool CExchange::Check(int * piItemCount)
{ {
if (GetOwner()->GetGold() < m_lGold) if (GetOwner()->GetGold() < m_lGold)
@ -325,10 +325,10 @@ bool CExchange::CheckSpace()
s_grid2.Put(i - INVENTORY_MAX_NUM / 2, 1, item->GetSize()); s_grid2.Put(i - INVENTORY_MAX_NUM / 2, 1, item->GetSize());
} }
// 아... 뭔가 개병신 같지만... 용혼석 인벤을 노멀 인벤 보고 따라 만든 내 잘못이다 ㅠㅠ // 아... 뭔가 개병신 같지만... 용혼석 인벤을 노멀 인벤 보고 따라 만든 내 잘못이다 ㅠㅠ
static std::vector <WORD> s_vDSGrid(DRAGON_SOUL_INVENTORY_MAX_NUM); static std::vector <WORD> s_vDSGrid(DRAGON_SOUL_INVENTORY_MAX_NUM);
// 일단 용혼석을 교환하지 않을 가능성이 크므로, 용혼석 인벤 복사는 용혼석이 있을 때 하도록 한다. // 일단 용혼석을 교환하지 않을 가능성이 크므로, 용혼석 인벤 복사는 용혼석이 있을 때 하도록 한다.
bool bDSInitialized = false; bool bDSInitialized = false;
for (i = 0; i < EXCHANGE_ITEM_MAX_NUM; ++i) for (i = 0; i < EXCHANGE_ITEM_MAX_NUM; ++i)
@ -411,7 +411,7 @@ bool CExchange::CheckSpace()
return true; return true;
} }
// 교환 끝 (아이템과 돈 등을 실제로 옮긴다) // 교환 끝 (아이템과 돈 등을 실제로 옮긴다)
bool CExchange::Done() bool CExchange::Done()
{ {
int empty_pos, i; int empty_pos, i;
@ -493,7 +493,7 @@ bool CExchange::Done()
return true; return true;
} }
// 교환을 동의 // 교환을 동의
bool CExchange::Accept(bool bAccept) bool CExchange::Accept(bool bAccept)
{ {
if (m_bAccept == bAccept) if (m_bAccept == bAccept)
@ -501,7 +501,7 @@ bool CExchange::Accept(bool bAccept)
m_bAccept = bAccept; m_bAccept = bAccept;
// 둘 다 동의 했으므로 교환 성립 // 둘 다 동의 했으므로 교환 성립
if (m_bAccept && GetCompany()->m_bAccept) if (m_bAccept && GetCompany()->m_bAccept)
{ {
int iItemCount; int iItemCount;
@ -513,9 +513,9 @@ bool CExchange::Accept(bool bAccept)
victim->SetExchangeTime(); victim->SetExchangeTime();
//END_PREVENT_PORTAL_AFTER_EXCHANGE //END_PREVENT_PORTAL_AFTER_EXCHANGE
// exchange_check 에서는 교환할 아이템들이 제자리에 있나 확인하고, // exchange_check 에서는 교환할 아이템들이 제자리에 있나 확인하고,
// 엘크도 충분히 있나 확인한다, 두번째 인자로 교환할 아이템 개수 // 엘크도 충분히 있나 확인한다, 두번째 인자로 교환할 아이템 개수
// 를 리턴한다. // 를 리턴한다.
if (!Check(&iItemCount)) if (!Check(&iItemCount))
{ {
GetOwner()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB5\xB7\xC0\xCC \xBA\xCE\xC1\xB7\xC7\xCF\xB0\xC5\xB3\xAA \xBE\xC6\xC0\xCC\xC5\xDB\xC0\xCC \xC1\xA6\xC0\xDA\xB8\xAE\xBF\xA1 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9.")); GetOwner()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB5\xB7\xC0\xCC \xBA\xCE\xC1\xB7\xC7\xCF\xB0\xC5\xB3\xAA \xBE\xC6\xC0\xCC\xC5\xDB\xC0\xCC \xC1\xA6\xC0\xDA\xB8\xAE\xBF\xA1 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9."));
@ -523,7 +523,7 @@ bool CExchange::Accept(bool bAccept)
goto EXCHANGE_END; goto EXCHANGE_END;
} }
// 리턴 받은 아이템 개수로 상대방의 소지품에 남은 자리가 있나 확인한다. // 리턴 받은 아이템 개수로 상대방의 소지품에 남은 자리가 있나 확인한다.
if (!CheckSpace()) if (!CheckSpace())
{ {
GetOwner()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xBB\xF3\xB4\xEB\xB9\xE6\xC0\xC7 \xBC\xD2\xC1\xF6\xC7\xB0\xBF\xA1 \xBA\xF3 \xB0\xF8\xB0\xA3\xC0\xCC \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9.")); GetOwner()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xBB\xF3\xB4\xEB\xB9\xE6\xC0\xC7 \xBC\xD2\xC1\xF6\xC7\xB0\xBF\xA1 \xBA\xF3 \xB0\xF8\xB0\xA3\xC0\xCC \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9."));
@ -531,7 +531,7 @@ bool CExchange::Accept(bool bAccept)
goto EXCHANGE_END; goto EXCHANGE_END;
} }
// 상대방도 마찬가지로.. // 상대방도 마찬가지로..
if (!GetCompany()->Check(&iItemCount)) if (!GetCompany()->Check(&iItemCount))
{ {
victim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB5\xB7\xC0\xCC \xBA\xCE\xC1\xB7\xC7\xCF\xB0\xC5\xB3\xAA \xBE\xC6\xC0\xCC\xC5\xDB\xC0\xCC \xC1\xA6\xC0\xDA\xB8\xAE\xBF\xA1 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9.")); victim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB5\xB7\xC0\xCC \xBA\xCE\xC1\xB7\xC7\xCF\xB0\xC5\xB3\xAA \xBE\xC6\xC0\xCC\xC5\xDB\xC0\xCC \xC1\xA6\xC0\xDA\xB8\xAE\xBF\xA1 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9."));
@ -556,12 +556,12 @@ bool CExchange::Accept(bool bAccept)
if (Done()) if (Done())
{ {
if (m_lGold) // 돈이 있을 ??만 저장 if (m_lGold) // 돈이 있을 ??만 저장
GetOwner()->Save(); GetOwner()->Save();
if (GetCompany()->Done()) if (GetCompany()->Done())
{ {
if (GetCompany()->m_lGold) // 돈이 있을 때만 저장 if (GetCompany()->m_lGold) // 돈이 있을 때만 저장
victim->Save(); victim->Save();
// INTERNATIONAL_VERSION // INTERNATIONAL_VERSION
@ -577,14 +577,14 @@ EXCHANGE_END:
} }
else else
{ {
// 아니면 accept에 대한 패킷을 보내자. // 아니면 accept에 대한 패킷을 보내자.
exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_ACCEPT, true, m_bAccept, NPOS, 0); exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_ACCEPT, true, m_bAccept, NPOS, 0);
exchange_packet(GetCompany()->GetOwner(), EXCHANGE_SUBHEADER_GC_ACCEPT, false, m_bAccept, NPOS, 0); exchange_packet(GetCompany()->GetOwner(), EXCHANGE_SUBHEADER_GC_ACCEPT, false, m_bAccept, NPOS, 0);
return true; return true;
} }
} }
// 교환 취소 // 교환 취소
void CExchange::Cancel() void CExchange::Cancel()
{ {
exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_END, 0, 0, NPOS, 0); exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_END, 0, 0, NPOS, 0);

View File

@ -48,7 +48,7 @@ bool CMemoryTextFileLoader::SplitLine(DWORD dwLine, std::vector<std::string>* ps
pstTokenVector->push_back(c_rstLine.substr(beginPos, endPos - beginPos)); pstTokenVector->push_back(c_rstLine.substr(beginPos, endPos - beginPos));
// 추가 코드. 맨뒤에 탭이 있는 경우를 체크한다. - [levites] // 추가 코드. 맨뒤에 탭이 있는 경우를 체크한다. - [levites]
if (int(c_rstLine.find_first_not_of(c_szDelimeter, basePos)) < 0) if (int(c_rstLine.find_first_not_of(c_szDelimeter, basePos)) < 0)
break; break;
} while (basePos < c_rstLine.length()); } while (basePos < c_rstLine.length());

View File

@ -205,7 +205,7 @@ void Initialize()
{ {
SendLog("error! cannot open fishing.txt"); SendLog("error! cannot open fishing.txt");
// 백업에 이름이 있으면 리스토어 한다. // 백업에 이름이 있으면 리스토어 한다.
if (*fish_info_bak[0].name) if (*fish_info_bak[0].name)
{ {
memcpy(fish_info, fish_info_bak, sizeof(fish_info)); memcpy(fish_info, fish_info_bak, sizeof(fish_info));
@ -313,7 +313,7 @@ void Initialize()
fish_info[i].length_range[2]); fish_info[i].length_range[2]);
} }
// 확률 계산 // 확률 계산
for (int j = 0; j < MAX_PROB; ++j) for (int j = 0; j < MAX_PROB; ++j)
{ {
g_prob_accumulate[j][0] = fish_info[0].prob[j]; g_prob_accumulate[j][0] = fish_info[0].prob[j];
@ -366,7 +366,7 @@ int DetermineFish(LPCHARACTER ch)
// ADD_PREMIUM // ADD_PREMIUM
if (ch->GetPremiumRemainSeconds(PREMIUM_FISH_MIND) > 0 || if (ch->GetPremiumRemainSeconds(PREMIUM_FISH_MIND) > 0 ||
ch->IsEquipUniqueGroup(UNIQUE_GROUP_FISH_MIND)) // 월간어심 착용시 고급 물고기 확률 상승 ch->IsEquipUniqueGroup(UNIQUE_GROUP_FISH_MIND)) // 월간어심 착용시 고급 물고기 확률 상승
{ {
if (quest::CQuestManager::instance().GetEventFlag("manwoo") != 0) if (quest::CQuestManager::instance().GetEventFlag("manwoo") != 0)
prob_idx = 3; prob_idx = 3;
@ -394,7 +394,7 @@ int DetermineFish(LPCHARACTER ch)
return 0; return 0;
} }
if (g_iUseLocale) // 중국에서는 금덩어리, 금열쇠, 은열쇠 나오지 않게 함 if (g_iUseLocale) // 중국에서는 금덩어리, 금열쇠, 은열쇠 나오지 않게 함
{ {
DWORD vnum = fish_info[fish_idx].vnum; DWORD vnum = fish_info[fish_idx].vnum;
@ -437,7 +437,7 @@ void FishingPractice(LPCHARACTER ch)
LPITEM rod = ch->GetWear(WEAR_WEAPON); LPITEM rod = ch->GetWear(WEAR_WEAPON);
if (rod && rod->GetType() == ITEM_ROD) if (rod && rod->GetType() == ITEM_ROD)
{ {
// 최대 수련도가 아닌 경우 낚시대 수련 // 최대 수련도가 아닌 경우 낚시대 수련
if ( rod->GetRefinedVnum()>0 && rod->GetSocket(0) < rod->GetValue(2) && Random::get(1,rod->GetValue(1))==1 ) if ( rod->GetRefinedVnum()>0 && rod->GetSocket(0) < rod->GetValue(2) && Random::get(1,rod->GetValue(1))==1 )
{ {
rod->SetSocket(0, rod->GetSocket(0) + 1); rod->SetSocket(0, rod->GetSocket(0) + 1);
@ -449,14 +449,14 @@ void FishingPractice(LPCHARACTER ch)
} }
} }
} }
// 미끼를 뺀다 // 미끼를 뺀다
rod->SetSocket(2, 0); rod->SetSocket(2, 0);
} }
bool PredictFish(LPCHARACTER ch) bool PredictFish(LPCHARACTER ch)
{ {
// ADD_PREMIUM // ADD_PREMIUM
// 어심환 // 어심환
if (ch->FindAffect(AFFECT_FISH_MIND_PILL) || if (ch->FindAffect(AFFECT_FISH_MIND_PILL) ||
ch->GetPremiumRemainSeconds(PREMIUM_FISH_MIND) > 0 || ch->GetPremiumRemainSeconds(PREMIUM_FISH_MIND) > 0 ||
ch->IsEquipUniqueGroup(UNIQUE_GROUP_FISH_MIND)) ch->IsEquipUniqueGroup(UNIQUE_GROUP_FISH_MIND))
@ -491,7 +491,7 @@ EVENTFUNC(fishing_event)
switch (info->step) switch (info->step)
{ {
case 0: // 흔들리기 또는 떡밥만 날아감 case 0: // 흔들리기 또는 떡밥만 날아감
++info->step; ++info->step;
//info->ch->Motion(MOTION_FISHING_SIGN); //info->ch->Motion(MOTION_FISHING_SIGN);
@ -600,7 +600,7 @@ int GetFishLength(int fish_id)
void Take(fishing_event_info* info, LPCHARACTER ch) void Take(fishing_event_info* info, LPCHARACTER ch)
{ {
if (info->step == 1) // 고기가 걸린 상태면.. if (info->step == 1) // 고기가 걸린 상태면..
{ {
int ms = (int) ((get_dword_time() - info->hang_time)); int ms = (int) ((get_dword_time() - info->hang_time));
DWORD item_vnum = 0; DWORD item_vnum = 0;
@ -611,9 +611,9 @@ void Take(fishing_event_info* info, LPCHARACTER ch)
switch (ret) switch (ret)
{ {
case -2: // 잡히지 않은 경우 case -2: // 잡히지 않은 경우
case -3: // 난이도 때문에 실패 case -3: // 난이도 때문에 실패
case -1: // 시간 확률 때문에 실패 case -1: // 시간 확률 때문에 실패
//ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB0\xED\xB1\xE2\xB0\xA1 \xB9\xCC\xB3\xA2\xB8\xB8 \xBB\xA9\xB8\xD4\xB0\xED \xC0\xEC\xBD\xCE\xB0\xD4 \xB5\xB5\xB8\xC1\xC4\xA8\xB4\xCF\xB4\xD9.")); //ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB0\xED\xB1\xE2\xB0\xA1 \xB9\xCC\xB3\xA2\xB8\xB8 \xBB\xA9\xB8\xD4\xB0\xED \xC0\xEC\xBD\xCE\xB0\xD4 \xB5\xB5\xB8\xC1\xC4\xA8\xB4\xCF\xB4\xD9."));
{ {
int map_idx = ch->GetMapIndex(); int map_idx = ch->GetMapIndex();
@ -652,7 +652,7 @@ void Take(fishing_event_info* info, LPCHARACTER ch)
if (quest::CQuestManager::instance().GetEventFlag("fishevent") > 0 && (info->fish_id == 5 || info->fish_id == 6)) if (quest::CQuestManager::instance().GetEventFlag("fishevent") > 0 && (info->fish_id == 5 || info->fish_id == 6))
{ {
// 이벤트 중이므로 기록한다. // 이벤트 중이므로 기록한다.
TPacketGDHighscore p; TPacketGDHighscore p;
p.dwPID = ch->GetPlayerID(); p.dwPID = ch->GetPlayerID();
@ -758,7 +758,7 @@ void UseFish(LPCHARACTER ch, LPITEM item)
{ {
int idx = item->GetVnum() - fish_info[2].vnum+2; int idx = item->GetVnum() - fish_info[2].vnum+2;
// 피라미 사용불가, 살아있는게 아닌건 사용불가 // 피라미 사용불가, 살아있는게 아닌건 사용불가
if (idx<=1 || idx >= MAX_FISH) if (idx<=1 || idx >= MAX_FISH)
return; return;
@ -769,12 +769,12 @@ void UseFish(LPCHARACTER ch, LPITEM item)
if (r >= 4001) if (r >= 4001)
{ {
// 죽은 물고기 // 죽은 물고기
ch->AutoGiveItem(fish_info[idx].dead_vnum); ch->AutoGiveItem(fish_info[idx].dead_vnum);
} }
else if (r >= 2001) else if (r >= 2001)
{ {
// 생선뼈 // 생선뼈
ch->AutoGiveItem(FISH_BONE_VNUM); ch->AutoGiveItem(FISH_BONE_VNUM);
} }
else else
@ -878,14 +878,14 @@ int RealRefineRod(LPCHARACTER ch, LPITEM item)
if (pkNewItem) if (pkNewItem)
{ {
BYTE bCell = rod->GetCell(); BYTE bCell = rod->GetCell();
// 낚시대 개량 성공 // 낚시대 개량 성공
ITEM_MANAGER::instance().RemoveItem(rod, "REMOVE (REFINE FISH_ROD)"); ITEM_MANAGER::instance().RemoveItem(rod, "REMOVE (REFINE FISH_ROD)");
pkNewItem->AddToCharacter(ch, TItemPos (INVENTORY, bCell)); pkNewItem->AddToCharacter(ch, TItemPos (INVENTORY, bCell));
LogManager::instance().ItemLog(ch, pkNewItem, "REFINE FISH_ROD SUCCESS", pkNewItem->GetName()); LogManager::instance().ItemLog(ch, pkNewItem, "REFINE FISH_ROD SUCCESS", pkNewItem->GetName());
return 1; return 1;
} }
// 낚시대 개량 실패 // 낚시대 개량 실패
return 2; return 2;
} }
else else
@ -896,14 +896,14 @@ int RealRefineRod(LPCHARACTER ch, LPITEM item)
if (pkNewItem) if (pkNewItem)
{ {
BYTE bCell = rod->GetCell(); BYTE bCell = rod->GetCell();
// 낚시대 개량에 성공 // 낚시대 개량에 성공
ITEM_MANAGER::instance().RemoveItem(rod, "REMOVE (REFINE FISH_ROD)"); ITEM_MANAGER::instance().RemoveItem(rod, "REMOVE (REFINE FISH_ROD)");
pkNewItem->AddToCharacter(ch, TItemPos(INVENTORY, bCell)); pkNewItem->AddToCharacter(ch, TItemPos(INVENTORY, bCell));
LogManager::instance().ItemLog(ch, pkNewItem, "REFINE FISH_ROD FAIL", pkNewItem->GetName()); LogManager::instance().ItemLog(ch, pkNewItem, "REFINE FISH_ROD FAIL", pkNewItem->GetName());
return 0; return 0;
} }
// 낚시대 개량 실패 // 낚시대 개량 실패
return 2; return 2;
} }
} }

View File

@ -65,7 +65,7 @@ BYTE gm_new_get_level( const char * name, const char * host, const char* account
return GM_PLAYER; return GM_PLAYER;
// GERMAN_GM_NOT_CHECK_HOST // GERMAN_GM_NOT_CHECK_HOST
// 독일 버전은 호스트 체크를 하지 않는다. // 독일 버전은 호스트 체크를 하지 않는다.
if ( LC_IsEurope() && !LC_IsTaiwan() || LC_IsSingapore() ) if ( LC_IsEurope() && !LC_IsTaiwan() || LC_IsSingapore() )
{ {
if (account) if (account)

View File

@ -200,7 +200,7 @@ bool CGroupNode::GetRow(const std::string & c_rstrRowKey, OUT const CGroupNode::
return true; return true;
} }
// 참고로, idx랑 txt에 쓰여진 순서랑 관계 없음. // 참고로, idx랑 txt에 쓰여진 순서랑 관계 없음.
bool CGroupNode::GetRow(int idx, OUT const CGroupNode::CGroupNodeRow ** ppRow) const bool CGroupNode::GetRow(int idx, OUT const CGroupNode::CGroupNodeRow ** ppRow) const
{ {
if (idx >= m_map_rows.size()) if (idx >= m_map_rows.size())
@ -223,7 +223,7 @@ bool CGroupNode::GetGroupRow(const std::string& stGroupName, const std::string&
if (pChildGroup->GetRow(stRow, ppRow)) if (pChildGroup->GetRow(stRow, ppRow))
return true; return true;
} }
// default group을 살펴봄. // default group을 살펴봄.
pChildGroup = GetChildNode("default"); pChildGroup = GetChildNode("default");
if (NULL != pChildGroup) if (NULL != pChildGroup)
{ {

View File

@ -418,7 +418,7 @@ void CGuild::SendListPacket(LPCHARACTER ch)
Count (byte) Count (byte)
[ [
... ...
name_flag 1 - 이름을 보내느냐 안보내느냐 name_flag 1 - 이름을 보내느냐 안보내느냐
name CHARACTER_NAME_MAX_LEN+1 name CHARACTER_NAME_MAX_LEN+1
] * Count ] * Count
@ -560,7 +560,7 @@ void CGuild::LoadGuildMemberData(SQLMsg* pmsg)
void CGuild::LoadGuildGradeData(SQLMsg* pmsg) void CGuild::LoadGuildGradeData(SQLMsg* pmsg)
{ {
/* /*
// 15개 아닐 가능성 존재 // 15개 아닐 가능성 존재
if (pmsg->Get()->iNumRows != 15) if (pmsg->Get()->iNumRows != 15)
{ {
SPDLOG_ERROR("Query failed: getting guild grade data. GuildID({})", GetID()); SPDLOG_ERROR("Query failed: getting guild grade data. GuildID({})", GetID());
@ -698,7 +698,7 @@ void CGuild::__P2PUpdateGrade(SQLMsg* pmsg)
grade--; grade--;
// 등급 명칭이 현재와 다르다면 업데이트 // 등급 명칭이 현재와 다르다면 업데이트
if (0 != strcmp(m_data.grade_array[grade].grade_name, name)) if (0 != strcmp(m_data.grade_array[grade].grade_name, name))
{ {
strlcpy(m_data.grade_array[grade].grade_name, name, sizeof(m_data.grade_array[grade].grade_name)); strlcpy(m_data.grade_array[grade].grade_name, name, sizeof(m_data.grade_array[grade].grade_name));
@ -1084,7 +1084,7 @@ void CGuild::RefreshCommentForce(DWORD player_id)
d->RawPacket(szName, sizeof(szName)); d->RawPacket(szName, sizeof(szName));
if (i == pmsg->Get()->uiNumRows - 1) if (i == pmsg->Get()->uiNumRows - 1)
d->Packet(szContent, sizeof(szContent)); // 마지막 줄이면 보내기 d->Packet(szContent, sizeof(szContent)); // 마지막 줄이면 보내기
else else
d->RawPacket(szContent, sizeof(szContent)); d->RawPacket(szContent, sizeof(szContent));
} }
@ -1263,7 +1263,7 @@ void CGuild::UseSkill(DWORD dwVnum, LPCHARACTER ch, DWORD pid)
if ((pkSk->dwFlag & SKILL_FLAG_SELFONLY)) if ((pkSk->dwFlag & SKILL_FLAG_SELFONLY))
{ {
// 이미 걸려 있으므로 사용하지 않음. // 이미 걸려 있으므로 사용하지 않음.
if (ch->FindAffect(pkSk->dwVnum)) if (ch->FindAffect(pkSk->dwVnum))
return; return;
@ -1315,7 +1315,7 @@ void CGuild::UseSkill(DWORD dwVnum, LPCHARACTER ch, DWORD pid)
switch (dwVnum) switch (dwVnum)
{ {
case GUILD_SKILL_TELEPORT: case GUILD_SKILL_TELEPORT:
// 현재 서버에 있는 사람을 먼저 시도. // 현재 서버에 있는 사람을 먼저 시도.
SendDBSkillUpdate(-iNeededSP); SendDBSkillUpdate(-iNeededSP);
if ((victim = (CHARACTER_MANAGER::instance().FindByPID(pid)))) if ((victim = (CHARACTER_MANAGER::instance().FindByPID(pid))))
ch->WarpSet(victim->GetX(), victim->GetY()); ch->WarpSet(victim->GetX(), victim->GetY());
@ -1323,10 +1323,10 @@ void CGuild::UseSkill(DWORD dwVnum, LPCHARACTER ch, DWORD pid)
{ {
if (m_memberP2POnline.find(pid) != m_memberP2POnline.end()) if (m_memberP2POnline.find(pid) != m_memberP2POnline.end())
{ {
// 다른 서버에 로그인된 사람이 있음 -> 메시지 보내 좌표를 받아오자 // 다른 서버에 로그인된 사람이 있음 -> 메시지 보내 좌표를 받아오자
// 1. A.pid, B.pid 를 뿌림 // 1. A.pid, B.pid 를 뿌림
// 2. B.pid를 가진 서버가 뿌린서버에게 A.pid, 좌표 를 보냄 // 2. B.pid를 가진 서버가 뿌린서버에게 A.pid, 좌표 를 보냄
// 3. 워프 // 3. 워프
CCI * pcci = P2P_MANAGER::instance().FindByPID(pid); CCI * pcci = P2P_MANAGER::instance().FindByPID(pid);
if (pcci->bChannel != g_bChannel) if (pcci->bChannel != g_bChannel)
@ -1897,11 +1897,11 @@ bool CGuild::HasLand()
} }
// GUILD_JOIN_BUG_FIX // GUILD_JOIN_BUG_FIX
/// 길드 초대 event 정보 /// 길드 초대 event 정보
EVENTINFO(TInviteGuildEventInfo) EVENTINFO(TInviteGuildEventInfo)
{ {
DWORD dwInviteePID; ///< 초대받은 character 의 PID DWORD dwInviteePID; ///< 초대받은 character 의 PID
DWORD dwGuildID; ///< 초대한 Guild 의 ID DWORD dwGuildID; ///< 초대한 Guild 의 ID
TInviteGuildEventInfo() TInviteGuildEventInfo()
: dwInviteePID( 0 ) : dwInviteePID( 0 )
@ -1911,8 +1911,8 @@ EVENTINFO(TInviteGuildEventInfo)
}; };
/** /**
* 길드 초대 event callback 함수. * 길드 초대 event callback 함수.
* event 가 발동하면 초대 거절로 처리한다. * event 가 발동하면 초대 거절로 처리한다.
*/ */
EVENTFUNC( GuildInviteEvent ) EVENTFUNC( GuildInviteEvent )
{ {
@ -1989,7 +1989,7 @@ void CGuild::Invite( LPCHARACTER pchInviter, LPCHARACTER pchInvitee )
return; return;
// //
// 이벤트 생성 // 이벤트 생성
// //
TInviteGuildEventInfo* pInfo = AllocEventInfo<TInviteGuildEventInfo>(); TInviteGuildEventInfo* pInfo = AllocEventInfo<TInviteGuildEventInfo>();
pInfo->dwInviteePID = pchInvitee->GetPlayerID(); pInfo->dwInviteePID = pchInvitee->GetPlayerID();
@ -1998,7 +1998,7 @@ void CGuild::Invite( LPCHARACTER pchInviter, LPCHARACTER pchInvitee )
m_GuildInviteEventMap.insert(EventMap::value_type(pchInvitee->GetPlayerID(), event_create(GuildInviteEvent, pInfo, PASSES_PER_SEC(10)))); m_GuildInviteEventMap.insert(EventMap::value_type(pchInvitee->GetPlayerID(), event_create(GuildInviteEvent, pInfo, PASSES_PER_SEC(10))));
// //
// 초대 받는 character 에게 초대 패킷 전송 // 초대 받는 character 에게 초대 패킷 전송
// //
DWORD gid = GetID(); DWORD gid = GetID();

View File

@ -504,7 +504,7 @@ void CGuildManager::RequestWarOver(DWORD dwGuild1, DWORD dwGuild2, DWORD dwGuild
TPacketGuildWar p; TPacketGuildWar p;
p.bWar = GUILD_WAR_OVER; p.bWar = GUILD_WAR_OVER;
// 길드전이 끝나도 보상은 없다. // 길드전이 끝나도 보상은 없다.
//p.lWarPrice = lReward; //p.lWarPrice = lReward;
p.lWarPrice = 0; p.lWarPrice = 0;
p.bType = dwGuildWinner == 0 ? 1 : 0; // bType == 1 means draw for this packet. p.bType = dwGuildWinner == 0 ? 1 : 0; // bType == 1 means draw for this packet.
@ -952,7 +952,7 @@ void CGuildManager::ChangeMaster(DWORD dwGID)
iter->second->Load(dwGID); iter->second->Load(dwGID);
} }
// 업데이트된 정보 보내주기 // 업데이트된 정보 보내주기
DBManager::instance().FuncQuery(std::bind1st(std::mem_fun(&CGuild::SendGuildDataUpdateToAllMember), iter->second), DBManager::instance().FuncQuery(std::bind1st(std::mem_fun(&CGuild::SendGuildDataUpdateToAllMember), iter->second),
"SELECT 1"); "SELECT 1");

View File

@ -140,12 +140,12 @@ DWORD CGuild::GetGuildWarMapIndex(DWORD dwOppGID)
return git->second.map_index; return git->second.map_index;
} }
bool CGuild::CanStartWar(BYTE bGuildWarType) // 타입에 따라 다른 조건이 생길 수도 있음 bool CGuild::CanStartWar(BYTE bGuildWarType) // 타입에 따라 다른 조건이 생길 수도 있음
{ {
if (bGuildWarType >= GUILD_WAR_TYPE_MAX_NUM) if (bGuildWarType >= GUILD_WAR_TYPE_MAX_NUM)
return false; return false;
// 테스트시에는 인원수를 확인하지 않는다. // 테스트시에는 인원수를 확인하지 않는다.
if (test_server || quest::CQuestManager::instance().GetEventFlag("guild_war_test") != 0) if (test_server || quest::CQuestManager::instance().GetEventFlag("guild_war_test") != 0)
return GetLadderPoint() > 0; return GetLadderPoint() > 0;
@ -317,7 +317,7 @@ void CGuild::RequestDeclareWar(DWORD dwOppGID, BYTE type)
return; return;
} }
// 패킷 보내기 to another server // 패킷 보내기 to another server
TPacketGuildWar p; TPacketGuildWar p;
p.bType = type; p.bType = type;
p.bWar = GUILD_WAR_SEND_DECLARE; p.bWar = GUILD_WAR_SEND_DECLARE;
@ -336,7 +336,7 @@ void CGuild::RequestDeclareWar(DWORD dwOppGID, BYTE type)
if (saved_type == GUILD_WAR_TYPE_FIELD) if (saved_type == GUILD_WAR_TYPE_FIELD)
{ {
// 선전포고 한것을 받아들였다. // 선전포고 한것을 받아들였다.
TPacketGuildWar p; TPacketGuildWar p;
p.bType = saved_type; p.bType = saved_type;
p.bWar = GUILD_WAR_ON_WAR; p.bWar = GUILD_WAR_ON_WAR;
@ -441,14 +441,14 @@ void CGuild::StartWar(DWORD dwOppGID)
bool CGuild::WaitStartWar(DWORD dwOppGID) bool CGuild::WaitStartWar(DWORD dwOppGID)
{ {
//자기자신이면 //자기자신이면
if (dwOppGID == GetID()) if (dwOppGID == GetID())
{ {
SPDLOG_ERROR("GuildWar.WaitStartWar.DECLARE_WAR_SELF id({} -> {})", GetID(), dwOppGID); SPDLOG_ERROR("GuildWar.WaitStartWar.DECLARE_WAR_SELF id({} -> {})", GetID(), dwOppGID);
return false; return false;
} }
//상대방 길드 TGuildWar 를 얻어온다. //상대방 길드 TGuildWar 를 얻어온다.
itertype(m_EnemyGuild) it = m_EnemyGuild.find(dwOppGID); itertype(m_EnemyGuild) it = m_EnemyGuild.find(dwOppGID);
if (it == m_EnemyGuild.end()) if (it == m_EnemyGuild.end())
{ {
@ -456,7 +456,7 @@ bool CGuild::WaitStartWar(DWORD dwOppGID)
return false; return false;
} }
//레퍼런스에 등록하고 //레퍼런스에 등록하고
TGuildWar & gw(it->second); TGuildWar & gw(it->second);
if (gw.state == GUILD_WAR_WAIT_START) if (gw.state == GUILD_WAR_WAIT_START)
@ -465,10 +465,10 @@ bool CGuild::WaitStartWar(DWORD dwOppGID)
return false; return false;
} }
//상태를 저장한다. //상태를 저장한다.
gw.state = GUILD_WAR_WAIT_START; gw.state = GUILD_WAR_WAIT_START;
//상대편의 길드 클래스 포인터를 얻어오고 //상대편의 길드 클래스 포인터를 얻어오고
CGuild* g = CGuildManager::instance().FindGuild(dwOppGID); CGuild* g = CGuildManager::instance().FindGuild(dwOppGID);
if (!g) if (!g)
{ {
@ -481,14 +481,14 @@ bool CGuild::WaitStartWar(DWORD dwOppGID)
// END_OF_GUILDWAR_INFO // END_OF_GUILDWAR_INFO
// 필드형이면 맵생성 안함 // 필드형이면 맵생성 안함
if (gw.type == GUILD_WAR_TYPE_FIELD) if (gw.type == GUILD_WAR_TYPE_FIELD)
{ {
SPDLOG_DEBUG("GuildWar.WaitStartWar.FIELD_TYPE id({} -> {})", GetID(), dwOppGID); SPDLOG_DEBUG("GuildWar.WaitStartWar.FIELD_TYPE id({} -> {})", GetID(), dwOppGID);
return true; return true;
} }
// 전쟁 서버 인지 확인 // 전쟁 서버 인지 확인
SPDLOG_DEBUG("GuildWar.WaitStartWar.CheckWarServer id({} -> {}), type({}), map({})", SPDLOG_DEBUG("GuildWar.WaitStartWar.CheckWarServer id({} -> {}), type({}), map({})",
GetID(), dwOppGID, gw.type, rkGuildWarInfo.lMapIndex); GetID(), dwOppGID, gw.type, rkGuildWarInfo.lMapIndex);
@ -505,7 +505,7 @@ bool CGuild::WaitStartWar(DWORD dwOppGID)
if (id1 > id2) if (id1 > id2)
std::swap(id1, id2); std::swap(id1, id2);
//워프 맵을 생성 //워프 맵을 생성
DWORD lMapIndex = CWarMapManager::instance().CreateWarMap(rkGuildWarInfo, id1, id2); DWORD lMapIndex = CWarMapManager::instance().CreateWarMap(rkGuildWarInfo, id1, id2);
if (!lMapIndex) if (!lMapIndex)
{ {
@ -516,10 +516,10 @@ bool CGuild::WaitStartWar(DWORD dwOppGID)
SPDLOG_DEBUG("GuildWar.WaitStartWar.CreateMap id({} vs {}), type({}), map({}) -> map_inst({})", id1, id2, gw.type, rkGuildWarInfo.lMapIndex, lMapIndex); SPDLOG_DEBUG("GuildWar.WaitStartWar.CreateMap id({} vs {}), type({}), map({}) -> map_inst({})", id1, id2, gw.type, rkGuildWarInfo.lMapIndex, lMapIndex);
//길드전 정보에 맵인덱스를 세팅 //길드전 정보에 맵인덱스를 세팅
gw.map_index = lMapIndex; gw.map_index = lMapIndex;
//양쪽에 등록(?) //양쪽에 등록(?)
SetGuildWarMapIndex(dwOppGID, lMapIndex); SetGuildWarMapIndex(dwOppGID, lMapIndex);
g->SetGuildWarMapIndex(GetID(), lMapIndex); g->SetGuildWarMapIndex(GetID(), lMapIndex);
@ -546,7 +546,7 @@ void CGuild::RequestRefuseWar(DWORD dwOppGID)
if (it != m_EnemyGuild.end() && it->second.state == GUILD_WAR_RECV_DECLARE) if (it != m_EnemyGuild.end() && it->second.state == GUILD_WAR_RECV_DECLARE)
{ {
// 선전포고를 거절했다. // 선전포고를 거절했다.
TPacketGuildWar p; TPacketGuildWar p;
p.bWar = GUILD_WAR_REFUSE; p.bWar = GUILD_WAR_REFUSE;
p.dwGuildFrom = GetID(); p.dwGuildFrom = GetID();

View File

@ -14,10 +14,10 @@ const int HORSE_STAMINA_REGEN_INTERVAL = 12 * 60;
THorseStat c_aHorseStat[HORSE_MAX_LEVEL+1] = THorseStat c_aHorseStat[HORSE_MAX_LEVEL+1] =
/* /*
int iMinLevel; // 탑승할 수 있는 최소 레벨 int iMinLevel; // 탑승할 수 있는 최소 레벨
int iNPCRace; int iNPCRace;
int iMaxHealth; // 말의 최대 체력 int iMaxHealth; // 말의 최대 체력
int iMaxStamina; // 말의 최대 스테미너 int iMaxStamina; // 말의 최대 스테미너
int iST; int iST;
int iDX; int iDX;
int iHT; int iHT;
@ -29,7 +29,7 @@ THorseStat c_aHorseStat[HORSE_MAX_LEVEL+1] =
*/ */
{ {
{ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 25, 20101, 3, 4, 26, 35, 18, 9, 54, 43, 64, 32 }, // 1 (초급) { 25, 20101, 3, 4, 26, 35, 18, 9, 54, 43, 64, 32 }, // 1 (초급)
{ 25, 20101, 4, 4, 27, 36, 18, 9, 55, 44, 66, 33 }, { 25, 20101, 4, 4, 27, 36, 18, 9, 55, 44, 66, 33 },
{ 25, 20101, 5, 5, 28, 38, 19, 9, 56, 44, 67, 33 }, { 25, 20101, 5, 5, 28, 38, 19, 9, 56, 44, 67, 33 },
{ 25, 20101, 7, 5, 29, 39, 19, 10, 57, 45, 68, 34 }, { 25, 20101, 7, 5, 29, 39, 19, 10, 57, 45, 68, 34 },
@ -39,7 +39,7 @@ THorseStat c_aHorseStat[HORSE_MAX_LEVEL+1] =
{ 25, 20101, 12, 7, 33, 44, 22, 11, 61, 48, 73, 36 }, { 25, 20101, 12, 7, 33, 44, 22, 11, 61, 48, 73, 36 },
{ 25, 20101, 13, 8, 34, 45, 22, 11, 62, 49, 74, 37 }, { 25, 20101, 13, 8, 34, 45, 22, 11, 62, 49, 74, 37 },
{ 25, 20101, 15, 10, 35, 46, 23, 12, 63, 50, 75, 37 }, { 25, 20101, 15, 10, 35, 46, 23, 12, 63, 50, 75, 37 },
{ 35, 20104, 18, 30, 40, 53, 27, 13, 69, 55, 82, 41 }, // 11 (중급) { 35, 20104, 18, 30, 40, 53, 27, 13, 69, 55, 82, 41 }, // 11 (중급)
{ 35, 20104, 19, 35, 41, 54, 27, 14, 70, 56, 84, 42 }, { 35, 20104, 19, 35, 41, 54, 27, 14, 70, 56, 84, 42 },
{ 35, 20104, 21, 40, 42, 56, 28, 14, 71, 56, 85, 42 }, { 35, 20104, 21, 40, 42, 56, 28, 14, 71, 56, 85, 42 },
{ 35, 20104, 22, 50, 43, 57, 28, 14, 72, 57, 86, 43 }, { 35, 20104, 22, 50, 43, 57, 28, 14, 72, 57, 86, 43 },
@ -49,7 +49,7 @@ THorseStat c_aHorseStat[HORSE_MAX_LEVEL+1] =
{ 35, 20104, 28, 70, 46, 62, 31, 15, 76, 60, 91, 45 }, { 35, 20104, 28, 70, 46, 62, 31, 15, 76, 60, 91, 45 },
{ 35, 20104, 30, 80, 47, 63, 31, 16, 77, 61, 92, 46 }, { 35, 20104, 30, 80, 47, 63, 31, 16, 77, 61, 92, 46 },
{ 35, 20104, 32, 100, 48, 64, 32, 16, 78, 62, 93, 46 }, { 35, 20104, 32, 100, 48, 64, 32, 16, 78, 62, 93, 46 },
{ 50, 20107, 35, 120, 53, 71, 36, 18, 84, 67, 100, 50 }, // 21 (고급) { 50, 20107, 35, 120, 53, 71, 36, 18, 84, 67, 100, 50 }, // 21 (고급)
{ 50, 20107, 36, 125, 55, 74, 37, 18, 86, 68, 103, 51 }, { 50, 20107, 36, 125, 55, 74, 37, 18, 86, 68, 103, 51 },
{ 50, 20107, 37, 130, 57, 76, 38, 19, 88, 70, 105, 52 }, { 50, 20107, 37, 130, 57, 76, 38, 19, 88, 70, 105, 52 },
{ 50, 20107, 38, 135, 59, 78, 39, 20, 90, 72, 108, 54 }, { 50, 20107, 38, 135, 59, 78, 39, 20, 90, 72, 108, 54 },
@ -117,7 +117,7 @@ bool CHorseRider::ReviveHorse()
m_Horse.sHealth = c_aHorseStat[level].iMaxHealth; m_Horse.sHealth = c_aHorseStat[level].iMaxHealth;
m_Horse.sStamina = c_aHorseStat[level].iMaxStamina; m_Horse.sStamina = c_aHorseStat[level].iMaxStamina;
// 2005.03.24.ipkn.말 살린후 다시 죽는 현상 수정 // 2005.03.24.ipkn.말 살린후 다시 죽는 현상 수정
ResetHorseHealthDropTime(); ResetHorseHealthDropTime();
StartStaminaRegenEvent(); StartStaminaRegenEvent();
@ -138,11 +138,11 @@ short CHorseRider::GetHorseMaxStamina()
void CHorseRider::FeedHorse() void CHorseRider::FeedHorse()
{ {
// 말을 가지고 살아있을때만 // 말을 가지고 살아있을때만
if (GetHorseLevel() > 0 && GetHorseHealth() > 0) if (GetHorseLevel() > 0 && GetHorseHealth() > 0)
{ {
UpdateHorseHealth(+1); UpdateHorseHealth(+1);
// 20050324. ipkn 말 먹였을때도 체력 감소 딜레이를 늘린다. // 20050324. ipkn 말 먹였을때도 체력 감소 딜레이를 늘린다.
ResetHorseHealthDropTime(); ResetHorseHealthDropTime();
} }
} }
@ -159,7 +159,7 @@ void CHorseRider::UpdateHorseDataByLogoff(DWORD dwLogoffTime)
return; return;
if (dwLogoffTime >= 12 * 60) if (dwLogoffTime >= 12 * 60)
UpdateHorseStamina(dwLogoffTime / 12 / 60, false); // 로그오프 12분당 1씩 회복 UpdateHorseStamina(dwLogoffTime / 12 / 60, false); // 로그오프 12분당 1씩 회복
} }
void CHorseRider::UpdateHorseStamina(int iStamina, bool bSend) void CHorseRider::UpdateHorseStamina(int iStamina, bool bSend)

View File

@ -72,7 +72,7 @@ bool CInputProcessor::Process(LPDESC lpDesc, const void * c_pvOrig, int iBytes,
BYTE bHeader = (BYTE) *(c_pData); BYTE bHeader = (BYTE) *(c_pData);
const char * c_pszName; const char * c_pszName;
if (bHeader == 0) // 암호화 처리가 있으므로 0번 헤더는 스킵한다. if (bHeader == 0) // 암호화 처리가 있으므로 0번 헤더는 스킵한다.
iPacketLen = 1; iPacketLen = 1;
else if (!m_pPacketInfo->Get(bHeader, &iPacketLen, &c_pszName)) else if (!m_pPacketInfo->Get(bHeader, &iPacketLen, &c_pszName))
{ {
@ -249,7 +249,7 @@ ACMD(do_block_chat);
int CInputHandshake::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) int CInputHandshake::Analyze(LPDESC d, BYTE bHeader, const char * c_pData)
{ {
if (bHeader == 10) // 엔터는 무시 if (bHeader == 10) // 엔터는 무시
return 0; return 0;
if (bHeader == HEADER_CG_TEXT) if (bHeader == HEADER_CG_TEXT)
@ -257,7 +257,7 @@ int CInputHandshake::Analyze(LPDESC d, BYTE bHeader, const char * c_pData)
++c_pData; ++c_pData;
const char * c_pSep; const char * c_pSep;
if (!(c_pSep = strchr(c_pData, '\n'))) // \n을 찾는다. if (!(c_pSep = strchr(c_pData, '\n'))) // \n을 찾는다.
return -1; return -1;
if (*(c_pSep - 1) == '\r') if (*(c_pSep - 1) == '\r')
@ -356,7 +356,7 @@ int CInputHandshake::Analyze(LPDESC d, BYTE bHeader, const char * c_pData)
else if (!stBuf.compare(0,15,"DELETE_AWARDID ")) else if (!stBuf.compare(0,15,"DELETE_AWARDID "))
{ {
char szTmp[64]; char szTmp[64];
std::string msg = stBuf.substr(15,26); // item_award의 id범위? std::string msg = stBuf.substr(15,26); // item_award의 id범위?
TPacketDeleteAwardID p; TPacketDeleteAwardID p;
p.dwID = (DWORD)(atoi(msg.c_str())); p.dwID = (DWORD)(atoi(msg.c_str()));
@ -371,7 +371,7 @@ int CInputHandshake::Analyze(LPDESC d, BYTE bHeader, const char * c_pData)
if (d->IsAdminMode()) if (d->IsAdminMode())
{ {
// 어드민 명령들 // 어드민 명령들
if (!stBuf.compare(0, 7, "NOTICE ")) if (!stBuf.compare(0, 7, "NOTICE "))
{ {
std::string msg = stBuf.substr(7, 50); std::string msg = stBuf.substr(7, 50);
@ -519,7 +519,7 @@ int CInputHandshake::Analyze(LPDESC d, BYTE bHeader, const char * c_pData)
std::string strPrivEmpire; std::string strPrivEmpire;
is >> strPrivEmpire >> empire >> type >> value >> duration; is >> strPrivEmpire >> empire >> type >> value >> duration;
// 최대치 10배 // 최대치 10배
value = std::clamp(value, 0, 1000); value = std::clamp(value, 0, 1000);
stResult = "PRIV_EMPIRE FAIL"; stResult = "PRIV_EMPIRE FAIL";
@ -534,7 +534,7 @@ int CInputHandshake::Analyze(LPDESC d, BYTE bHeader, const char * c_pData)
{ {
stResult = "PRIV_EMPIRE SUCCEED"; stResult = "PRIV_EMPIRE SUCCEED";
// 시간 단위로 변경 // 시간 단위로 변경
duration = duration * (60 * 60); duration = duration * (60 * 60);
SPDLOG_DEBUG("_give_empire_privileage(empire={}, type={}, value={}, duration={}) by web", SPDLOG_DEBUG("_give_empire_privileage(empire={}, type={}, value={}, duration={}) by web",
@ -569,13 +569,13 @@ int CInputHandshake::Analyze(LPDESC d, BYTE bHeader, const char * c_pData)
{ {
if (!guild_mark_server) if (!guild_mark_server)
{ {
// 끊어버려! - 마크 서버가 아닌데 마크를 요청하려고? // 끊어버려! - 마크 서버가 아닌데 마크를 요청하려고?
SPDLOG_ERROR("Guild Mark login requested but i'm not a mark server!"); SPDLOG_ERROR("Guild Mark login requested but i'm not a mark server!");
d->SetPhase(PHASE_CLOSE); d->SetPhase(PHASE_CLOSE);
return 0; return 0;
} }
// 무조건 인증 --; // 무조건 인증 --;
SPDLOG_DEBUG("MARK_SERVER: Login"); SPDLOG_DEBUG("MARK_SERVER: Login");
d->SetPhase(PHASE_LOGIN); d->SetPhase(PHASE_LOGIN);
return 0; return 0;

View File

@ -23,11 +23,11 @@ bool FN_IS_VALID_LOGIN_STRING(const char *str)
for (tmp = str; *tmp; ++tmp) for (tmp = str; *tmp; ++tmp)
{ {
// 알파벳과 수자만 허용 // 알파벳과 수자만 허용
if (isdigit(*tmp) || isalpha(*tmp)) if (isdigit(*tmp) || isalpha(*tmp))
continue; continue;
// 캐나다는 몇몇 특수문자 허용 // 캐나다는 몇몇 특수문자 허용
if (LC_IsCanada()) if (LC_IsCanada())
{ {
switch (*tmp) switch (*tmp)
@ -111,7 +111,7 @@ void CInputAuth::Login(LPDESC d, const char * c_pData)
return; return;
} }
// string 무결성을 위해 복사 // string 무결성을 위해 복사
char login[LOGIN_MAX_LEN + 1]; char login[LOGIN_MAX_LEN + 1];
trim_and_lower(pinfo->login, login, sizeof(login)); trim_and_lower(pinfo->login, login, sizeof(login));

View File

@ -135,7 +135,7 @@ void CInputDB::LoginSuccess(DWORD dwHandle, const char *data)
return; return;
} }
if (strcmp(pTab->status, "OK")) // OK가 아니면 if (strcmp(pTab->status, "OK")) // OK가 아니면
{ {
SPDLOG_DEBUG("CInputDB::LoginSuccess - status[{}] is not OK [{}]", pTab->status, pTab->login); SPDLOG_DEBUG("CInputDB::LoginSuccess - status[{}] is not OK [{}]", pTab->status, pTab->login);
@ -158,7 +158,7 @@ void CInputDB::LoginSuccess(DWORD dwHandle, const char *data)
d->BindAccountTable(pTab); d->BindAccountTable(pTab);
if (!bFound) // 캐릭터가 없으면 랜덤한 제국으로 보낸다.. -_- if (!bFound) // 캐릭터가 없으면 랜덤한 제국으로 보낸다.. -_-
{ {
TPacketGCEmpire pe; TPacketGCEmpire pe;
pe.bHeader = HEADER_GC_EMPIRE; pe.bHeader = HEADER_GC_EMPIRE;
@ -231,7 +231,7 @@ void CInputDB::PlayerCreateSuccess(LPDESC d, const char * data)
d->Packet(&pack, sizeof(TPacketGCPlayerCreateSuccess)); d->Packet(&pack, sizeof(TPacketGCPlayerCreateSuccess));
// 기본 무기와 귀환부를 지급 // 기본 무기와 귀환부를 지급
TPlayerItem t; TPlayerItem t;
memset(&t, 0, sizeof(t)); memset(&t, 0, sizeof(t));
@ -241,10 +241,10 @@ void CInputDB::PlayerCreateSuccess(LPDESC d, const char * data)
t.count = 1; t.count = 1;
t.owner = r_Tab.players[pPacketDB->bAccountCharacterIndex].dwID; t.owner = r_Tab.players[pPacketDB->bAccountCharacterIndex].dwID;
//무사: 자인갑+3,철편투구+3,금편신발+3,남만도+3,백금목걸이+3, 흑단귀걸이+3, 소산부+3, 오각패+3, 흑단팔찌+3 //무사: 자인갑+3,철편투구+3,금편신발+3,남만도+3,백금목걸이+3, 흑단귀걸이+3, 소산부+3, 오각패+3, 흑단팔찌+3
//자객:영린+3,연환두건+3,금편신발+3,마안도+3,화안궁+3,옥목걸이+3, 옥귀걸이+3, 오각패+3, 흑단팔찌+3 //자객:영린+3,연환두건+3,금편신발+3,마안도+3,화안궁+3,옥목걸이+3, 옥귀걸이+3, 오각패+3, 흑단팔찌+3
//수라:음양갑+3,애희투구+3,금편신발+3,남만도+3,진주목걸이+3, 백금귀걸이+3, 오각패+3, 흑단팔찌+3 //수라:음양갑+3,애희투구+3,금편신발+3,남만도+3,진주목걸이+3, 백금귀걸이+3, 오각패+3, 흑단팔찌+3
//무당:서천의+3,태을모+3,금편신발+3,자린선+3,매화령+3,진주목걸이+3, 백금귀걸이+3, 오각패+3, 흑단팔찌+3 //무당:서천의+3,태을모+3,금편신발+3,자린선+3,매화령+3,진주목걸이+3, 백금귀걸이+3, 오각패+3, 흑단팔찌+3
struct SInitialItem struct SInitialItem
{ {
@ -347,7 +347,7 @@ void CInputDB::PlayerLoad(LPDESC d, const char * data)
{ {
lMapIndex = SECTREE_MANAGER::instance().GetMapIndex(pTab->x, pTab->y); lMapIndex = SECTREE_MANAGER::instance().GetMapIndex(pTab->x, pTab->y);
if (lMapIndex == 0) // 좌표를 찾을 수 없다. if (lMapIndex == 0) // 좌표를 찾을 수 없다.
{ {
lMapIndex = EMPIRE_START_MAP(d->GetAccountTable().bEmpire); lMapIndex = EMPIRE_START_MAP(d->GetAccountTable().bEmpire);
pos.x = EMPIRE_START_X(d->GetAccountTable().bEmpire); pos.x = EMPIRE_START_X(d->GetAccountTable().bEmpire);
@ -361,11 +361,11 @@ void CInputDB::PlayerLoad(LPDESC d, const char * data)
} }
pTab->lMapIndex = lMapIndex; pTab->lMapIndex = lMapIndex;
// Private 맵에 있었는데, Private 맵이 사라진 상태라면 출구로 돌아가야 한다. // Private 맵에 있었는데, Private 맵이 사라진 상태라면 출구로 돌아가야 한다.
// ---- // ----
// 근데 출구로 돌아가야 한다면서... 왜 출구가 아니라 private map 상에 대응되는 pulic map의 위치를 찾냐고... // 근데 출구로 돌아가야 한다면서... 왜 출구가 아니라 private map 상에 대응되는 pulic map의 위치를 찾냐고...
// 역사를 모르니... 또 하드코딩 한다. // 역사를 모르니... 또 하드코딩 한다.
// 아귀동굴이면, 출구로... // 아귀동굴이면, 출구로...
// by rtsummit // by rtsummit
if (!SECTREE_MANAGER::instance().GetValidLocation(pTab->lMapIndex, pTab->x, pTab->y, lMapIndex, pos, d->GetEmpire())) if (!SECTREE_MANAGER::instance().GetValidLocation(pTab->lMapIndex, pTab->x, pTab->y, lMapIndex, pos, d->GetEmpire()))
{ {
@ -479,11 +479,11 @@ void CInputDB::Boot(const char* data)
{ {
signal_timer_disable(); signal_timer_disable();
// 패킷 사이즈 체크 // 패킷 사이즈 체크
DWORD dwPacketSize = decode_4bytes(data); DWORD dwPacketSize = decode_4bytes(data);
data += 4; data += 4;
// 패킷 버전 체크 // 패킷 버전 체크
BYTE bVersion = decode_byte(data); BYTE bVersion = decode_byte(data);
data += 1; data += 1;
@ -802,7 +802,7 @@ void CInputDB::Boot(const char* data)
data += size * sizeof(TItemIDRangeTable); data += size * sizeof(TItemIDRangeTable);
//ADMIN_MANAGER //ADMIN_MANAGER
//관리자 등록 //관리자 등록
int ChunkSize = decode_2bytes(data ); int ChunkSize = decode_2bytes(data );
data += 2; data += 2;
int HostSize = decode_2bytes(data ); int HostSize = decode_2bytes(data );
@ -1170,7 +1170,7 @@ void CInputDB::SafeboxLoad(LPDESC d, const char * c_pData)
// END_OF_ADD_PREMIUM // END_OF_ADD_PREMIUM
//if (d->GetCharacter()->IsEquipUniqueItem(UNIQUE_ITEM_SAFEBOX_EXPAND)) //if (d->GetCharacter()->IsEquipUniqueItem(UNIQUE_ITEM_SAFEBOX_EXPAND))
//bSize = 3; // 창고확장권 //bSize = 3; // 창고확장권
//d->GetCharacter()->LoadSafebox(p->bSize * SAFEBOX_PAGE_SIZE, p->dwGold, p->wItemCount, (TPlayerItem *) (c_pData + sizeof(TSafeboxTable))); //d->GetCharacter()->LoadSafebox(p->bSize * SAFEBOX_PAGE_SIZE, p->dwGold, p->wItemCount, (TPlayerItem *) (c_pData + sizeof(TSafeboxTable)));
d->GetCharacter()->LoadSafebox(bSize * SAFEBOX_PAGE_SIZE, p->dwGold, p->wItemCount, (TPlayerItem *) (c_pData + sizeof(TSafeboxTable))); d->GetCharacter()->LoadSafebox(bSize * SAFEBOX_PAGE_SIZE, p->dwGold, p->wItemCount, (TPlayerItem *) (c_pData + sizeof(TSafeboxTable)));
@ -1190,7 +1190,7 @@ void CInputDB::SafeboxChangeSize(LPDESC d, const char * c_pData)
} }
// //
// @version 05/06/20 Bang2ni - ReqSafeboxLoad 의 취소 // @version 05/06/20 Bang2ni - ReqSafeboxLoad 의 취소
// //
void CInputDB::SafeboxWrongPassword(LPDESC d) void CInputDB::SafeboxWrongPassword(LPDESC d)
{ {
@ -1250,7 +1250,7 @@ void CInputDB::LoginAlready(LPDESC d, const char * c_pData)
if (!d) if (!d)
return; return;
// INTERNATIONAL_VERSION 이미 접속중이면 접속 끊음 // INTERNATIONAL_VERSION 이미 접속중이면 접속 끊음
{ {
TPacketDGLoginAlready * p = (TPacketDGLoginAlready *) c_pData; TPacketDGLoginAlready * p = (TPacketDGLoginAlready *) c_pData;
@ -1730,11 +1730,11 @@ void CInputDB::AuthLogin(LPDESC d, const char * c_pData)
if (bResult) if (bResult)
{ {
// Panama 암호화 팩에 필요한 키 보내기 // Panama 암호화 팩에 필요한 키 보내기
SendPanamaList(d); SendPanamaList(d);
ptoc.dwLoginKey = d->GetLoginKey(); ptoc.dwLoginKey = d->GetLoginKey();
//NOTE: AuthSucess보다 먼저 보내야지 안그러면 PHASE Close가 되서 보내지지 않는다.-_- //NOTE: AuthSucess보다 먼저 보내야지 안그러면 PHASE Close가 되서 보내지지 않는다.-_-
//Send Client Package CryptKey //Send Client Package CryptKey
{ {
DESC_MANAGER::instance().SendClientPackageCryptKey(d); DESC_MANAGER::instance().SendClientPackageCryptKey(d);
@ -1762,7 +1762,7 @@ void CInputDB::ChangeEmpirePriv(const char* c_pData)
} }
/** /**
* @version 05/06/08 Bang2ni - 지속시간 추가 * @version 05/06/08 Bang2ni - 지속시간 추가
*/ */
void CInputDB::ChangeGuildPriv(const char* c_pData) void CInputDB::ChangeGuildPriv(const char* c_pData)
{ {
@ -2101,7 +2101,7 @@ void CInputDB::ReloadAdmin(const char * c_pData )
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Analyze // Analyze
// @version 05/06/10 Bang2ni - 아이템 가격정보 리스트 패킷(HEADER_DG_MYSHOP_PRICELIST_RES) 처리루틴 추가. // @version 05/06/10 Bang2ni - 아이템 가격정보 리스트 패킷(HEADER_DG_MYSHOP_PRICELIST_RES) 처리루틴 추가.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
int CInputDB::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) int CInputDB::Analyze(LPDESC d, BYTE bHeader, const char * c_pData)
{ {
@ -2450,7 +2450,7 @@ int CInputDB::Analyze(LPDESC d, BYTE bHeader, const char * c_pData)
case HEADER_DG_NEED_LOGIN_LOG: case HEADER_DG_NEED_LOGIN_LOG:
DetailLog( (TPacketNeedLoginLogInfo*) c_pData ); DetailLog( (TPacketNeedLoginLogInfo*) c_pData );
break; break;
// 독일 선물 기능 테스트 // 독일 선물 기능 테스트
case HEADER_DG_ITEMAWARD_INFORMER: case HEADER_DG_ITEMAWARD_INFORMER:
ItemAwardInformer((TPacketItemAwardInfromer*) c_pData); ItemAwardInformer((TPacketItemAwardInfromer*) c_pData);
break; break;
@ -2618,7 +2618,7 @@ void CInputDB::DetailLog(const TPacketNeedLoginLogInfo* info)
void CInputDB::ItemAwardInformer(TPacketItemAwardInfromer *data) void CInputDB::ItemAwardInformer(TPacketItemAwardInfromer *data)
{ {
LPDESC d = DESC_MANAGER::instance().FindByLoginName(data->login); //login정보 LPDESC d = DESC_MANAGER::instance().FindByLoginName(data->login); //login정보
if(d == NULL) if(d == NULL)
return; return;
@ -2627,12 +2627,12 @@ void CInputDB::ItemAwardInformer(TPacketItemAwardInfromer *data)
if (d->GetCharacter()) if (d->GetCharacter())
{ {
LPCHARACTER ch = d->GetCharacter(); LPCHARACTER ch = d->GetCharacter();
ch->SetItemAward_vnum(data->vnum); // ch 에 임시 저장해놨다가 QuestLoad 함수에서 처리 ch->SetItemAward_vnum(data->vnum); // ch 에 임시 저장해놨다가 QuestLoad 함수에서 처리
ch->SetItemAward_cmd(data->command); ch->SetItemAward_cmd(data->command);
if(d->IsPhase(PHASE_GAME)) //게임페이즈일때 if(d->IsPhase(PHASE_GAME)) //게임페이즈일때
{ {
quest::CQuestManager::instance().ItemInformer(ch->GetPlayerID(),ch->GetItemAward_vnum()); //questmanager 호출 quest::CQuestManager::instance().ItemInformer(ch->GetPlayerID(),ch->GetItemAward_vnum()); //questmanager 호출
} }
} }
} }

View File

@ -68,13 +68,13 @@ static bool FN_is_battle_zone(LPCHARACTER ch)
{ {
switch (ch->GetMapIndex()) switch (ch->GetMapIndex())
{ {
case 1: // 신수 1차 마을 case 1: // 신수 1차 마을
case 2: // 신수 2차 마을 case 2: // 신수 2차 마을
case 21: // 천조 1차 마을 case 21: // 천조 1차 마을
case 23: // 천조 2차 마을 case 23: // 천조 2차 마을
case 41: // 진노 1차 마을 case 41: // 진노 1차 마을
case 43: // 진노 2차 마을 case 43: // 진노 2차 마을
case 113: // OX 맵 case 113: // OX 맵
return false; return false;
} }
@ -373,7 +373,7 @@ bool RaceToJob(unsigned race, unsigned* ret_job)
return true; return true;
} }
// 신규 캐릭터 지원 // 신규 캐릭터 지원
bool NewPlayerTable2(TPlayerTable * table, const char * name, BYTE race, BYTE shape, BYTE bEmpire) bool NewPlayerTable2(TPlayerTable * table, const char * name, BYTE race, BYTE shape, BYTE bEmpire)
{ {
if (race >= MAIN_RACE_MAX_NUM) if (race >= MAIN_RACE_MAX_NUM)
@ -397,7 +397,7 @@ bool NewPlayerTable2(TPlayerTable * table, const char * name, BYTE race, BYTE sh
strlcpy(table->name, name, sizeof(table->name)); strlcpy(table->name, name, sizeof(table->name));
table->level = 1; table->level = 1;
table->job = race; // 직업대신 종족을 넣는다 table->job = race; // 직업대신 종족을 넣는다
table->voice = 0; table->voice = 0;
table->part_base = shape; table->part_base = shape;
@ -443,7 +443,7 @@ void CInputLogin::CharacterCreate(LPDESC d, const char * data)
return; return;
} }
// 사용할 수 없는 이름이거나, 잘못된 평상복이면 생설 실패 // 사용할 수 없는 이름이거나, 잘못된 평상복이면 생설 실패
if (!check_name(pinfo->name) || pinfo->shape > 1) if (!check_name(pinfo->name) || pinfo->shape > 1)
{ {
if (LC_IsCanada() == true) if (LC_IsCanada() == true)
@ -573,7 +573,7 @@ void CInputLogin::Entergame(LPDESC d, const char * data)
CGuildManager::instance().LoginMember(ch); CGuildManager::instance().LoginMember(ch);
// 캐릭터를 맵에 추가 // 캐릭터를 맵에 추가
ch->Show(ch->GetMapIndex(), pos.x, pos.y, pos.z); ch->Show(ch->GetMapIndex(), pos.x, pos.y, pos.z);
SECTREE_MANAGER::instance().SendNPCPosition(ch); SECTREE_MANAGER::instance().SendNPCPosition(ch);
@ -581,8 +581,8 @@ void CInputLogin::Entergame(LPDESC d, const char * data)
d->SetPhase(PHASE_GAME); d->SetPhase(PHASE_GAME);
if(ch->GetItemAward_cmd()) //게임페이즈 들어가면 if(ch->GetItemAward_cmd()) //게임페이즈 들어가면
quest::CQuestManager::instance().ItemInformer(ch->GetPlayerID(),ch->GetItemAward_vnum()); //questmanager 호출 quest::CQuestManager::instance().ItemInformer(ch->GetPlayerID(),ch->GetItemAward_vnum()); //questmanager 호출
SPDLOG_DEBUG("ENTERGAME: {} {}x{}x{} {} map_index {}", SPDLOG_DEBUG("ENTERGAME: {} {}x{}x{} {} map_index {}",
ch->GetName(), ch->GetX(), ch->GetY(), ch->GetZ(), d->GetHostName(), ch->GetMapIndex()); ch->GetName(), ch->GetX(), ch->GetY(), ch->GetZ(), d->GetHostName(), ch->GetMapIndex());
@ -592,10 +592,10 @@ void CInputLogin::Entergame(LPDESC d, const char * data)
ch->EnterHorse(); ch->EnterHorse();
} }
// 플레이시간 레코딩 시작 // 플레이시간 레코딩 시작
ch->ResetPlayTime(); ch->ResetPlayTime();
// 자동 저장 이벤트 추가 // 자동 저장 이벤트 추가
ch->StartSaveEvent(); ch->StartSaveEvent();
ch->StartRecoveryEvent(); ch->StartRecoveryEvent();
ch->StartCheckSpeedHackEvent(); ch->StartCheckSpeedHackEvent();
@ -751,10 +751,10 @@ void CInputLogin::Entergame(LPDESC d, const char * data)
} }
else if (ch->GetMapIndex() == 113) else if (ch->GetMapIndex() == 113)
{ {
// ox 이벤트 맵 // ox 이벤트 맵
if (COXEventManager::instance().Enter(ch) == false) if (COXEventManager::instance().Enter(ch) == false)
{ {
// ox 맵 진입 허가가 나지 않음. 플레이어면 마을로 보내자 // ox 맵 진입 허가가 나지 않음. 플레이어면 마을로 보내자
if (ch->GetGMLevel() == GM_PLAYER) if (ch->GetGMLevel() == GM_PLAYER)
ch->WarpSet(EMPIRE_START_X(ch->GetEmpire()), EMPIRE_START_Y(ch->GetEmpire())); ch->WarpSet(EMPIRE_START_X(ch->GetEmpire()), EMPIRE_START_Y(ch->GetEmpire()));
} }
@ -769,8 +769,8 @@ void CInputLogin::Entergame(LPDESC d, const char * data)
} }
} }
// 청소년 보호 // 청소년 보호
if (g_TeenDesc) // RawPacket 사용 금지 if (g_TeenDesc) // RawPacket 사용 금지
{ {
TPacketGTLogin p; TPacketGTLogin p;
@ -790,7 +790,7 @@ void CInputLogin::Entergame(LPDESC d, const char * data)
db_clientdesc->DBPacket(HEADER_GD_REQ_HORSE_NAME, 0, &pid, sizeof(DWORD)); db_clientdesc->DBPacket(HEADER_GD_REQ_HORSE_NAME, 0, &pid, sizeof(DWORD));
} }
// 중립맵에 들어갔을때 안내하기 // 중립맵에 들어갔을때 안내하기
if (g_noticeBattleZone) if (g_noticeBattleZone)
{ {
if (FN_is_battle_zone(ch)) if (FN_is_battle_zone(ch))
@ -850,13 +850,13 @@ int CInputLogin::GuildSymbolUpload(LPDESC d, const char* c_pData, size_t uiBytes
if (iSymbolSize <= 0 || iSymbolSize > 64 * 1024) if (iSymbolSize <= 0 || iSymbolSize > 64 * 1024)
{ {
// 64k 보다 큰 길드 심볼은 올릴수없다 // 64k 보다 큰 길드 심볼은 올릴수없다
// 접속을 끊고 무시 // 접속을 끊고 무시
d->SetPhase(PHASE_CLOSE); d->SetPhase(PHASE_CLOSE);
return 0; return 0;
} }
// 땅을 소유하지 않은 길드인 경우. // 땅을 소유하지 않은 길드인 경우.
if (!test_server) if (!test_server)
if (!building::CManager::instance().FindLandByGuild(p->guild_id)) if (!building::CManager::instance().FindLandByGuild(p->guild_id))
{ {
@ -972,7 +972,7 @@ void CInputLogin::GuildMarkCRCList(LPDESC d, const char* c_pData)
CGuildMarkManager::instance().GetDiffBlocks(pCG->imgIdx, pCG->crclist, mapDiffBlocks); CGuildMarkManager::instance().GetDiffBlocks(pCG->imgIdx, pCG->crclist, mapDiffBlocks);
DWORD blockCount = 0; DWORD blockCount = 0;
TEMP_BUFFER buf(1024 * 1024); // 1M 버퍼 TEMP_BUFFER buf(1024 * 1024); // 1M 버퍼
for (itertype(mapDiffBlocks) it = mapDiffBlocks.begin(); it != mapDiffBlocks.end(); ++it) for (itertype(mapDiffBlocks) it = mapDiffBlocks.begin(); it != mapDiffBlocks.end(); ++it)
{ {

View File

@ -45,7 +45,7 @@ extern int g_nPortalLimitTime;
static int __deposit_limit() static int __deposit_limit()
{ {
return (1000*10000); // 1천만 return (1000*10000); // 1천만
} }
void SendBlockChatInfo(LPCHARACTER ch, int sec) void SendBlockChatInfo(LPCHARACTER ch, int sec)
@ -181,7 +181,7 @@ int GetTextTag(const char * src, int maxLen, int & tagLen, std::string & extraIn
const char * cur = ++src; const char * cur = ++src;
if (*cur == '|') // ||는 |로 표시한다. if (*cur == '|') // ||는 |로 표시한다.
{ {
tagLen = 2; tagLen = 2;
return TEXT_TAG_TAG; return TEXT_TAG_TAG;
@ -191,7 +191,7 @@ int GetTextTag(const char * src, int maxLen, int & tagLen, std::string & extraIn
tagLen = 2; tagLen = 2;
return TEXT_TAG_COLOR; return TEXT_TAG_COLOR;
} }
else if (*cur == 'H') // hyperlink |Hitem:10000:0:0:0:0|h[이름]|h else if (*cur == 'H') // hyperlink |Hitem:10000:0:0:0:0|h[이름]|h
{ {
tagLen = 2; tagLen = 2;
return TEXT_TAG_HYPERLINK_START; return TEXT_TAG_HYPERLINK_START;
@ -229,12 +229,12 @@ void GetTextTagInfo(const char * src, int src_len, int & hyperlinks, bool & colo
int ProcessTextTag(LPCHARACTER ch, const char * c_pszText, size_t len) int ProcessTextTag(LPCHARACTER ch, const char * c_pszText, size_t len)
{ {
//2012.05.17 김용욱 //2012.05.17 김용욱
//0 : 정상적으로 사용 //0 : 정상적으로 사용
//1 : 금강경 부족 //1 : 금강경 부족
//2 : 금강경이 있으나, 개인상점에서 사용중 //2 : 금강경이 있으나, 개인상점에서 사용중
//3 : 교환중 //3 : 교환중
//4 : 에러 //4 : 에러
int hyperlinks; int hyperlinks;
bool colored; bool colored;
@ -419,18 +419,18 @@ int CInputMain::Whisper(LPCHARACTER ch, const char * data, size_t uiBytes)
if (g_bEmpireWhisper) if (g_bEmpireWhisper)
if (!ch->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE)) if (!ch->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE))
if (!(pkChr && pkChr->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE))) if (!(pkChr && pkChr->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE)))
if (bOpponentEmpire != ch->GetEmpire() && ch->GetEmpire() && bOpponentEmpire // 서로 제국이 다르면서 if (bOpponentEmpire != ch->GetEmpire() && ch->GetEmpire() && bOpponentEmpire // 서로 제국이 다르면서
&& ch->GetGMLevel() == GM_PLAYER && gm_get_level(pinfo->szNameTo) == GM_PLAYER) // 둘다 일반 플레이어이면 && ch->GetGMLevel() == GM_PLAYER && gm_get_level(pinfo->szNameTo) == GM_PLAYER) // 둘다 일반 플레이어이면
// 이름 밖에 모르니 gm_get_level 함수를 사용 // 이름 밖에 모르니 gm_get_level 함수를 사용
{ {
if (!pkChr) if (!pkChr)
{ {
// 다른 서버에 있으니 제국 표시만 한다. bType의 상위 4비트를 Empire번호로 사용한다. // 다른 서버에 있으니 제국 표시만 한다. bType의 상위 4비트를 Empire번호로 사용한다.
bType = ch->GetEmpire() << 4; bType = ch->GetEmpire() << 4;
} }
else else
{ {
ConvertEmpireText(ch->GetEmpire(), buf, buflen, 10 + 2 * pkChr->GetSkillPower(SKILL_LANGUAGE1 + ch->GetEmpire() - 1)/*변환확률*/); ConvertEmpireText(ch->GetEmpire(), buf, buflen, 10 + 2 * pkChr->GetSkillPower(SKILL_LANGUAGE1 + ch->GetEmpire() - 1)/*변환확률*/);
} }
} }
@ -445,7 +445,7 @@ int CInputMain::Whisper(LPCHARACTER ch, const char * data, size_t uiBytes)
{ {
char buf[128]; char buf[128];
int len; int len;
if (3==processReturn) //교환중 if (3==processReturn) //교환중
len = snprintf(buf, sizeof(buf), LC_TEXT("\xB4\xD9\xB8\xA5 \xB0\xC5\xB7\xA1\xC1\xDF(\xC3\xA2\xB0\xED,\xB1\xB3\xC8\xAF,\xBB\xF3\xC1\xA1)\xBF\xA1\xB4\xC2 \xB0\xB3\xC0\xCE\xBB\xF3\xC1\xA1\xC0\xBB \xBB\xE7\xBF\xEB\xC7\xD2 \xBC\xF6 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9."), pTable->szLocaleName); len = snprintf(buf, sizeof(buf), LC_TEXT("\xB4\xD9\xB8\xA5 \xB0\xC5\xB7\xA1\xC1\xDF(\xC3\xA2\xB0\xED,\xB1\xB3\xC8\xAF,\xBB\xF3\xC1\xA1)\xBF\xA1\xB4\xC2 \xB0\xB3\xC0\xCE\xBB\xF3\xC1\xA1\xC0\xBB \xBB\xE7\xBF\xEB\xC7\xD2 \xBC\xF6 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9."), pTable->szLocaleName);
else else
len = snprintf(buf, sizeof(buf), LC_TEXT("%s\xC0\xCC \xC7\xCA\xBF\xE4\xC7\xD5\xB4\xCF\xB4\xD9."), pTable->szLocaleName); len = snprintf(buf, sizeof(buf), LC_TEXT("%s\xC0\xCC \xC7\xCA\xBF\xE4\xC7\xD5\xB4\xCF\xB4\xD9."), pTable->szLocaleName);
@ -454,7 +454,7 @@ int CInputMain::Whisper(LPCHARACTER ch, const char * data, size_t uiBytes)
if (len < 0 || len >= (int) sizeof(buf)) if (len < 0 || len >= (int) sizeof(buf))
len = sizeof(buf) - 1; len = sizeof(buf) - 1;
++len; // \0 문자 포함 ++len; // \0 문자 포함
TPacketGCWhisper pack; TPacketGCWhisper pack;
@ -470,7 +470,7 @@ int CInputMain::Whisper(LPCHARACTER ch, const char * data, size_t uiBytes)
} }
} }
// 릴래이 상태일 수 있으므로 릴래이를 풀어준다. // 릴래이 상태일 수 있으므로 릴래이를 풀어준다.
pkDesc->SetRelay(""); pkDesc->SetRelay("");
return (iExtraLen); return (iExtraLen);
} }
@ -487,8 +487,8 @@ int CInputMain::Whisper(LPCHARACTER ch, const char * data, size_t uiBytes)
pack.bType = bType; pack.bType = bType;
strlcpy(pack.szNameFrom, ch->GetName(), sizeof(pack.szNameFrom)); strlcpy(pack.szNameFrom, ch->GetName(), sizeof(pack.szNameFrom));
// desc->BufferedPacket을 하지 않고 버퍼에 써야하는 이유는 // desc->BufferedPacket을 하지 않고 버퍼에 써야하는 이유는
// P2P relay되어 패킷이 캡슐화 될 수 있기 때문이다. // P2P relay되어 패킷이 캡슐화 될 수 있기 때문이다.
TEMP_BUFFER tmpbuf; TEMP_BUFFER tmpbuf;
tmpbuf.write(&pack, sizeof(pack)); tmpbuf.write(&pack, sizeof(pack));
@ -563,7 +563,7 @@ struct FEmpireChatPacket
} }
else else
{ {
// 사람마다 스킬레벨이 다르니 매번 해야합니다 // 사람마다 스킬레벨이 다르니 매번 해야합니다
strlcpy(converted_msg, orig_msg, sizeof(converted_msg)); strlcpy(converted_msg, orig_msg, sizeof(converted_msg));
ConvertEmpireText(bEmpire, converted_msg + namelen, sizeof(converted_msg) - namelen, 10 + 2 * d->GetCharacter()->GetSkillPower(SKILL_LANGUAGE1 + bEmpire - 1)); ConvertEmpireText(bEmpire, converted_msg + namelen, sizeof(converted_msg) - namelen, 10 + 2 * d->GetCharacter()->GetSkillPower(SKILL_LANGUAGE1 + bEmpire - 1));
@ -595,17 +595,17 @@ struct FYmirChatPacket
m_iMapIndex(iMapIndex), m_bEmpire(empire), m_iMapIndex(iMapIndex), m_bEmpire(empire),
m_ring(ring) m_ring(ring)
{ {
m_len_orig_msg = snprintf(m_orig_msg, sizeof(m_orig_msg), "%s : %s", m_szName, m_szChat) + 1; // 널 문자 포함 m_len_orig_msg = snprintf(m_orig_msg, sizeof(m_orig_msg), "%s : %s", m_szName, m_szChat) + 1; // 널 문자 포함
if (m_len_orig_msg < 0 || m_len_orig_msg >= (int) sizeof(m_orig_msg)) if (m_len_orig_msg < 0 || m_len_orig_msg >= (int) sizeof(m_orig_msg))
m_len_orig_msg = sizeof(m_orig_msg) - 1; m_len_orig_msg = sizeof(m_orig_msg) - 1;
m_len_conv_msg = snprintf(m_conv_msg, sizeof(m_conv_msg), "??? : %s", m_szChat) + 1; // 널 문자 미포함 m_len_conv_msg = snprintf(m_conv_msg, sizeof(m_conv_msg), "??? : %s", m_szChat) + 1; // 널 문자 미포함
if (m_len_conv_msg < 0 || m_len_conv_msg >= (int) sizeof(m_conv_msg)) if (m_len_conv_msg < 0 || m_len_conv_msg >= (int) sizeof(m_conv_msg))
m_len_conv_msg = sizeof(m_conv_msg) - 1; m_len_conv_msg = sizeof(m_conv_msg) - 1;
ConvertEmpireText(m_bEmpire, m_conv_msg + 6, m_len_conv_msg - 6, 10); // 6은 "??? : "의 길이 ConvertEmpireText(m_bEmpire, m_conv_msg + 6, m_len_conv_msg - 6, 10); // 6은 "??? : "의 길이
} }
void operator() (LPDESC d) void operator() (LPDESC d)
@ -673,7 +673,7 @@ int CInputMain::Chat(LPCHARACTER ch, const char * data, size_t uiBytes)
return iExtraLen; return iExtraLen;
} }
// 채팅 금지 Affect 처리 // 채팅 금지 Affect 처리
const CAffect* pAffect = ch->FindAffect(AFFECT_BLOCK_CHAT); const CAffect* pAffect = ch->FindAffect(AFFECT_BLOCK_CHAT);
if (pAffect != NULL) if (pAffect != NULL)
@ -710,7 +710,7 @@ int CInputMain::Chat(LPCHARACTER ch, const char * data, size_t uiBytes)
if (NULL != pTable) if (NULL != pTable)
{ {
if (3==processReturn) //교환중 if (3==processReturn) //교환중
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB4\xD9\xB8\xA5 \xB0\xC5\xB7\xA1\xC1\xDF(\xC3\xA2\xB0\xED,\xB1\xB3\xC8\xAF,\xBB\xF3\xC1\xA1)\xBF\xA1\xB4\xC2 \xB0\xB3\xC0\xCE\xBB\xF3\xC1\xA1\xC0\xBB \xBB\xE7\xBF\xEB\xC7\xD2 \xBC\xF6 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9."), pTable->szLocaleName); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("\xB4\xD9\xB8\xA5 \xB0\xC5\xB7\xA1\xC1\xDF(\xC3\xA2\xB0\xED,\xB1\xB3\xC8\xAF,\xBB\xF3\xC1\xA1)\xBF\xA1\xB4\xC2 \xB0\xB3\xC0\xCE\xBB\xF3\xC1\xA1\xC0\xBB \xBB\xE7\xBF\xEB\xC7\xD2 \xBC\xF6 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9."), pTable->szLocaleName);
else else
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s\xC0\xCC \xC7\xCA\xBF\xE4\xC7\xD5\xB4\xCF\xB4\xD9."), pTable->szLocaleName); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s\xC0\xCC \xC7\xCA\xBF\xE4\xC7\xD5\xB4\xCF\xB4\xD9."), pTable->szLocaleName);
@ -843,7 +843,7 @@ void CInputMain::ItemDrop(LPCHARACTER ch, const char * data)
if (!ch) if (!ch)
return; return;
// 엘크가 0보다 크면 엘크를 버리는 것 이다. // 엘크가 0보다 크면 엘크를 버리는 것 이다.
if (pinfo->gold > 0) if (pinfo->gold > 0)
ch->DropGold(pinfo->gold); ch->DropGold(pinfo->gold);
else else
@ -859,7 +859,7 @@ void CInputMain::ItemDrop2(LPCHARACTER ch, const char * data)
TPacketCGItemDrop2 * pinfo = (TPacketCGItemDrop2 *) data; TPacketCGItemDrop2 * pinfo = (TPacketCGItemDrop2 *) data;
// 엘크가 0보다 크면 엘크를 버리는 것 이다. // 엘크가 0보다 크면 엘크를 버리는 것 이다.
if (!ch) if (!ch)
return; return;
@ -945,7 +945,7 @@ int CInputMain::Messenger(LPCHARACTER ch, const char* c_pData, size_t uiBytes)
return sizeof(TPacketCGMessengerAddByVID); return sizeof(TPacketCGMessengerAddByVID);
} }
if (ch->GetDesc() == d) // 자신은 추가할 수 없다. if (ch->GetDesc() == d) // 자신은 추가할 수 없다.
return sizeof(TPacketCGMessengerAddByVID); return sizeof(TPacketCGMessengerAddByVID);
MessengerManager::instance().RequestToAdd(ch, ch_companion); MessengerManager::instance().RequestToAdd(ch, ch_companion);
@ -973,7 +973,7 @@ int CInputMain::Messenger(LPCHARACTER ch, const char* c_pData, size_t uiBytes)
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s \xB4\xD4\xC0\xBA \xC1\xA2\xBC\xD3\xB5\xC7 \xC0\xD6\xC1\xF6 \xBE\xCA\xBD\xC0\xB4\xCF\xB4\xD9."), name); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s \xB4\xD4\xC0\xBA \xC1\xA2\xBC\xD3\xB5\xC7 \xC0\xD6\xC1\xF6 \xBE\xCA\xBD\xC0\xB4\xCF\xB4\xD9."), name);
else else
{ {
if (tch == ch) // 자신은 추가할 수 없다. if (tch == ch) // 자신은 추가할 수 없다.
return CHARACTER_NAME_MAX_LEN; return CHARACTER_NAME_MAX_LEN;
if (tch->IsBlockMode(BLOCK_MESSENGER_INVITE) == true) if (tch->IsBlockMode(BLOCK_MESSENGER_INVITE) == true)
@ -982,7 +982,7 @@ int CInputMain::Messenger(LPCHARACTER ch, const char* c_pData, size_t uiBytes)
} }
else else
{ {
// 메신저가 캐릭터단위가 되면서 변경 // 메신저가 캐릭터단위가 되면서 변경
MessengerManager::instance().RequestToAdd(ch, tch); MessengerManager::instance().RequestToAdd(ch, tch);
//MessengerManager::instance().AddToList(ch->GetName(), tch->GetName()); //MessengerManager::instance().AddToList(ch->GetName(), tch->GetName());
} }
@ -1268,7 +1268,7 @@ static const int ComboSequenceBySkillLevel[3][8] =
DWORD ClacValidComboInterval( LPCHARACTER ch, BYTE bArg ) DWORD ClacValidComboInterval( LPCHARACTER ch, BYTE bArg )
{ {
int nInterval = 300; int nInterval = 300;
float fAdjustNum = 1.5f; // 일반 유저가 speed hack 에 걸리는 것을 막기 위해. 2013.09.10 CYH float fAdjustNum = 1.5f; // 일반 유저가 speed hack 에 걸리는 것을 막기 위해. 2013.09.10 CYH
if( !ch ) if( !ch )
{ {
@ -1299,17 +1299,17 @@ DWORD ClacValidComboInterval( LPCHARACTER ch, BYTE bArg )
bool CheckComboHack(LPCHARACTER ch, BYTE bArg, DWORD dwTime, bool CheckSpeedHack) bool CheckComboHack(LPCHARACTER ch, BYTE bArg, DWORD dwTime, bool CheckSpeedHack)
{ {
// 죽거나 기절 상태에서는 공격할 수 없으므로, skip한다. // 죽거나 기절 상태에서는 공격할 수 없으므로, skip한다.
// 이렇게 하지 말고, CHRACTER::CanMove()에 // 이렇게 하지 말고, CHRACTER::CanMove()에
// if (IsStun() || IsDead()) return false; // if (IsStun() || IsDead()) return false;
// 를 추가하는게 맞다고 생각하나, // 를 추가하는게 맞다고 생각하나,
// 이미 다른 부분에서 CanMove()는 IsStun(), IsDead()과 // 이미 다른 부분에서 CanMove()는 IsStun(), IsDead()과
// 독립적으로 체크하고 있기 때문에 수정에 의한 영향을 // 독립적으로 체크하고 있기 때문에 수정에 의한 영향을
// 최소화하기 위해 이렇게 땜빵 코드를 써놓는다. // 최소화하기 위해 이렇게 땜빵 코드를 써놓는다.
if (ch->IsStun() || ch->IsDead()) if (ch->IsStun() || ch->IsDead())
return false; return false;
int ComboInterval = dwTime - ch->GetLastComboTime(); int ComboInterval = dwTime - ch->GetLastComboTime();
int HackScalar = 0; // 기본 스칼라 단위 1 int HackScalar = 0; // 기본 스칼라 단위 1
// [2013 09 11 CYH] debugging log // [2013 09 11 CYH] debugging log
/*SPDLOG_DEBUG("COMBO_TEST_LOG: {} arg:{} interval:{} valid:{} atkspd:{} riding:{}", /*SPDLOG_DEBUG("COMBO_TEST_LOG: {} arg:{} interval:{} valid:{} atkspd:{} riding:{}",
@ -1324,18 +1324,18 @@ bool CheckComboHack(LPCHARACTER ch, BYTE bArg, DWORD dwTime, bool CheckSpeedHack
SPDLOG_DEBUG("COMBO: {} arg:{} seq:{} delta:{} checkspeedhack:{}", SPDLOG_DEBUG("COMBO: {} arg:{} seq:{} delta:{} checkspeedhack:{}",
ch->GetName(), bArg, ch->GetComboSequence(), ComboInterval - ch->GetValidComboInterval(), CheckSpeedHack); ch->GetName(), bArg, ch->GetComboSequence(), ComboInterval - ch->GetValidComboInterval(), CheckSpeedHack);
#endif #endif
// bArg 14 ~ 21번 까지 총 8콤보 가능 // bArg 14 ~ 21번 까지 총 8콤보 가능
// 1. 첫 콤보(14)는 일정 시간 이후에 반복 가능 // 1. 첫 콤보(14)는 일정 시간 이후에 반복 가능
// 2. 15 ~ 21번은 반복 불가능 // 2. 15 ~ 21번은 반복 불가능
// 3. 차례대로 증가한다. // 3. 차례대로 증가한다.
if (bArg == 14) if (bArg == 14)
{ {
if (CheckSpeedHack && ComboInterval > 0 && ComboInterval < ch->GetValidComboInterval() - COMBO_HACK_ALLOWABLE_MS) if (CheckSpeedHack && ComboInterval > 0 && ComboInterval < ch->GetValidComboInterval() - COMBO_HACK_ALLOWABLE_MS)
{ {
// FIXME 첫번째 콤보는 이상하게 빨리 올 수가 있어서 300으로 나눔 -_-; // FIXME 첫번째 콤보는 이상하게 빨리 올 수가 있어서 300으로 나눔 -_-;
// 다수의 몬스터에 의해 다운되는 상황에서 공격을 하면 // 다수의 몬스터에 의해 다운되는 상황에서 공격을 하면
// 첫번째 콤보가 매우 적은 인터벌로 들어오는 상황 발생. // 첫번째 콤보가 매우 적은 인터벌로 들어오는 상황 발생.
// 이로 인해 콤보핵으로 튕기는 경우가 있어 다음 코드 비 활성화. // 이로 인해 콤보핵으로 튕기는 경우가 있어 다음 코드 비 활성화.
//HackScalar = 1 + (ch->GetValidComboInterval() - ComboInterval) / 300; //HackScalar = 1 + (ch->GetValidComboInterval() - ComboInterval) / 300;
//SPDLOG_WARN("COMBO_HACK: 2 {} arg:{} interval:{} valid:{} atkspd:{} riding:{}", //SPDLOG_WARN("COMBO_HACK: 2 {} arg:{} interval:{} valid:{} atkspd:{} riding:{}",
@ -1357,13 +1357,13 @@ bool CheckComboHack(LPCHARACTER ch, BYTE bArg, DWORD dwTime, bool CheckSpeedHack
{ {
int idx = std::min<int>(2, ch->GetComboIndex()); int idx = std::min<int>(2, ch->GetComboIndex());
if (ch->GetComboSequence() > 5) // 현재 6콤보 이상은 없다. if (ch->GetComboSequence() > 5) // 현재 6콤보 이상은 없다.
{ {
HackScalar = 1; HackScalar = 1;
ch->SetValidComboInterval(300); ch->SetValidComboInterval(300);
SPDLOG_WARN("COMBO_HACK: 5 {} combo_seq:{}", ch->GetName(), ch->GetComboSequence()); SPDLOG_WARN("COMBO_HACK: 5 {} combo_seq:{}", ch->GetName(), ch->GetComboSequence());
} }
// 자객 쌍수 콤보 예외처리 // 자객 쌍수 콤보 예외처리
else if (bArg == 21 && else if (bArg == 21 &&
idx == 2 && idx == 2 &&
ch->GetComboSequence() == 5 && ch->GetComboSequence() == 5 &&
@ -1398,7 +1398,7 @@ bool CheckComboHack(LPCHARACTER ch, BYTE bArg, DWORD dwTime, bool CheckSpeedHack
ch->IsRiding() ? "yes" : "no"); ch->IsRiding() ? "yes" : "no");
} }
// 말을 탔을 때는 15번 ~ 16번을 반복한다 // 말을 탔을 때는 15번 ~ 16번을 반복한다
//if (ch->IsHorseRiding()) //if (ch->IsHorseRiding())
if (ch->IsRiding()) if (ch->IsRiding())
ch->SetComboSequence(ch->GetComboSequence() == 1 ? 2 : 1); ch->SetComboSequence(ch->GetComboSequence() == 1 ? 2 : 1);
@ -1411,13 +1411,13 @@ bool CheckComboHack(LPCHARACTER ch, BYTE bArg, DWORD dwTime, bool CheckSpeedHack
ch->SetLastComboTime(dwTime); ch->SetLastComboTime(dwTime);
} }
} }
else if (bArg == 13) // 기본 공격 (둔갑(Polymorph)했을 때 온다) else if (bArg == 13) // 기본 공격 (둔갑(Polymorph)했을 때 온다)
{ {
if (CheckSpeedHack && ComboInterval > 0 && ComboInterval < ch->GetValidComboInterval() - COMBO_HACK_ALLOWABLE_MS) if (CheckSpeedHack && ComboInterval > 0 && ComboInterval < ch->GetValidComboInterval() - COMBO_HACK_ALLOWABLE_MS)
{ {
// 다수의 몬스터에 의해 다운되는 상황에서 공격을 하면 // 다수의 몬스터에 의해 다운되는 상황에서 공격을 하면
// 첫번째 콤보가 매우 적은 인터벌로 들어오는 상황 발생. // 첫번째 콤보가 매우 적은 인터벌로 들어오는 상황 발생.
// 이로 인해 콤보핵으로 튕기는 경우가 있어 다음 코드 비 활성화. // 이로 인해 콤보핵으로 튕기는 경우가 있어 다음 코드 비 활성화.
//HackScalar = 1 + (ch->GetValidComboInterval() - ComboInterval) / 100; //HackScalar = 1 + (ch->GetValidComboInterval() - ComboInterval) / 100;
//SPDLOG_WARN("COMBO_HACK: 6 {} arg:{} interval:{} valid:{} atkspd:{}", //SPDLOG_WARN("COMBO_HACK: 6 {} arg:{} interval:{} valid:{} atkspd:{}",
@ -1440,8 +1440,8 @@ bool CheckComboHack(LPCHARACTER ch, BYTE bArg, DWORD dwTime, bool CheckSpeedHack
SPDLOG_ERROR("cannot find motion by race {}", ch->GetRaceNum()); SPDLOG_ERROR("cannot find motion by race {}", ch->GetRaceNum());
else else
{ {
// 정상적 계산이라면 1000.f를 곱해야 하지만 클라이언트가 애니메이션 속도의 90%에서 // 정상적 계산이라면 1000.f를 곱해야 하지만 클라이언트가 애니메이션 속도의 90%에서
// 다음 애니메이션 블렌딩을 허용하므로 900.f를 곱한다. // 다음 애니메이션 블렌딩을 허용하므로 900.f를 곱한다.
int k = (int) (pkMotion->GetDuration() / ((float) ch->GetPoint(POINT_ATT_SPEED) / 100.f) * 900.f); int k = (int) (pkMotion->GetDuration() / ((float) ch->GetPoint(POINT_ATT_SPEED) / 100.f) * 900.f);
ch->SetValidComboInterval(k); ch->SetValidComboInterval(k);
ch->SetLastComboTime(dwTime); ch->SetLastComboTime(dwTime);
@ -1458,32 +1458,32 @@ bool CheckComboHack(LPCHARACTER ch, BYTE bArg, DWORD dwTime, bool CheckSpeedHack
} }
else else
{ {
// 말이 안되는 콤보가 왔다 해커일 가능성? // 말이 안되는 콤보가 왔다 해커일 가능성?
//if (ch->GetDesc()->DelayedDisconnect(Random::get(2, 9))) //if (ch->GetDesc()->DelayedDisconnect(Random::get(2, 9)))
//{ //{
// LogManager::instance().HackLog("Hacker", ch); // LogManager::instance().HackLog("Hacker", ch);
// SPDLOG_WARN("HACKER: {} arg {}", ch->GetName(), bArg); // SPDLOG_WARN("HACKER: {} arg {}", ch->GetName(), bArg);
//} //}
// 위 코드로 인해, 폴리모프를 푸는 중에 공격 하면, // 위 코드로 인해, 폴리모프를 푸는 중에 공격 하면,
// 가끔 핵으로 인식하는 경우가 있다. // 가끔 핵으로 인식하는 경우가 있다.
// 자세히 말혀면, // 자세히 말혀면,
// 서버에서 poly 0를 처리했지만, // 서버에서 poly 0를 처리했지만,
// 클라에서 그 패킷을 받기 전에, 몹을 공격. <- 즉, 몹인 상태에서 공격. // 클라에서 그 패킷을 받기 전에, 몹을 공격. <- 즉, 몹인 상태에서 공격.
// //
// 그러면 클라에서는 서버에 몹 상태로 공격했다는 커맨드를 보내고 (arg == 13) // 그러면 클라에서는 서버에 몹 상태로 공격했다는 커맨드를 보내고 (arg == 13)
// //
// 서버에서는 race는 인간인데 공격형태는 몹인 놈이다! 라고 하여 핵체크를 했다. // 서버에서는 race는 인간인데 공격형태는 몹인 놈이다! 라고 하여 핵체크를 했다.
// 사실 공격 패턴에 대한 것은 클라이언트에서 판단해서 보낼 것이 아니라, // 사실 공격 패턴에 대한 것은 클라이언트에서 판단해서 보낼 것이 아니라,
// 서버에서 판단해야 할 것인데... 왜 이렇게 해놨을까... // 서버에서 판단해야 할 것인데... 왜 이렇게 해놨을까...
// by rtsummit // by rtsummit
} }
} }
else else
{ {
// 말이 안되는 콤보가 왔다 해커일 가능성? // 말이 안되는 콤보가 왔다 해커일 가능성?
if (ch->GetDesc()->DelayedDisconnect(Random::get(2, 9))) if (ch->GetDesc()->DelayedDisconnect(Random::get(2, 9)))
{ {
LogManager::instance().HackLog("Hacker", ch); LogManager::instance().HackLog("Hacker", ch);
@ -1496,7 +1496,7 @@ bool CheckComboHack(LPCHARACTER ch, BYTE bArg, DWORD dwTime, bool CheckSpeedHack
if (HackScalar) if (HackScalar)
{ {
// 말에 타거나 내렸을 때 1.5초간 공격은 핵으로 간주하지 않되 공격력은 없게 하는 처리 // 말에 타거나 내렸을 때 1.5초간 공격은 핵으로 간주하지 않되 공격력은 없게 하는 처리
if (get_dword_time() - ch->GetLastMountTime() > 1500) if (get_dword_time() - ch->GetLastMountTime() > 1500)
ch->IncreaseComboHackCount(1 + HackScalar); ch->IncreaseComboHackCount(1 + HackScalar);
@ -1531,9 +1531,9 @@ void CInputMain::Move(LPCHARACTER ch, const char * data)
// FUNC_SKILL = 0x80, // FUNC_SKILL = 0x80,
//}; //};
// 텔레포트 핵 체크 // 텔레포트 핵 체크
// if (!test_server) //2012.05.15 김용욱 : 테섭에서 (무적상태로) 다수 몬스터 상대로 다운되면서 공격시 콤보핵으로 죽는 문제가 있었다. // if (!test_server) //2012.05.15 김용욱 : 테섭에서 (무적상태로) 다수 몬스터 상대로 다운되면서 공격시 콤보핵으로 죽는 문제가 있었다.
{ {
const float fDist = DISTANCE_SQRT((ch->GetX() - pinfo->lX) / 100, (ch->GetY() - pinfo->lY) / 100); const float fDist = DISTANCE_SQRT((ch->GetX() - pinfo->lX) / 100, (ch->GetY() - pinfo->lY) / 100);
@ -1544,7 +1544,7 @@ void CInputMain::Move(LPCHARACTER ch, const char * data)
const PIXEL_POSITION & warpPos = ch->GetWarpPosition(); const PIXEL_POSITION & warpPos = ch->GetWarpPosition();
if (warpPos.x == 0 && warpPos.y == 0) if (warpPos.x == 0 && warpPos.y == 0)
LogManager::instance().HackLog("Teleport", ch); // 부정확할 수 있음 LogManager::instance().HackLog("Teleport", ch); // 부정확할 수 있음
} }
SPDLOG_WARN("MOVE: {} trying to move too far (dist: {:.1f}m) Riding({})", ch->GetName(), fDist, ch->IsRiding()); SPDLOG_WARN("MOVE: {} trying to move too far (dist: {:.1f}m) Riding({})", ch->GetName(), fDist, ch->IsRiding());
@ -1555,10 +1555,10 @@ void CInputMain::Move(LPCHARACTER ch, const char * data)
} }
// //
// 스피드핵(SPEEDHACK) Check // 스피드핵(SPEEDHACK) Check
// //
DWORD dwCurTime = get_dword_time(); DWORD dwCurTime = get_dword_time();
// 시간을 Sync하고 7초 후 부터 검사한다. (20090702 이전엔 5초였음) // 시간을 Sync하고 7초 후 부터 검사한다. (20090702 이전엔 5초였음)
bool CheckSpeedHack = (false == ch->GetDesc()->IsHandshaking() && dwCurTime - ch->GetDesc()->GetClientTime() > 7000); bool CheckSpeedHack = (false == ch->GetDesc()->IsHandshaking() && dwCurTime - ch->GetDesc()->GetClientTime() > 7000);
if (CheckSpeedHack) if (CheckSpeedHack)
@ -1568,13 +1568,13 @@ void CInputMain::Move(LPCHARACTER ch, const char * data)
iDelta = (int) (dwCurTime - pinfo->dwTime); iDelta = (int) (dwCurTime - pinfo->dwTime);
// 시간이 늦게간다. 일단 로그만 해둔다. 진짜 이런 사람들이 많은지 체크해야함. TODO // 시간이 늦게간다. 일단 로그만 해둔다. 진짜 이런 사람들이 많은지 체크해야함. TODO
if (iDelta >= 30000) if (iDelta >= 30000)
{ {
SPDLOG_WARN("SPEEDHACK: slow timer name {} delta {}", ch->GetName(), iDelta); SPDLOG_WARN("SPEEDHACK: slow timer name {} delta {}", ch->GetName(), iDelta);
ch->GetDesc()->DelayedDisconnect(3); ch->GetDesc()->DelayedDisconnect(3);
} }
// 1초에 20msec 빨리 가는거 까지는 이해한다. // 1초에 20msec 빨리 가는거 까지는 이해한다.
else if (iDelta < -(iServerDelta / 50)) else if (iDelta < -(iServerDelta / 50))
{ {
SPDLOG_WARN("SPEEDHACK: DETECTED! {} (delta {} {})", ch->GetName(), iDelta, iServerDelta); SPDLOG_WARN("SPEEDHACK: DETECTED! {} (delta {} {})", ch->GetName(), iDelta, iServerDelta);
@ -1583,11 +1583,11 @@ void CInputMain::Move(LPCHARACTER ch, const char * data)
} }
// //
// 콤보핵 및 스피드핵 체크 // 콤보핵 및 스피드핵 체크
// //
if (pinfo->bFunc == FUNC_COMBO && g_bCheckMultiHack) if (pinfo->bFunc == FUNC_COMBO && g_bCheckMultiHack)
{ {
CheckComboHack(ch, pinfo->bArg, pinfo->dwTime, CheckSpeedHack); // 콤보 체크 CheckComboHack(ch, pinfo->bArg, pinfo->dwTime, CheckSpeedHack); // 콤보 체크
} }
} }
@ -1596,7 +1596,7 @@ void CInputMain::Move(LPCHARACTER ch, const char * data)
if (ch->GetLimitPoint(POINT_MOV_SPEED) == 0) if (ch->GetLimitPoint(POINT_MOV_SPEED) == 0)
return; return;
ch->SetRotation(pinfo->bRot * 5); // 중복 코드 ch->SetRotation(pinfo->bRot * 5); // 중복 코드
ch->ResetStopTime(); // "" ch->ResetStopTime(); // ""
ch->Goto(pinfo->lX, pinfo->lY); ch->Goto(pinfo->lX, pinfo->lY);
@ -1635,7 +1635,7 @@ void CInputMain::Move(LPCHARACTER ch, const char * data)
ch->OnMove(); ch->OnMove();
} }
ch->SetRotation(pinfo->bRot * 5); // 중복 코드 ch->SetRotation(pinfo->bRot * 5); // 중복 코드
ch->ResetStopTime(); // "" ch->ResetStopTime(); // ""
ch->Move(pinfo->lX, pinfo->lY); ch->Move(pinfo->lX, pinfo->lY);
@ -1657,13 +1657,13 @@ void CInputMain::Move(LPCHARACTER ch, const char * data)
ch->PacketAround(&pack, sizeof(TPacketGCMove), ch); ch->PacketAround(&pack, sizeof(TPacketGCMove), ch);
/* /*
if (pinfo->dwTime == 10653691) // 디버거 발견 if (pinfo->dwTime == 10653691) // 디버거 발견
{ {
if (ch->GetDesc()->DelayedDisconnect(Random::get(15, 30))) if (ch->GetDesc()->DelayedDisconnect(Random::get(15, 30)))
LogManager::instance().HackLog("Debugger", ch); LogManager::instance().HackLog("Debugger", ch);
} }
else if (pinfo->dwTime == 10653971) // Softice 발견 else if (pinfo->dwTime == 10653971) // Softice 발견
{ {
if (ch->GetDesc()->DelayedDisconnect(Random::get(15, 30))) if (ch->GetDesc()->DelayedDisconnect(Random::get(15, 30)))
LogManager::instance().HackLog("Softice", ch); LogManager::instance().HackLog("Softice", ch);
@ -1839,20 +1839,20 @@ int CInputMain::SyncPosition(LPCHARACTER ch, const char * c_pcData, size_t uiByt
continue; continue;
} }
// 소유권 검사 // 소유권 검사
if (!victim->SetSyncOwner(ch)) if (!victim->SetSyncOwner(ch))
continue; continue;
const float fDistWithSyncOwner = DISTANCE_SQRT( (victim->GetX() - ch->GetX()) / 100, (victim->GetY() - ch->GetY()) / 100 ); const float fDistWithSyncOwner = DISTANCE_SQRT( (victim->GetX() - ch->GetX()) / 100, (victim->GetY() - ch->GetY()) / 100 );
static const float fLimitDistWithSyncOwner = 2500.f + 1000.f; static const float fLimitDistWithSyncOwner = 2500.f + 1000.f;
// victim과의 거리가 2500 + a 이상이면 핵으로 간주. // victim과의 거리가 2500 + a 이상이면 핵으로 간주.
// 거리 참조 : 클라이언트의 __GetSkillTargetRange, __GetBowRange 함수 // 거리 참조 : 클라이언트의 __GetSkillTargetRange, __GetBowRange 함수
// 2500 : 스킬 proto에서 가장 사거리가 긴 스킬의 사거리, 또는 활의 사거리 // 2500 : 스킬 proto에서 가장 사거리가 긴 스킬의 사거리, 또는 활의 사거리
// a = POINT_BOW_DISTANCE 값... 인데 실제로 사용하는 값인지는 잘 모르겠음. 아이템이나 포션, 스킬, 퀘스트에는 없는데... // a = POINT_BOW_DISTANCE 값... 인데 실제로 사용하는 값인지는 잘 모르겠음. 아이템이나 포션, 스킬, 퀘스트에는 없는데...
// 그래도 혹시나 하는 마음에 버퍼로 사용할 겸해서 1000.f 로 둠... // 그래도 혹시나 하는 마음에 버퍼로 사용할 겸해서 1000.f 로 둠...
if (fDistWithSyncOwner > fLimitDistWithSyncOwner) if (fDistWithSyncOwner > fLimitDistWithSyncOwner)
{ {
// g_iSyncHackLimitCount번 까지는 봐줌. // g_iSyncHackLimitCount번 까지는 봐줌.
if (ch->GetSyncHackCount() < g_iSyncHackLimitCount) if (ch->GetSyncHackCount() < g_iSyncHackLimitCount)
{ {
ch->SetSyncHackCount(ch->GetSyncHackCount() + 1); ch->SetSyncHackCount(ch->GetSyncHackCount() + 1);
@ -1877,11 +1877,11 @@ int CInputMain::SyncPosition(LPCHARACTER ch, const char * c_pcData, size_t uiByt
const timeval &tvLastSyncTime = victim->GetLastSyncTime(); const timeval &tvLastSyncTime = victim->GetLastSyncTime();
timeval *tvDiff = timediff(&tvCurTime, &tvLastSyncTime); timeval *tvDiff = timediff(&tvCurTime, &tvLastSyncTime);
// SyncPosition을 악용하여 타유저를 이상한 곳으로 보내는 핵 방어하기 위하여, // SyncPosition을 악용하여 타유저를 이상한 곳으로 보내는 핵 방어하기 위하여,
// 같은 유저를 g_lValidSyncInterval ms 이내에 다시 SyncPosition하려고 하면 핵으로 간주. // 같은 유저를 g_lValidSyncInterval ms 이내에 다시 SyncPosition하려고 하면 핵으로 간주.
if (tvDiff->tv_sec == 0 && tvDiff->tv_usec < g_lValidSyncInterval) if (tvDiff->tv_sec == 0 && tvDiff->tv_usec < g_lValidSyncInterval)
{ {
// g_iSyncHackLimitCount번 까지는 봐줌. // g_iSyncHackLimitCount번 까지는 봐줌.
if (ch->GetSyncHackCount() < g_iSyncHackLimitCount) if (ch->GetSyncHackCount() < g_iSyncHackLimitCount)
{ {
ch->SetSyncHackCount(ch->GetSyncHackCount() + 1); ch->SetSyncHackCount(ch->GetSyncHackCount() + 1);
@ -1968,11 +1968,11 @@ void CInputMain::ScriptAnswer(LPCHARACTER ch, const void* c_pData)
TPacketCGScriptAnswer * p = (TPacketCGScriptAnswer *) c_pData; TPacketCGScriptAnswer * p = (TPacketCGScriptAnswer *) c_pData;
SPDLOG_DEBUG("QUEST ScriptAnswer pid {} answer {}", ch->GetPlayerID(), p->answer); SPDLOG_DEBUG("QUEST ScriptAnswer pid {} answer {}", ch->GetPlayerID(), p->answer);
if (p->answer > 250) // 다음 버튼에 대한 응답으로 온 패킷인 경우 if (p->answer > 250) // 다음 버튼에 대한 응답으로 온 패킷인 경우
{ {
quest::CQuestManager::Instance().Resume(ch->GetPlayerID()); quest::CQuestManager::Instance().Resume(ch->GetPlayerID());
} }
else // 선택 버튼을 골라서 온 패킷인 경우 else // 선택 버튼을 골라서 온 패킷인 경우
{ {
quest::CQuestManager::Instance().Select(ch->GetPlayerID(), p->answer); quest::CQuestManager::Instance().Select(ch->GetPlayerID(), p->answer);
} }
@ -2115,9 +2115,9 @@ void CInputMain::SafeboxCheckout(LPCHARACTER ch, const char * c_pData, bool bMal
if (!ch->IsEmptyItemGrid(p->ItemPos, pkItem->GetSize())) if (!ch->IsEmptyItemGrid(p->ItemPos, pkItem->GetSize()))
return; return;
// 아이템 몰에서 인벤으로 옮기는 부분에서 용혼석 특수 처리 // 아이템 몰에서 인벤으로 옮기는 부분에서 용혼석 특수 처리
// (몰에서 만드는 아이템은 item_proto에 정의된대로 속성이 붙기 때문에, // (몰에서 만드는 아이템은 item_proto에 정의된대로 속성이 붙기 때문에,
// 용혼석의 경우, 이 처리를 하지 않으면 속성이 하나도 붙지 않게 된다.) // 용혼석의 경우, 이 처리를 하지 않으면 속성이 하나도 붙지 않게 된다.)
if (pkItem->IsDragonSoul()) if (pkItem->IsDragonSoul())
{ {
if (bMall) if (bMall)
@ -2163,7 +2163,7 @@ void CInputMain::SafeboxCheckout(LPCHARACTER ch, const char * c_pData, bool bMal
SPDLOG_ERROR("pkItem->GetProto() == NULL (id : {})",pkItem->GetID()); SPDLOG_ERROR("pkItem->GetProto() == NULL (id : {})",pkItem->GetID());
return ; return ;
} }
// 100% 확률로 속성이 붙어야 하는데 안 붙어있다면 새로 붙힌다. ............... // 100% 확률로 속성이 붙어야 하는데 안 붙어있다면 새로 붙힌다. ...............
if (100 == pkItem->GetProto()->bAlterToMagicItemPct && 0 == pkItem->GetAttributeCount()) if (100 == pkItem->GetProto()->bAlterToMagicItemPct && 0 == pkItem->GetAttributeCount())
{ {
pkItem->AlterToMagicItem(); pkItem->AlterToMagicItem();
@ -2232,7 +2232,7 @@ void CInputMain::PartyInviteAnswer(LPCHARACTER ch, const char * c_pData)
LPCHARACTER pInviter = CHARACTER_MANAGER::instance().Find(p->leader_vid); LPCHARACTER pInviter = CHARACTER_MANAGER::instance().Find(p->leader_vid);
// pInviter 가 ch 에게 파티 요청을 했었다. // pInviter 가 ch 에게 파티 요청을 했었다.
if (!pInviter) if (!pInviter)
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<\xC6\xC4\xC6\xBC> \xC6\xC4\xC6\xBC\xBF\xE4\xC3\xBB\xC0\xBB \xC7\xD1 \xC4\xB3\xB8\xAF\xC5\xCD\xB8\xA6 \xC3\xA3\xC0\xBB\xBC\xF6 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9.")); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<\xC6\xC4\xC6\xBC> \xC6\xC4\xC6\xBC\xBF\xE4\xC3\xBB\xC0\xBB \xC7\xD1 \xC4\xB3\xB8\xAF\xC5\xCD\xB8\xA6 \xC3\xA3\xC0\xBB\xBC\xF6 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9."));
@ -2554,7 +2554,7 @@ int CInputMain::Guild(LPCHARACTER ch, const char * data, size_t uiBytes)
{ {
case GUILD_SUBHEADER_CG_DEPOSIT_MONEY: case GUILD_SUBHEADER_CG_DEPOSIT_MONEY:
{ {
// by mhh : 길드자금은 당분간 넣을 수 없다. // by mhh : 길드자금은 당분간 넣을 수 없다.
return SubPacketLen; return SubPacketLen;
const int gold = std::min(*reinterpret_cast<const int*>(c_pData), __deposit_limit()); const int gold = std::min(*reinterpret_cast<const int*>(c_pData), __deposit_limit());
@ -2577,7 +2577,7 @@ int CInputMain::Guild(LPCHARACTER ch, const char * data, size_t uiBytes)
case GUILD_SUBHEADER_CG_WITHDRAW_MONEY: case GUILD_SUBHEADER_CG_WITHDRAW_MONEY:
{ {
// by mhh : 길드자금은 당분간 뺄 수 없다. // by mhh : 길드자금은 당분간 뺄 수 없다.
return SubPacketLen; return SubPacketLen;
const int gold = std::min(*reinterpret_cast<const int*>(c_pData), 500000); const int gold = std::min(*reinterpret_cast<const int*>(c_pData), 500000);
@ -2773,7 +2773,7 @@ int CInputMain::Guild(LPCHARACTER ch, const char * data, size_t uiBytes)
if (length > GUILD_COMMENT_MAX_LEN) if (length > GUILD_COMMENT_MAX_LEN)
{ {
// 잘못된 길이.. 끊어주자. // 잘못된 길이.. 끊어주자.
SPDLOG_ERROR("POST_COMMENT: {} comment too long (length: {})", ch->GetName(), length); SPDLOG_ERROR("POST_COMMENT: {} comment too long (length: {})", ch->GetName(), length);
ch->GetDesc()->SetPhase(PHASE_CLOSE); ch->GetDesc()->SetPhase(PHASE_CLOSE);
return -1; return -1;

View File

@ -67,7 +67,7 @@ int CInputP2P::Relay(LPDESC d, const char * c_pData, size_t uiBytes)
{ {
if (pkChr->IsBlockMode(BLOCK_WHISPER)) if (pkChr->IsBlockMode(BLOCK_WHISPER))
{ {
// 귓속말 거부 상태에서 귓속말 거부. // 귓속말 거부 상태에서 귓속말 거부.
return p->lSize; return p->lSize;
} }
@ -75,12 +75,12 @@ int CInputP2P::Relay(LPDESC d, const char * c_pData, size_t uiBytes)
memcpy(buf, c_pbData, std::min<size_t>(p->lSize, sizeof(buf))); memcpy(buf, c_pbData, std::min<size_t>(p->lSize, sizeof(buf)));
TPacketGCWhisper* p2 = (TPacketGCWhisper*) buf; TPacketGCWhisper* p2 = (TPacketGCWhisper*) buf;
// bType 상위 4비트: Empire 번호 // bType 상위 4비트: Empire 번호
// bType 하위 4비트: EWhisperType // bType 하위 4비트: EWhisperType
BYTE bToEmpire = (p2->bType >> 4); BYTE bToEmpire = (p2->bType >> 4);
p2->bType = p2->bType & 0x0F; p2->bType = p2->bType & 0x0F;
if(p2->bType == 0x0F) { if(p2->bType == 0x0F) {
// 시스템 메세지 귓속말은 bType의 상위비트까지 모두 사용함. // 시스템 메세지 귓속말은 bType의 상위비트까지 모두 사용함.
p2->bType = WHISPER_TYPE_SYSTEM; p2->bType = WHISPER_TYPE_SYSTEM;
} else { } else {
if (!pkChr->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE)) if (!pkChr->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE))
@ -338,7 +338,7 @@ void CInputP2P::XmasWarpSanta(const char * c_pData)
else else
iNextSpawnDelay = 50 * 60; iNextSpawnDelay = 50 * 60;
xmas::SpawnSanta(p->lMapIndex, iNextSpawnDelay); // 50분있다가 새로운 산타가 나타남 (한국은 20분) xmas::SpawnSanta(p->lMapIndex, iNextSpawnDelay); // 50분있다가 새로운 산타가 나타남 (한국은 20분)
TPacketGGXmasWarpSantaReply pack_reply; TPacketGGXmasWarpSantaReply pack_reply;
pack_reply.bHeader = HEADER_GG_XMAS_WARP_SANTA_REPLY; pack_reply.bHeader = HEADER_GG_XMAS_WARP_SANTA_REPLY;

View File

@ -294,7 +294,7 @@ LPITEM CItem::RemoveFromCharacter()
LPCHARACTER pOwner = m_pOwner; LPCHARACTER pOwner = m_pOwner;
if (m_bEquipped) // 장착되었는가? if (m_bEquipped) // 장착되었는가?
{ {
Unequip(); Unequip();
//pOwner->UpdatePacket(); //pOwner->UpdatePacket();
@ -318,7 +318,7 @@ LPITEM CItem::RemoveFromCharacter()
{ {
TItemPos cell(INVENTORY, m_wCell); TItemPos cell(INVENTORY, m_wCell);
if (false == cell.IsDefaultInventoryPosition() && false == cell.IsBeltInventoryPosition()) // 아니면 소지품에? if (false == cell.IsDefaultInventoryPosition() && false == cell.IsBeltInventoryPosition()) // 아니면 소지품에?
SPDLOG_ERROR("CItem::RemoveFromCharacter: Invalid Item Position"); SPDLOG_ERROR("CItem::RemoveFromCharacter: Invalid Item Position");
else else
{ {
@ -470,16 +470,16 @@ bool CItem::CanUsedBy(LPCHARACTER ch)
int CItem::FindEquipCell(LPCHARACTER ch, int iCandidateCell) int CItem::FindEquipCell(LPCHARACTER ch, int iCandidateCell)
{ {
// 코스츔 아이템(ITEM_COSTUME)은 WearFlag 없어도 됨. (sub type으로 착용위치 구분. 귀찮게 또 wear flag 줄 필요가 있나..) // 코스츔 아이템(ITEM_COSTUME)은 WearFlag 없어도 됨. (sub type으로 착용위치 구분. 귀찮게 또 wear flag 줄 필요가 있나..)
// 용혼석(ITEM_DS, ITEM_SPECIAL_DS)도 SUB_TYPE으로 구분. 신규 반지, 벨트는 ITEM_TYPE으로 구분 -_- // 용혼석(ITEM_DS, ITEM_SPECIAL_DS)도 SUB_TYPE으로 구분. 신규 반지, 벨트는 ITEM_TYPE으로 구분 -_-
if ((0 == GetWearFlag() || ITEM_TOTEM == GetType()) && ITEM_COSTUME != GetType() && ITEM_DS != GetType() && ITEM_SPECIAL_DS != GetType() && ITEM_RING != GetType() && ITEM_BELT != GetType()) if ((0 == GetWearFlag() || ITEM_TOTEM == GetType()) && ITEM_COSTUME != GetType() && ITEM_DS != GetType() && ITEM_SPECIAL_DS != GetType() && ITEM_RING != GetType() && ITEM_BELT != GetType())
return -1; return -1;
// 용혼석 슬롯을 WEAR로 처리할 수가 없어서(WEAR는 최대 32개까지 가능한데 용혼석을 추가하면 32가 넘는다.) // 용혼석 슬롯을 WEAR로 처리할 수가 없어서(WEAR는 최대 32개까지 가능한데 용혼석을 추가하면 32가 넘는다.)
// 인벤토리의 특정 위치((INVENTORY_MAX_NUM + WEAR_MAX_NUM)부터 (INVENTORY_MAX_NUM + WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX - 1)까지)를 // 인벤토리의 특정 위치((INVENTORY_MAX_NUM + WEAR_MAX_NUM)부터 (INVENTORY_MAX_NUM + WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX - 1)까지)를
// 용혼석 슬롯으로 정함. // 용혼석 슬롯으로 정함.
// return 할 때에, INVENTORY_MAX_NUM을 뺀 이유는, // return 할 때에, INVENTORY_MAX_NUM을 뺀 이유는,
// 본래 WearCell이 INVENTORY_MAX_NUM를 빼고 return 하기 때문. // 본래 WearCell이 INVENTORY_MAX_NUM를 빼고 return 하기 때문.
if (GetType() == ITEM_DS || GetType() == ITEM_SPECIAL_DS) if (GetType() == ITEM_DS || GetType() == ITEM_SPECIAL_DS)
{ {
if (iCandidateCell < 0) if (iCandidateCell < 0)
@ -540,7 +540,7 @@ int CItem::FindEquipCell(LPCHARACTER ch, int iCandidateCell)
return WEAR_UNIQUE1; return WEAR_UNIQUE1;
} }
// 수집 퀘스트를 위한 아이템이 박히는곳으로 한번 박히면 절대 ?E수 없다. // 수집 퀘스트를 위한 아이템이 박히는곳으로 한번 박히면 절대 ?E수 없다.
else if (GetWearFlag() & WEARABLE_ABILITY) else if (GetWearFlag() & WEARABLE_ABILITY)
{ {
if (!ch->GetWear(WEAR_ABILITY1)) if (!ch->GetWear(WEAR_ABILITY1))
@ -587,12 +587,12 @@ void CItem::ModifyPoints(bool bAdd)
{ {
int accessoryGrade; int accessoryGrade;
// 무기와 갑옷만 소켓을 적용시킨다. // 무기와 갑옷만 소켓을 적용시킨다.
if (false == IsAccessoryForSocket()) if (false == IsAccessoryForSocket())
{ {
if (m_pProto->bType == ITEM_WEAPON || m_pProto->bType == ITEM_ARMOR) if (m_pProto->bType == ITEM_WEAPON || m_pProto->bType == ITEM_ARMOR)
{ {
// 소켓이 속성강화에 사용되는 경우 적용하지 않는다 (ARMOR_WRIST ARMOR_NECK ARMOR_EAR) // 소켓이 속성강화에 사용되는 경우 적용하지 않는다 (ARMOR_WRIST ARMOR_NECK ARMOR_EAR)
for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i) for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
{ {
DWORD dwVnum; DWORD dwVnum;
@ -651,12 +651,12 @@ void CItem::ModifyPoints(bool bAdd)
m_pOwner->ApplyPoint(m_pProto->aApplies[i].bType, bAdd ? value : -value); m_pOwner->ApplyPoint(m_pProto->aApplies[i].bType, bAdd ? value : -value);
} }
} }
// 초승달의 반지, 할로윈 사탕, 행복의 반지, 영원한 사랑의 펜던트의 경우 // 초승달의 반지, 할로윈 사탕, 행복의 반지, 영원한 사랑의 펜던트의 경우
// 기존의 하드 코딩으로 강제로 속성을 부여했지만, // 기존의 하드 코딩으로 강제로 속성을 부여했지만,
// 그 부분을 제거하고 special item group 테이블에서 속성을 부여하도록 변경하였다. // 그 부분을 제거하고 special item group 테이블에서 속성을 부여하도록 변경하였다.
// 하지만 하드 코딩되어있을 때 생성된 아이템이 남아있을 수도 있어서 특수처리 해놓는다. // 하지만 하드 코딩되어있을 때 생성된 아이템이 남아있을 수도 있어서 특수처리 해놓는다.
// 이 아이템들의 경우, 밑에 ITEM_UNIQUE일 때의 처리로 속성이 부여되기 때문에, // 이 아이템들의 경우, 밑에 ITEM_UNIQUE일 때의 처리로 속성이 부여되기 때문에,
// 아이템에 박혀있는 attribute는 적용하지 않고 넘어간다. // 아이템에 박혀있는 attribute는 적용하지 않고 넘어간다.
if (true == CItemVnumHelper::IsRamadanMoonRing(GetVnum()) || true == CItemVnumHelper::IsHalloweenCandy(GetVnum()) if (true == CItemVnumHelper::IsRamadanMoonRing(GetVnum()) || true == CItemVnumHelper::IsHalloweenCandy(GetVnum())
|| true == CItemVnumHelper::IsHappinessRing(GetVnum()) || true == CItemVnumHelper::IsLovePendant(GetVnum())) || true == CItemVnumHelper::IsHappinessRing(GetVnum()) || true == CItemVnumHelper::IsLovePendant(GetVnum()))
{ {
@ -713,7 +713,7 @@ void CItem::ModifyPoints(bool bAdd)
case ITEM_ARMOR: case ITEM_ARMOR:
{ {
// 코스츔 body를 입고있다면 armor는 벗던 입던 상관 없이 비주얼에 영향을 주면 안 됨. // 코스츔 body를 입고있다면 armor는 벗던 입던 상관 없이 비주얼에 영향을 주면 안 됨.
if (0 != m_pOwner->GetWear(WEAR_COSTUME_BODY)) if (0 != m_pOwner->GetWear(WEAR_COSTUME_BODY))
break; break;
@ -733,33 +733,33 @@ void CItem::ModifyPoints(bool bAdd)
} }
break; break;
// 코스츔 아이템 입었을 때 캐릭터 parts 정보 세팅. 기존 스타일대로 추가함.. // 코스츔 아이템 입었을 때 캐릭터 parts 정보 세팅. 기존 스타일대로 추가함..
case ITEM_COSTUME: case ITEM_COSTUME:
{ {
DWORD toSetValue = this->GetVnum(); DWORD toSetValue = this->GetVnum();
EParts toSetPart = PART_MAX_NUM; EParts toSetPart = PART_MAX_NUM;
// 갑옷 코스츔 // 갑옷 코스츔
if (GetSubType() == COSTUME_BODY) if (GetSubType() == COSTUME_BODY)
{ {
toSetPart = PART_MAIN; toSetPart = PART_MAIN;
if (false == bAdd) if (false == bAdd)
{ {
// 코스츔 갑옷을 벗었을 때 원래 갑옷을 입고 있었다면 그 갑옷으로 look 세팅, 입지 않았다면 default look // 코스츔 갑옷을 벗었을 때 원래 갑옷을 입고 있었다면 그 갑옷으로 look 세팅, 입지 않았다면 default look
const CItem* pArmor = m_pOwner->GetWear(WEAR_BODY); const CItem* pArmor = m_pOwner->GetWear(WEAR_BODY);
toSetValue = (NULL != pArmor) ? pArmor->GetVnum() : m_pOwner->GetOriginalPart(PART_MAIN); toSetValue = (NULL != pArmor) ? pArmor->GetVnum() : m_pOwner->GetOriginalPart(PART_MAIN);
} }
} }
// 헤어 코스츔 // 헤어 코스츔
else if (GetSubType() == COSTUME_HAIR) else if (GetSubType() == COSTUME_HAIR)
{ {
toSetPart = PART_HAIR; toSetPart = PART_HAIR;
// 코스츔 헤어는 shape값을 item proto의 value3에 세팅하도록 함. 특별한 이유는 없고 기존 갑옷(ARMOR_BODY)의 shape값이 프로토의 value3에 있어서 헤어도 같이 value3으로 함. // 코스츔 헤어는 shape값을 item proto의 value3에 세팅하도록 함. 특별한 이유는 없고 기존 갑옷(ARMOR_BODY)의 shape값이 프로토의 value3에 있어서 헤어도 같이 value3으로 함.
// [NOTE] 갑옷은 아이템 vnum을 보내고 헤어는 shape(value3)값을 보내는 이유는.. 기존 시스템이 그렇게 되어있음... // [NOTE] 갑옷은 아이템 vnum을 보내고 헤어는 shape(value3)값을 보내는 이유는.. 기존 시스템이 그렇게 되어있음...
toSetValue = (true == bAdd) ? this->GetValue(3) : 0; toSetValue = (true == bAdd) ? this->GetValue(3) : 0;
} }
@ -820,7 +820,7 @@ bool CItem::EquipTo(LPCHARACTER ch, BYTE bWearCell)
return false; return false;
} }
// 용혼석 슬롯 index는 WEAR_MAX_NUM 보다 큼. // 용혼석 슬롯 index는 WEAR_MAX_NUM 보다 큼.
if (IsDragonSoul()) if (IsDragonSoul())
{ {
if (bWearCell < WEAR_MAX_NUM || bWearCell >= WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX) if (bWearCell < WEAR_MAX_NUM || bWearCell >= WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX)
@ -847,7 +847,7 @@ bool CItem::EquipTo(LPCHARACTER ch, BYTE bWearCell)
if (GetOwner()) if (GetOwner())
RemoveFromCharacter(); RemoveFromCharacter();
ch->SetWear(bWearCell, this); // 여기서 패킷 나감 ch->SetWear(bWearCell, this); // 여기서 패킷 나감
m_pOwner = ch; m_pOwner = ch;
m_bEquipped = true; m_bEquipped = true;
@ -905,7 +905,7 @@ bool CItem::Unequip()
return false; return false;
} }
//신규 말 아이템 제거시 처리 //신규 말 아이템 제거시 처리
if (IsRideItem()) if (IsRideItem())
ClearMountAttributeAndAffect(); ClearMountAttributeAndAffect();
@ -1209,7 +1209,7 @@ void CItem::AlterToMagicItem()
} }
} }
// 100% 확률로 좋은 속성 하나 // 100% 확률로 좋은 속성 하나
PutAttribute(aiItemMagicAttributePercentHigh); PutAttribute(aiItemMagicAttributePercentHigh);
if (Random::get(1, 100) <= iSecondPct) if (Random::get(1, 100) <= iSecondPct)
@ -1295,8 +1295,8 @@ EVENTFUNC(unique_expire_event)
} }
else else
{ {
// 게임 내에 시간제 아이템들이 빠릿빠릿하게 사라지지 않는 버그가 있어 // 게임 내에 시간제 아이템들이 빠릿빠릿하게 사라지지 않는 버그가 있어
// 수정 // 수정
// by rtsummit // by rtsummit
if (pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - cur < 600) if (pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - cur < 600)
return PASSES_PER_SEC(pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - cur); return PASSES_PER_SEC(pkItem->GetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME) - cur);
@ -1306,9 +1306,9 @@ EVENTFUNC(unique_expire_event)
} }
} }
// 시간 후불제 // 시간 후불제
// timer를 시작할 때에 시간 차감하는 것이 아니라, // timer를 시작할 때에 시간 차감하는 것이 아니라,
// timer가 발화할 때에 timer가 동작한 시간 만큼 시간 차감을 한다. // timer가 발화할 때에 timer가 동작한 시간 만큼 시간 차감을 한다.
EVENTFUNC(timer_based_on_wear_expire_event) EVENTFUNC(timer_based_on_wear_expire_event)
{ {
item_event_info* info = dynamic_cast<item_event_info*>( event->info ); item_event_info* info = dynamic_cast<item_event_info*>( event->info );
@ -1327,7 +1327,7 @@ EVENTFUNC(timer_based_on_wear_expire_event)
pkItem->SetTimerBasedOnWearExpireEvent(NULL); pkItem->SetTimerBasedOnWearExpireEvent(NULL);
pkItem->SetSocket(ITEM_SOCKET_REMAIN_SEC, 0); pkItem->SetSocket(ITEM_SOCKET_REMAIN_SEC, 0);
// 일단 timer based on wear 용혼석은 시간 다 되었다고 없애지 않는다. // 일단 timer based on wear 용혼석은 시간 다 되었다고 없애지 않는다.
if (pkItem->IsDragonSoul()) if (pkItem->IsDragonSoul())
{ {
DSManager::instance().DeactivateDragonSoul(pkItem); DSManager::instance().DeactivateDragonSoul(pkItem);
@ -1419,7 +1419,7 @@ void CItem::StartUniqueExpireEvent()
if (m_pkUniqueExpireEvent) if (m_pkUniqueExpireEvent)
return; return;
//기간제 아이템일 경우 시간제 아이템은 동작하지 않는다 //기간제 아이템일 경우 시간제 아이템은 동작하지 않는다
if (IsRealTimeItem()) if (IsRealTimeItem())
return; return;
@ -1442,14 +1442,14 @@ void CItem::StartUniqueExpireEvent()
SetUniqueExpireEvent(event_create(unique_expire_event, info, PASSES_PER_SEC(iSec))); SetUniqueExpireEvent(event_create(unique_expire_event, info, PASSES_PER_SEC(iSec)));
} }
// 시간 후불제 // 시간 후불제
// timer_based_on_wear_expire_event 설명 참조 // timer_based_on_wear_expire_event 설명 참조
void CItem::StartTimerBasedOnWearExpireEvent() void CItem::StartTimerBasedOnWearExpireEvent()
{ {
if (m_pkTimerBasedOnWearExpireEvent) if (m_pkTimerBasedOnWearExpireEvent)
return; return;
//기간제 아이템일 경우 시간제 아이템은 동작하지 않는다 //기간제 아이템일 경우 시간제 아이템은 동작하지 않는다
if (IsRealTimeItem()) if (IsRealTimeItem())
return; return;
@ -1458,7 +1458,7 @@ void CItem::StartTimerBasedOnWearExpireEvent()
int iSec = GetSocket(0); int iSec = GetSocket(0);
// 남은 시간을 분단위로 끊기 위해... // 남은 시간을 분단위로 끊기 위해...
if (0 != iSec) if (0 != iSec)
{ {
iSec %= 60; iSec %= 60;
@ -1477,7 +1477,7 @@ void CItem::StopUniqueExpireEvent()
if (!m_pkUniqueExpireEvent) if (!m_pkUniqueExpireEvent)
return; return;
if (GetValue(2) != 0) // 게임시간제 이외의 아이템은 UniqueExpireEvent를 중단할 수 없다. if (GetValue(2) != 0) // 게임시간제 이외의 아이템은 UniqueExpireEvent를 중단할 수 없다.
return; return;
// HARD CODING // HARD CODING
@ -1514,12 +1514,12 @@ int CItem::GetSpecialGroup() const
} }
// //
// 악세서리 소켓 처리. // 악세서리 소켓 처리.
// //
bool CItem::IsAccessoryForSocket() bool CItem::IsAccessoryForSocket()
{ {
return (m_pProto->bType == ITEM_ARMOR && (m_pProto->bSubType == ARMOR_WRIST || m_pProto->bSubType == ARMOR_NECK || m_pProto->bSubType == ARMOR_EAR)) || return (m_pProto->bType == ITEM_ARMOR && (m_pProto->bSubType == ARMOR_WRIST || m_pProto->bSubType == ARMOR_NECK || m_pProto->bSubType == ARMOR_EAR)) ||
(m_pProto->bType == ITEM_BELT); // 2013년 2월 새로 추가된 '벨트' 아이템의 경우 기획팀에서 악세서리 소켓 시스템을 그대로 이용하자고 함. (m_pProto->bType == ITEM_BELT); // 2013년 2월 새로 추가된 '벨트' 아이템의 경우 기획팀에서 악세서리 소켓 시스템을 그대로 이용하자고 함.
} }
void CItem::SetAccessorySocketGrade(int iGrade) void CItem::SetAccessorySocketGrade(int iGrade)
@ -1664,7 +1664,7 @@ void CItem::ClearMountAttributeAndAffect()
} }
// fixme // fixme
// 이거 지금은 안쓴데... 근데 혹시나 싶어서 남겨둠. // 이거 지금은 안쓴데... 근데 혹시나 싶어서 남겨둠.
// by rtsummit // by rtsummit
bool CItem::IsNewMountItem() bool CItem::IsNewMountItem()
{ {
@ -1711,7 +1711,7 @@ void CItem::AccessorySocketDegrade()
} }
} }
// ring에 item을 박을 수 있는지 여부를 체크해서 리턴 // ring에 item을 박을 수 있는지 여부를 체크해서 리턴
static const bool CanPutIntoRing(LPITEM ring, LPITEM item) static const bool CanPutIntoRing(LPITEM ring, LPITEM item)
{ {
const DWORD vnum = item->GetVnum(); const DWORD vnum = item->GetVnum();
@ -1932,10 +1932,10 @@ int CItem::GetLevelLimit()
bool CItem::OnAfterCreatedItem() bool CItem::OnAfterCreatedItem()
{ {
// 아이템을 한 번이라도 사용했다면, 그 이후엔 사용 중이지 않아도 시간이 차감되는 방식 // 아이템을 한 번이라도 사용했다면, 그 이후엔 사용 중이지 않아도 시간이 차감되는 방식
if (-1 != this->GetProto()->cLimitRealTimeFirstUseIndex) if (-1 != this->GetProto()->cLimitRealTimeFirstUseIndex)
{ {
// Socket1에 아이템의 사용 횟수가 기록되어 있으니, 한 번이라도 사용한 아이템은 타이머를 시작한다. // Socket1에 아이템의 사용 횟수가 기록되어 있으니, 한 번이라도 사용한 아이템은 타이머를 시작한다.
if (0 != GetSocket(1)) if (0 != GetSocket(1))
{ {
StartRealTimeExpireEvent(); StartRealTimeExpireEvent();
@ -1948,8 +1948,8 @@ bool CItem::OnAfterCreatedItem()
#ifdef __AUCTION__ #ifdef __AUCTION__
// 경매장 // 경매장
// window를 경매장으로 한다. // window를 경매장으로 한다.
bool CItem::MoveToAuction() bool CItem::MoveToAuction()
{ {
@ -2016,7 +2016,7 @@ int CItem::GiveMoreTime_Per(float fPercent)
return given_time; return given_time;
} }
} }
// 우선 용혼석에 관해서만 하도록 한다. // 우선 용혼석에 관해서만 하도록 한다.
else else
return 0; return 0;
} }
@ -2040,7 +2040,7 @@ int CItem::GiveMoreTime_Fix(DWORD dwTime)
return dwTime; return dwTime;
} }
} }
// 우선 용혼석에 관해서만 하도록 한다. // 우선 용혼석에 관해서만 하도록 한다.
else else
return 0; return 0;
} }
@ -2065,7 +2065,7 @@ int CItem::GetDuration()
bool CItem::IsSameSpecialGroup(const LPITEM item) const bool CItem::IsSameSpecialGroup(const LPITEM item) const
{ {
// 서로 VNUM이 같다면 같은 그룹인 것으로 간주 // 서로 VNUM이 같다면 같은 그룹인 것으로 간주
if (this->GetVnum() == item->GetVnum()) if (this->GetVnum() == item->GetVnum())
return true; return true;

View File

@ -20,7 +20,7 @@ void CItemAddonManager::ApplyAddonTo(int iAddonType, LPITEM pItem)
return; return;
} }
// TODO 일단 하드코딩으로 평타 스킬 수치 변경만 경우만 적용받게한다. // TODO 일단 하드코딩으로 평타 스킬 수치 변경만 경우만 적용받게한다.
int iSkillBonus = std::clamp((int) (Random::get<std::normal_distribution<>>(0, 5) + 0.5f), -30, 30); int iSkillBonus = std::clamp((int) (Random::get<std::normal_distribution<>>(0, 5) + 0.5f), -30, 30);
int iNormalHitBonus = 0; int iNormalHitBonus = 0;

View File

@ -24,7 +24,7 @@ int CItem::GetAttributeSetIndex()
switch (GetSubType()) switch (GetSubType())
{ {
case ARMOR_BODY: case ARMOR_BODY:
// case COSTUME_BODY: // 코스츔 갑옷은 일반 갑옷과 동일한 Attribute Set을 이용하여 랜덤속성 붙음 (ARMOR_BODY == COSTUME_BODY) // case COSTUME_BODY: // 코스츔 갑옷은 일반 갑옷과 동일한 Attribute Set을 이용하여 랜덤속성 붙음 (ARMOR_BODY == COSTUME_BODY)
return ATTRIBUTE_SET_BODY; return ATTRIBUTE_SET_BODY;
case ARMOR_WRIST: case ARMOR_WRIST:
@ -37,7 +37,7 @@ int CItem::GetAttributeSetIndex()
return ATTRIBUTE_SET_NECK; return ATTRIBUTE_SET_NECK;
case ARMOR_HEAD: case ARMOR_HEAD:
// case COSTUME_HAIR: // 코스츔 헤어는 일반 투구 아이템과 동일한 Attribute Set을 이용하여 랜덤속성 붙음 (ARMOR_HEAD == COSTUME_HAIR) // case COSTUME_HAIR: // 코스츔 헤어는 일반 투구 아이템과 동일한 Attribute Set을 이용하여 랜덤속성 붙음 (ARMOR_HEAD == COSTUME_HAIR)
return ATTRIBUTE_SET_HEAD; return ATTRIBUTE_SET_HEAD;
case ARMOR_SHIELD: case ARMOR_SHIELD:
@ -125,7 +125,7 @@ void CItem::PutAttributeWithLevel(BYTE bLevel)
int total = 0; int total = 0;
// 붙일 수 있는 속성 배열을 구축 // 붙일 수 있는 속성 배열을 구축
for (int i = 0; i < MAX_APPLY_NUM; ++i) for (int i = 0; i < MAX_APPLY_NUM; ++i)
{ {
const TItemAttrTable & r = g_map_itemAttr[i]; const TItemAttrTable & r = g_map_itemAttr[i];
@ -137,7 +137,7 @@ void CItem::PutAttributeWithLevel(BYTE bLevel)
} }
} }
// 구축된 배열로 확률 계산을 통해 붙일 속성 선정 // 구축된 배열로 확률 계산을 통해 붙일 속성 선정
unsigned int prob = Random::get(1, total); unsigned int prob = Random::get(1, total);
int attr_idx = APPLY_NONE; int attr_idx = APPLY_NONE;
@ -162,7 +162,7 @@ void CItem::PutAttributeWithLevel(BYTE bLevel)
const TItemAttrTable & r = g_map_itemAttr[attr_idx]; const TItemAttrTable & r = g_map_itemAttr[attr_idx];
// 종류별 속성 레벨 최대값 제한 // 종류별 속성 레벨 최대값 제한
if (bLevel > r.bMaxLevelBySet[iAttributeSet]) if (bLevel > r.bMaxLevelBySet[iAttributeSet])
bLevel = r.bMaxLevelBySet[iAttributeSet]; bLevel = r.bMaxLevelBySet[iAttributeSet];

View File

@ -80,7 +80,7 @@ bool ITEM_MANAGER::Initialize(TItemTable * table, int size)
if (m_vec_prototype[i].dwRefinedVnum) if (m_vec_prototype[i].dwRefinedVnum)
m_map_ItemRefineFrom.insert(std::make_pair(m_vec_prototype[i].dwRefinedVnum, m_vec_prototype[i].dwVnum)); m_map_ItemRefineFrom.insert(std::make_pair(m_vec_prototype[i].dwRefinedVnum, m_vec_prototype[i].dwVnum));
// NOTE : QUEST_GIVE 플래그는 npc 이벤트로 발생. // NOTE : QUEST_GIVE 플래그는 npc 이벤트로 발생.
if (m_vec_prototype[i].bType == ITEM_QUEST || IS_SET(m_vec_prototype[i].dwFlags, ITEM_FLAG_QUEST_USE | ITEM_FLAG_QUEST_USE_MULTIPLE)) if (m_vec_prototype[i].bType == ITEM_QUEST || IS_SET(m_vec_prototype[i].dwFlags, ITEM_FLAG_QUEST_USE | ITEM_FLAG_QUEST_USE_MULTIPLE))
quest::CQuestManager::instance().RegisterNPCVnum(m_vec_prototype[i].dwVnum); quest::CQuestManager::instance().RegisterNPCVnum(m_vec_prototype[i].dwVnum);
@ -155,7 +155,7 @@ LPITEM ITEM_MANAGER::CreateItem(DWORD vnum, DWORD count, DWORD id, bool bTryMagi
{ {
if (vnum == 50300 && bTryMagic) if (vnum == 50300 && bTryMagic)
{ {
// 수련서를 아이템 번호를 다르게 만들어 준다. // 수련서를 아이템 번호를 다르게 만들어 준다.
DWORD dwSkillVnum; DWORD dwSkillVnum;
do do
@ -181,7 +181,7 @@ LPITEM ITEM_MANAGER::CreateItem(DWORD vnum, DWORD count, DWORD id, bool bTryMagi
LPITEM item = NULL; LPITEM item = NULL;
//id로 검사해서 존재한다면 -- 리턴! //id로 검사해서 존재한다면 -- 리턴!
if (m_map_pkItemByID.find(id) != m_map_pkItemByID.end()) if (m_map_pkItemByID.find(id) != m_map_pkItemByID.end())
{ {
item = m_map_pkItemByID[id]; item = m_map_pkItemByID[id];
@ -190,7 +190,7 @@ LPITEM ITEM_MANAGER::CreateItem(DWORD vnum, DWORD count, DWORD id, bool bTryMagi
return NULL; return NULL;
} }
//아이템 하나 할당하고 //아이템 하나 할당하고
#ifdef M2_USE_POOL #ifdef M2_USE_POOL
item = pool_.Construct(); item = pool_.Construct();
#else #else
@ -199,15 +199,15 @@ LPITEM ITEM_MANAGER::CreateItem(DWORD vnum, DWORD count, DWORD id, bool bTryMagi
bool bIsNewItem = (0 == id); bool bIsNewItem = (0 == id);
//초기화 하고. 테이블 셋하고 //초기화 하고. 테이블 셋하고
item->Initialize(); item->Initialize();
item->SetProto(table); item->SetProto(table);
item->SetMaskVnum(dwMaskVnum); item->SetMaskVnum(dwMaskVnum);
if (item->GetType() == ITEM_ELK) // 돈은 ID가 필요없고 저장도 필요없다. if (item->GetType() == ITEM_ELK) // 돈은 ID가 필요없고 저장도 필요없다.
item->SetSkipSave(true); item->SetSkipSave(true);
// Unique ID를 세팅하자 // Unique ID를 세팅하자
else if (!bIsNewItem) else if (!bIsNewItem)
{ {
item->SetID(id); item->SetID(id);
@ -217,16 +217,16 @@ LPITEM ITEM_MANAGER::CreateItem(DWORD vnum, DWORD count, DWORD id, bool bTryMagi
{ {
item->SetID(GetNewID()); item->SetID(GetNewID());
if (item->GetType() == ITEM_UNIQUE) // 유니크 아이템은 생성시에 소켓에 남은시간을 기록한다. if (item->GetType() == ITEM_UNIQUE) // 유니크 아이템은 생성시에 소켓에 남은시간을 기록한다.
{ {
if (item->GetValue(2) == 0) if (item->GetValue(2) == 0)
item->SetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME, item->GetValue(0)); // 게임 시간 유니크 item->SetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME, item->GetValue(0)); // 게임 시간 유니크
else else
{ {
//int globalTime = get_global_time(); //int globalTime = get_global_time();
//int lastTime = item->GetValue(0); //int lastTime = item->GetValue(0);
//int endTime = get_global_time() + item->GetValue(0); //int endTime = get_global_time() + item->GetValue(0);
item->SetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME, get_global_time() + item->GetValue(0)); // 실시간 유니크 item->SetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME, get_global_time() + item->GetValue(0)); // 실시간 유니크
} }
} }
} }
@ -255,9 +255,9 @@ LPITEM ITEM_MANAGER::CreateItem(DWORD vnum, DWORD count, DWORD id, bool bTryMagi
break; break;
} }
if (item->GetType() == ITEM_ELK) // 돈은 아무 처리가 필요하지 않음 if (item->GetType() == ITEM_ELK) // 돈은 아무 처리가 필요하지 않음
; ;
else if (item->IsStackable()) // 합칠 수 있는 아이템의 경우 else if (item->IsStackable()) // 합칠 수 있는 아이템의 경우
{ {
count = std::clamp<int>(count, 1, ITEM_MAX_COUNT); count = std::clamp<int>(count, 1, ITEM_MAX_COUNT);
@ -285,7 +285,7 @@ LPITEM ITEM_MANAGER::CreateItem(DWORD vnum, DWORD count, DWORD id, bool bTryMagi
for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++) for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++)
{ {
// 아이템 생성 시점부터 사용하지 않아도 시간이 차감되는 방식 // 아이템 생성 시점부터 사용하지 않아도 시간이 차감되는 방식
if (LIMIT_REAL_TIME == item->GetLimitType(i)) if (LIMIT_REAL_TIME == item->GetLimitType(i))
{ {
if (item->GetLimitValue(i)) if (item->GetLimitValue(i))
@ -300,11 +300,11 @@ LPITEM ITEM_MANAGER::CreateItem(DWORD vnum, DWORD count, DWORD id, bool bTryMagi
item->StartRealTimeExpireEvent(); item->StartRealTimeExpireEvent();
} }
// 기존 유니크 아이템처럼 착용시에만 사용가능 시간이 차감되는 방식 // 기존 유니크 아이템처럼 착용시에만 사용가능 시간이 차감되는 방식
else if (LIMIT_TIMER_BASED_ON_WEAR == item->GetLimitType(i)) else if (LIMIT_TIMER_BASED_ON_WEAR == item->GetLimitType(i))
{ {
// 이미 착용중인 아이템이면 타이머를 시작하고, 새로 만드는 아이템은 사용 가능 시간을 세팅해준다. ( // 이미 착용중인 아이템이면 타이머를 시작하고, 새로 만드는 아이템은 사용 가능 시간을 세팅해준다. (
// 아이템몰로 지급하는 경우에는 이 로직에 들어오기 전에 Socket0 값이 세팅이 되어 있어야 한다. // 아이템몰로 지급하는 경우에는 이 로직에 들어오기 전에 Socket0 값이 세팅이 되어 있어야 한다.
if (true == item->IsEquipped()) if (true == item->IsEquipped())
{ {
item->StartTimerBasedOnWearExpireEvent(); item->StartTimerBasedOnWearExpireEvent();
@ -316,16 +316,16 @@ LPITEM ITEM_MANAGER::CreateItem(DWORD vnum, DWORD count, DWORD id, bool bTryMagi
duration = item->GetLimitValue(i); duration = item->GetLimitValue(i);
if (0 == duration) if (0 == duration)
duration = 60 * 60 * 10; // 정보가 아무것도 없으면 디폴트로 10시간 세팅 duration = 60 * 60 * 10; // 정보가 아무것도 없으면 디폴트로 10시간 세팅
item->SetSocket(0, duration); item->SetSocket(0, duration);
} }
} }
} }
if (id == 0) // 새로 만드는 아이템일 때만 처리 if (id == 0) // 새로 만드는 아이템일 때만 처리
{ {
// 새로추가되는 약초들일경우 성능을 다르게처리 // 새로추가되는 약초들일경우 성능을 다르게처리
if (ITEM_BLEND==item->GetType()) if (ITEM_BLEND==item->GetType())
{ {
if (Blend_Item_find(item->GetVnum())) if (Blend_Item_find(item->GetVnum()))
@ -352,7 +352,7 @@ LPITEM ITEM_MANAGER::CreateItem(DWORD vnum, DWORD count, DWORD id, bool bTryMagi
if (table->bGainSocketPct) if (table->bGainSocketPct)
item->AlterToSocketItem(table->bGainSocketPct); item->AlterToSocketItem(table->bGainSocketPct);
// 50300 == 기술 수련서 // 50300 == 기술 수련서
if (vnum == 50300 || vnum == ITEM_SKILLFORGET_VNUM) if (vnum == 50300 || vnum == ITEM_SKILLFORGET_VNUM)
{ {
DWORD dwSkillVnum; DWORD dwSkillVnum;
@ -404,7 +404,7 @@ LPITEM ITEM_MANAGER::CreateItem(DWORD vnum, DWORD count, DWORD id, bool bTryMagi
} }
} }
// 새로 생성되는 용혼석 처리. // 새로 생성되는 용혼석 처리.
if (item->IsDragonSoul() && 0 == id) if (item->IsDragonSoul() && 0 == id)
{ {
DSManager::instance().DragonSoulItemInitialize(item); DSManager::instance().DragonSoulItemInitialize(item);
@ -473,7 +473,7 @@ void ITEM_MANAGER::Update()
this_it = it++; this_it = it++;
LPITEM item = *this_it; LPITEM item = *this_it;
// SLOW_QUERY 플래그가 있는 것은 종료시에만 저장한다. // SLOW_QUERY 플래그가 있는 것은 종료시에만 저장한다.
if (item->GetOwner() && IS_SET(item->GetFlag(), ITEM_FLAG_SLOW_QUERY)) if (item->GetOwner() && IS_SET(item->GetFlag(), ITEM_FLAG_SLOW_QUERY))
continue; continue;
@ -496,7 +496,7 @@ void ITEM_MANAGER::RemoveItem(LPITEM item, const char * c_pszReason)
// SAFEBOX_TIME_LIMIT_ITEM_BUG_FIX // SAFEBOX_TIME_LIMIT_ITEM_BUG_FIX
if (item->GetWindow() == MALL || item->GetWindow() == SAFEBOX) if (item->GetWindow() == MALL || item->GetWindow() == SAFEBOX)
{ {
// 20050613.ipkn.시간제 아이템이 상점에 있을 경우 시간만료시 서버가 다운된다. // 20050613.ipkn.시간제 아이템이 상점에 있을 경우 시간만료시 서버가 다운된다.
CSafebox* pSafebox = item->GetWindow() == MALL ? o->GetMall() : o->GetSafebox(); CSafebox* pSafebox = item->GetWindow() == MALL ? o->GetMall() : o->GetSafebox();
if (pSafebox) if (pSafebox)
{ {
@ -760,8 +760,8 @@ class CItemDropInfo
extern std::vector<CItemDropInfo> g_vec_pkCommonDropItem[MOB_RANK_MAX_NUM]; extern std::vector<CItemDropInfo> g_vec_pkCommonDropItem[MOB_RANK_MAX_NUM];
// 20050503.ipkn. // 20050503.ipkn.
// iMinimum 보다 작으면 iDefault 세팅 (단, iMinimum은 0보다 커야함) // iMinimum 보다 작으면 iDefault 세팅 (단, iMinimum은 0보다 커야함)
// 1, 0 식으로 ON/OFF 되는 방식을 지원하기 위해 존재 // 1, 0 식으로 ON/OFF 되는 방식을 지원하기 위해 존재
int GetDropPerKillPct(int iMinimum, int iDefault, int iDeltaPercent, const char * c_pszFlag) int GetDropPerKillPct(int iMinimum, int iDefault, int iDeltaPercent, const char * c_pszFlag)
{ {
int iVal = 0; int iVal = 0;
@ -781,8 +781,8 @@ int GetDropPerKillPct(int iMinimum, int iDefault, int iDeltaPercent, const char
if (iVal == 0) if (iVal == 0)
return 0; return 0;
// 기본 세팅일때 (iDeltaPercent=100) // 기본 세팅일때 (iDeltaPercent=100)
// 40000 iVal 마리당 하나 느낌을 주기 위한 상수임 // 40000 iVal 마리당 하나 느낌을 주기 위한 상수임
return (40000 * iDeltaPercent / iVal); return (40000 * iDeltaPercent / iVal);
} }
@ -930,7 +930,7 @@ bool ITEM_MANAGER::CreateDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::
CMobItemGroup* pGroup = it->second; CMobItemGroup* pGroup = it->second;
// MOB_DROP_ITEM_BUG_FIX // MOB_DROP_ITEM_BUG_FIX
// 20050805.myevan.MobDropItem 에 아이템이 없을 경우 CMobItemGroup::GetOne() 접근시 문제 발생 수정 // 20050805.myevan.MobDropItem 에 아이템이 없을 경우 CMobItemGroup::GetOne() 접근시 문제 발생 수정
if (pGroup && !pGroup->IsEmpty()) if (pGroup && !pGroup->IsEmpty())
{ {
int iPercent = 40000 * iDeltaPercent / pGroup->GetKillPerDrop(); int iPercent = 40000 * iDeltaPercent / pGroup->GetKillPerDrop();
@ -997,7 +997,7 @@ bool ITEM_MANAGER::CreateDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::
} }
} }
// 잡템 // 잡템
if (pkChr->GetMobDropItemVnum()) if (pkChr->GetMobDropItemVnum())
{ {
itertype(m_map_dwEtcItemDropProb) it = m_map_dwEtcItemDropProb.find(pkChr->GetMobDropItemVnum()); itertype(m_map_dwEtcItemDropProb) it = m_map_dwEtcItemDropProb.find(pkChr->GetMobDropItemVnum());
@ -1046,14 +1046,14 @@ bool ITEM_MANAGER::CreateDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::
pdw[1] = 1; pdw[1] = 1;
pdw[2] = quest::CQuestManager::instance().GetEventFlag("lotto_round"); pdw[2] = quest::CQuestManager::instance().GetEventFlag("lotto_round");
// 행운의 서는 소켓을 설정한다 // 행운의 서는 소켓을 설정한다
DBManager::instance().ReturnQuery(QID_LOTTO, pkKiller->GetPlayerID(), pdw, DBManager::instance().ReturnQuery(QID_LOTTO, pkKiller->GetPlayerID(), pdw,
"INSERT INTO lotto_list VALUES(0, 'server%s', %u, NOW())", "INSERT INTO lotto_list VALUES(0, 'server%s', %u, NOW())",
get_table_postfix(), pkKiller->GetPlayerID()); get_table_postfix(), pkKiller->GetPlayerID());
} }
// //
// 스페셜 드롭 아이템 // 스페셜 드롭 아이템
// //
CreateQuestDropItem(pkChr, pkKiller, vec_item, iDeltaPercent, iRandRange); CreateQuestDropItem(pkChr, pkKiller, vec_item, iDeltaPercent, iRandRange);
@ -1064,7 +1064,7 @@ bool ITEM_MANAGER::CreateDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::
} }
// //
// 승룡곡 천의동굴 2층에서만 수룡방 입장권 // 승룡곡 천의동굴 2층에서만 수룡방 입장권
// //
if (LC_IsYMIR() || LC_IsKorea()) if (LC_IsYMIR() || LC_IsKorea())
{ {
@ -1081,21 +1081,21 @@ bool ITEM_MANAGER::CreateDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::
} }
// //
// 승룡곡 1층, 2층에서만 7,8 스킬입문서 드롭 // 승룡곡 1층, 2층에서만 7,8 스킬입문서 드롭
// //
if (LC_IsYMIR() || LC_IsKorea()) if (LC_IsYMIR() || LC_IsKorea())
{ {
switch (pkKiller->GetMapIndex()) switch (pkKiller->GetMapIndex())
{ {
case 72: // 천의동굴 1층 case 72: // 천의동굴 1층
case 73: // 천의동굴 2층 case 73: // 천의동굴 2층
{ {
int vnum = 0; int vnum = 0;
if (2403 == pkChr->GetRaceNum()) // 천의법사 if (2403 == pkChr->GetRaceNum()) // 천의법사
vnum = 69200; // 7스킬 입문서 vnum = 69200; // 7스킬 입문서
else if (2411 == pkChr->GetRaceNum()) // 진천의병사 else if (2411 == pkChr->GetRaceNum()) // 진천의병사
vnum = 69201; // 8스킬 입문서 vnum = 69201; // 8스킬 입문서
else else
break; break;
@ -1250,11 +1250,11 @@ bool DropEvent_CharStone_SetValue(const std::string& name, int value)
// END_OF_DROPEVENT_CHARSTONE // END_OF_DROPEVENT_CHARSTONE
// fixme // fixme
// 위의 것과 함께 quest로 뺄것 빼보자. // 위의 것과 함께 quest로 뺄것 빼보자.
// 이거 너무 더럽잖아... // 이거 너무 더럽잖아...
// ??.. 하드코딩 싫다 ㅜㅠ // ??.. 하드코딩 싫다 ㅜㅠ
// 계량 아이템 보상 시작. // 계량 아이템 보상 시작.
// by rtsummit 고치자 진짜 // by rtsummit 고치자 진짜
static struct DropEvent_RefineBox static struct DropEvent_RefineBox
{ {
int percent_low; int percent_low;
@ -1371,7 +1371,7 @@ bool DropEvent_RefineBox_SetValue(const std::string& name, int value)
return true; return true;
} }
// 개량 아이템 보상 끝. // 개량 아이템 보상 끝.
void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::vector<LPITEM> & vec_item, int iDeltaPercent, int iRandRange) void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::vector<LPITEM> & vec_item, int iDeltaPercent, int iRandRange)
@ -1391,7 +1391,7 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
// END_OF_DROPEVENT_CHARSTONE // END_OF_DROPEVENT_CHARSTONE
__DropEvent_RefineBox_DropItem(*pkKiller, *pkChr, *this, vec_item); __DropEvent_RefineBox_DropItem(*pkKiller, *pkChr, *this, vec_item);
// 크리스마스 양말 // 크리스마스 양말
if (quest::CQuestManager::instance().GetEventFlag("xmas_sock")) if (quest::CQuestManager::instance().GetEventFlag("xmas_sock"))
{ {
//const DWORD SOCK_ITEM_VNUM = 50010; //const DWORD SOCK_ITEM_VNUM = 50010;
@ -1433,7 +1433,7 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
} }
} }
// 월광 보합 // 월광 보합
if (quest::CQuestManager::instance().GetEventFlag("drop_moon")) if (quest::CQuestManager::instance().GetEventFlag("drop_moon"))
{ {
const DWORD ITEM_VNUM = 50011; const DWORD ITEM_VNUM = 50011;
@ -1479,7 +1479,7 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
} }
} }
//육각보합 //육각보합
if (GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "2006_drop") >= Random::get(1, iRandRange)) if (GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "2006_drop") >= Random::get(1, iRandRange))
{ {
SPDLOG_DEBUG("\xC0\xB0\xB0\xA2\xBA\xB8\xC7\xD5 DROP EVENT "); SPDLOG_DEBUG("\xC0\xB0\xB0\xA2\xBA\xB8\xC7\xD5 DROP EVENT ");
@ -1491,7 +1491,7 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
} }
//육각보합+ //육각보합+
if (GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "2007_drop") >= Random::get(1, iRandRange)) if (GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "2007_drop") >= Random::get(1, iRandRange))
{ {
SPDLOG_DEBUG("\xC0\xB0\xB0\xA2\xBA\xB8\xC7\xD5 DROP EVENT "); SPDLOG_DEBUG("\xC0\xB0\xB0\xA2\xBA\xB8\xC7\xD5 DROP EVENT ");
@ -1502,17 +1502,17 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
vec_item.push_back(item); vec_item.push_back(item);
} }
// 새해 폭죽 이벤트 // 새해 폭죽 이벤트
if (GetDropPerKillPct(/* minimum */ 100, /* default */ 1000, iDeltaPercent, "newyear_fire") >= Random::get(1, iRandRange)) if (GetDropPerKillPct(/* minimum */ 100, /* default */ 1000, iDeltaPercent, "newyear_fire") >= Random::get(1, iRandRange))
{ {
// 중국은 폭죽, 한국 팽이 // 중국은 폭죽, 한국 팽이
const DWORD ITEM_VNUM_FIRE = g_iUseLocale ? 50107 : 50108; const DWORD ITEM_VNUM_FIRE = g_iUseLocale ? 50107 : 50108;
if ((item = CreateItem(ITEM_VNUM_FIRE, 1, 0, true))) if ((item = CreateItem(ITEM_VNUM_FIRE, 1, 0, true)))
vec_item.push_back(item); vec_item.push_back(item);
} }
// 새해 대보름 원소 이벤트 // 새해 대보름 원소 이벤트
if (GetDropPerKillPct(100, 500, iDeltaPercent, "newyear_moon") >= Random::get(1, iRandRange)) if (GetDropPerKillPct(100, 500, iDeltaPercent, "newyear_moon") >= Random::get(1, iRandRange))
{ {
SPDLOG_DEBUG("EVENT NEWYEAR_MOON DROP"); SPDLOG_DEBUG("EVENT NEWYEAR_MOON DROP");
@ -1524,7 +1524,7 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
vec_item.push_back(item); vec_item.push_back(item);
} }
// 발렌타인 데이 이벤트. OGE의 요구에 따라 event 최소값을 1로 변경.(다른 이벤트는 일단 그대로 둠.) // 발렌타인 데이 이벤트. OGE의 요구에 따라 event 최소값을 1로 변경.(다른 이벤트는 일단 그대로 둠.)
if (GetDropPerKillPct(1, g_iUseLocale ? 2000 : 800, iDeltaPercent, "valentine_drop") >= Random::get(1, iRandRange)) if (GetDropPerKillPct(1, g_iUseLocale ? 2000 : 800, iDeltaPercent, "valentine_drop") >= Random::get(1, iRandRange))
{ {
SPDLOG_DEBUG("EVENT VALENTINE_DROP"); SPDLOG_DEBUG("EVENT VALENTINE_DROP");
@ -1536,7 +1536,7 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
vec_item.push_back(item); vec_item.push_back(item);
} }
// 아이스크림 이벤트 // 아이스크림 이벤트
if (GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "icecream_drop") >= Random::get(1, iRandRange)) if (GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "icecream_drop") >= Random::get(1, iRandRange))
{ {
const static DWORD icecream = 50123; const static DWORD icecream = 50123;
@ -1545,8 +1545,8 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
vec_item.push_back(item); vec_item.push_back(item);
} }
// new 크리스마스 이벤트 // new 크리스마스 이벤트
// 53002 : 아기 순록 소환권 // 53002 : 아기 순록 소환권
if ((pkKiller->CountSpecifyItem(53002) > 0) && (GetDropPerKillPct(50, 100, iDeltaPercent, "new_xmas_event") >= Random::get(1, iRandRange))) if ((pkKiller->CountSpecifyItem(53002) > 0) && (GetDropPerKillPct(50, 100, iDeltaPercent, "new_xmas_event") >= Random::get(1, iRandRange)))
{ {
const static DWORD xmas_sock = 50010; const static DWORD xmas_sock = 50010;
@ -1590,7 +1590,7 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
vec_item.push_back(item); vec_item.push_back(item);
} }
// 월드컵 이벤트 // 월드컵 이벤트
if ( GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "football_drop") >= Random::get(1, iRandRange) ) if ( GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "football_drop") >= Random::get(1, iRandRange) )
{ {
const static DWORD football_item = 50096; const static DWORD football_item = 50096;
@ -1599,7 +1599,7 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
vec_item.push_back(item); vec_item.push_back(item);
} }
// 화이트 데이 이벤트 // 화이트 데이 이벤트
if (GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "whiteday_drop") >= Random::get(1, iRandRange)) if (GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "whiteday_drop") >= Random::get(1, iRandRange))
{ {
SPDLOG_DEBUG("EVENT WHITEDAY_DROP"); SPDLOG_DEBUG("EVENT WHITEDAY_DROP");
@ -1610,7 +1610,7 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
vec_item.push_back(item); vec_item.push_back(item);
} }
// 어린이날 수수께끼 상자 이벤트 // 어린이날 수수께끼 상자 이벤트
if (pkKiller->GetLevel()>=50) if (pkKiller->GetLevel()>=50)
{ {
if (GetDropPerKillPct(100, 1000, iDeltaPercent, "kids_day_drop_high") >= Random::get(1, iRandRange)) if (GetDropPerKillPct(100, 1000, iDeltaPercent, "kids_day_drop_high") >= Random::get(1, iRandRange))
@ -1632,7 +1632,7 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
} }
} }
// 올림픽 드롭 이벤트 // 올림픽 드롭 이벤트
if (pkChr->GetLevel() >= 30 && GetDropPerKillPct(50, 100, iDeltaPercent, "medal_part_drop") >= Random::get(1, iRandRange)) if (pkChr->GetLevel() >= 30 && GetDropPerKillPct(50, 100, iDeltaPercent, "medal_part_drop") >= Random::get(1, iRandRange))
{ {
const static DWORD drop_items[] = { 30265, 30266, 30267, 30268, 30269 }; const static DWORD drop_items[] = { 30265, 30266, 30267, 30268, 30269 };
@ -1643,7 +1643,7 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
} }
// ADD_GRANDMASTER_SKILL // ADD_GRANDMASTER_SKILL
// 혼석 아이템 드롭 // 혼석 아이템 드롭
if (pkChr->GetLevel() >= 40 && pkChr->GetMobRank() >= MOB_RANK_BOSS && GetDropPerKillPct(/* minimum */ 1, /* default */ 1000, iDeltaPercent, "three_skill_item") / GetThreeSkillLevelAdjust(pkChr->GetLevel()) >= Random::get(1, iRandRange)) if (pkChr->GetLevel() >= 40 && pkChr->GetMobRank() >= MOB_RANK_BOSS && GetDropPerKillPct(/* minimum */ 1, /* default */ 1000, iDeltaPercent, "three_skill_item") / GetThreeSkillLevelAdjust(pkChr->GetLevel()) >= Random::get(1, iRandRange))
{ {
const DWORD ITEM_VNUM = 50513; const DWORD ITEM_VNUM = 50513;
@ -1654,7 +1654,7 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
// END_OF_ADD_GRANDMASTER_SKILL // END_OF_ADD_GRANDMASTER_SKILL
// //
// 종자 아이템 drop // 종자 아이템 drop
// //
if (GetDropPerKillPct(100, 1000, iDeltaPercent, "dragon_boat_festival_drop") >= Random::get(1, iRandRange)) if (GetDropPerKillPct(100, 1000, iDeltaPercent, "dragon_boat_festival_drop") >= Random::get(1, iRandRange))
{ {
@ -1664,7 +1664,7 @@ void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller,
vec_item.push_back(item); vec_item.push_back(item);
} }
// 무신의 축복서용 만년한철 drop // 무신의 축복서용 만년한철 drop
if (pkKiller->GetLevel() >= 15 && quest::CQuestManager::instance().GetEventFlag("mars_drop")) if (pkKiller->GetLevel() >= 15 && quest::CQuestManager::instance().GetEventFlag("mars_drop"))
{ {
const DWORD ITEM_HANIRON = 70035; const DWORD ITEM_HANIRON = 70035;
@ -1726,8 +1726,8 @@ DWORD ITEM_MANAGER::GetMaskVnum(DWORD dwVnum)
return 0; return 0;
} }
// pkNewItem으로 모든 속성과 소켓 값들을 목사하는 함수. // pkNewItem으로 모든 속성과 소켓 값들을 목사하는 함수.
// 기존에 char_item.cpp 파일에 있던 로컬함수인 TransformRefineItem 그대로 복사함 // 기존에 char_item.cpp 파일에 있던 로컬함수인 TransformRefineItem 그대로 복사함
void ITEM_MANAGER::CopyAllAttrTo(LPITEM pkOldItem, LPITEM pkNewItem) void ITEM_MANAGER::CopyAllAttrTo(LPITEM pkOldItem, LPITEM pkNewItem)
{ {
// ACCESSORY_REFINE // ACCESSORY_REFINE
@ -1742,7 +1742,7 @@ void ITEM_MANAGER::CopyAllAttrTo(LPITEM pkOldItem, LPITEM pkNewItem)
// END_OF_ACCESSORY_REFINE // END_OF_ACCESSORY_REFINE
else else
{ {
// 여기서 깨진석이 자동적으로 청소 됨 // 여기서 깨진석이 자동적으로 청소 됨
for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i) for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
{ {
if (!pkOldItem->GetSocket(i)) if (!pkOldItem->GetSocket(i))
@ -1751,19 +1751,19 @@ void ITEM_MANAGER::CopyAllAttrTo(LPITEM pkOldItem, LPITEM pkNewItem)
pkNewItem->SetSocket(i, 1); pkNewItem->SetSocket(i, 1);
} }
// 소켓 설정 // 소켓 설정
int slot = 0; int slot = 0;
for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i) for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
{ {
int socket = pkOldItem->GetSocket(i); int socket = pkOldItem->GetSocket(i);
const int ITEM_BROKEN_METIN_VNUM = 28960; // 이건 뭐 똑같은 상수가 3군데나 있냐... 하나로 해놓지ㅠㅠㅠ 나는 패스 홍이 할꺼임 const int ITEM_BROKEN_METIN_VNUM = 28960; // 이건 뭐 똑같은 상수가 3군데나 있냐... 하나로 해놓지ㅠㅠㅠ 나는 패스 홍이 할꺼임
if (socket > 2 && socket != ITEM_BROKEN_METIN_VNUM) if (socket > 2 && socket != ITEM_BROKEN_METIN_VNUM)
pkNewItem->SetSocket(slot++, socket); pkNewItem->SetSocket(slot++, socket);
} }
} }
// 매직 아이템 설정 // 매직 아이템 설정
pkOldItem->CopyAttributeTo(pkNewItem); pkOldItem->CopyAttributeTo(pkNewItem);
} }

View File

@ -78,7 +78,7 @@ bool ITEM_MANAGER::ReadCommonDropItemFile(const char * c_pszFileName)
if (!ITEM_MANAGER::instance().GetVnumByOriginalName(d[i].szItemName, dwItemVnum)) if (!ITEM_MANAGER::instance().GetVnumByOriginalName(d[i].szItemName, dwItemVnum))
{ {
// <EFBFBD≯<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ã<EFBFBD><C3A3><EFBFBD><EFBFBD> <20><>ȣ<EFBFBD><C8A3> <20>˻<EFBFBD> // 이름으로 못찾으면 번호로 검색
str_to_number(dwItemVnum, d[i].szItemName); str_to_number(dwItemVnum, d[i].szItemName);
if (!ITEM_MANAGER::instance().GetTable(dwItemVnum)) if (!ITEM_MANAGER::instance().GetTable(dwItemVnum))
{ {
@ -405,7 +405,7 @@ bool ITEM_MANAGER::ConvSpecialDropItemFile()
str_to_number(iRarePct, pTok->at(3).c_str()); str_to_number(iRarePct, pTok->at(3).c_str());
} }
// 1 "<EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>ü<EFBFBD>" 1 100 // 1 "기술 수련서" 1 100
if (0 == dwVnum) if (0 == dwVnum)
fprintf(fp, " %d %s %d %d\n", k, name.c_str(), iCount, iProb); fprintf(fp, " %d %s %d %d\n", k, name.c_str(), iCount, iProb);
else else

View File

@ -48,7 +48,7 @@ const char *quote_find_end(const char *string)
{ {
if (quote && *tmp == '\\' && *(tmp + 1)) if (quote && *tmp == '\\' && *(tmp + 1))
{ {
// \ 다음 문자가 " 면 스킵한다. // \ 다음 문자가 " 면 스킵한다.
switch (*(tmp + 1)) switch (*(tmp + 1))
{ {
case '"': case '"':

View File

@ -79,7 +79,7 @@ int check_name_independent(const char * str)
if (CBanwordManager::instance().CheckString(str, strlen(str))) if (CBanwordManager::instance().CheckString(str, strlen(str)))
return 0; return 0;
// 몬스터 이름으로는 만들 수 없다. // 몬스터 이름으로는 만들 수 없다.
char szTmp[256]; char szTmp[256];
str_lower(str, szTmp, sizeof(szTmp)); str_lower(str, szTmp, sizeof(szTmp));
@ -120,12 +120,12 @@ int check_name_gb2312(const char * str)
b1 = str[i++]; b1 = str[i++];
b2 = str[i++]; b2 = str[i++];
// 중국 간체는 첫번째 바이트 범위가 b0 -> f7 까지고 // 중국 간체는 첫번째 바이트 범위가 b0 -> f7 까지고
// 두번째 바이트 범위가 a1 -> fe 다. // 두번째 바이트 범위가 a1 -> fe 다.
if (b1 < 0xb0 || b1 > 0xf7 || b2 < 0xa1 || b2 > 0xfe) if (b1 < 0xb0 || b1 > 0xf7 || b2 < 0xa1 || b2 > 0xfe)
return 0; return 0;
// 예외가 있다. // 예외가 있다.
for (j = 0; j < 5; j++) for (j = 0; j < 5; j++)
if (b1 == exceptions[j][0] && b2 == exceptions[j][1]) if (b1 == exceptions[j][0] && b2 == exceptions[j][1])
return 0; return 0;
@ -172,8 +172,8 @@ int check_name_big5(const char * str )
b[0] = b2; b[0] = b2;
b[1] = b1; b[1] = b1;
// 중국 번체 ( big5 : 홍콩 ) // 중국 번체 ( big5 : 홍콩 )
// 범위는 다음과 같다. // 범위는 다음과 같다.
// big5: 0xA140--0xF9D5 // big5: 0xA140--0xF9D5
// extended big5: 0x40--0x7E and 0xA1--0xFE // extended big5: 0x40--0x7E and 0xA1--0xFE
@ -230,15 +230,15 @@ int check_name_latin1(const char * str)
for (tmp = str; *tmp; ++tmp) for (tmp = str; *tmp; ++tmp)
{ {
// 한글이 아니고 빈칸이면 잘못된 것 // 한글이 아니고 빈칸이면 잘못된 것
if (isspace(*tmp)) if (isspace(*tmp))
return 0; return 0;
// 한글이 아니고 숫자라면 적합하다. // 한글이 아니고 숫자라면 적합하다.
if (isdigit(*tmp)) if (isdigit(*tmp))
continue; continue;
// 한글이 아니고 영문이라면 적합하다. // 한글이 아니고 영문이라면 적합하다.
if (isalpha(*tmp)) if (isalpha(*tmp))
continue; continue;
@ -275,7 +275,7 @@ int check_name_alphabet(const char * str)
for (tmp = str; *tmp; ++tmp) for (tmp = str; *tmp; ++tmp)
{ {
// 알파벳과 수자만 허용 // 알파벳과 수자만 허용
if (isdigit(*tmp) || isalpha(*tmp)) if (isdigit(*tmp) || isalpha(*tmp))
continue; continue;
else else
@ -324,7 +324,7 @@ int check_name_sjis(const char *str)
const char *p = str; const char *p = str;
const char *e = str + strlen(str); // NULL position const char *e = str + strlen(str); // NULL position
// 일본은 캐릭터 이름길이 16byte 까지 // 일본은 캐릭터 이름길이 16byte 까지
if ( strlen(str) < 2 || strlen(str) > 16 ) if ( strlen(str) < 2 || strlen(str) > 16 )
return 0; return 0;
@ -337,7 +337,7 @@ int check_name_sjis(const char *str)
return false; return false;
// END_OF_DISABLE_SPECIAL_CHAR_NAMING // END_OF_DISABLE_SPECIAL_CHAR_NAMING
// 이문자는 허용되지 않는다. // 이문자는 허용되지 않는다.
if ((BYTE)p[0]==0x81 && (BYTE)p[1]==0x40) return false; if ((BYTE)p[0]==0x81 && (BYTE)p[1]==0x40) return false;
p += 2; p += 2;
@ -345,7 +345,7 @@ int check_name_sjis(const char *str)
} }
else else
{ {
// 영문이나 수자는 허용한다. // 영문이나 수자는 허용한다.
if (isalpha(*p) || isdigit(*p)) if (isalpha(*p) || isdigit(*p))
{ {
p += 1; p += 1;
@ -888,7 +888,7 @@ static void __LocaleService_Init_Singapore()
check_name = check_name_alphabet; check_name = check_name_alphabet;
g_iUseLocale = true; g_iUseLocale = true;
//exp_table = exp_table_newcibn; 2013 09 11 CYH europe 과 동일하게 간다. //exp_table = exp_table_newcibn; 2013 09 11 CYH europe 과 동일하게 간다.
} }
static void __LocaleService_Init_Vietnam() static void __LocaleService_Init_Vietnam()
@ -1309,18 +1309,18 @@ bool LC_IsEurope()
case LC_DENMARK: case LC_DENMARK:
case LC_BULGARIA: case LC_BULGARIA:
case LC_CROATIA: case LC_CROATIA:
case LC_MEXICO: // 남미지만 GF에서 서비스 하므로 여기 넣음 case LC_MEXICO: // 남미지만 GF에서 서비스 하므로 여기 넣음
case LC_ARABIA: // 중동이지만 GF에서 서비스 하므로 여기 넣음 case LC_ARABIA: // 중동이지만 GF에서 서비스 하므로 여기 넣음
case LC_CZECH: case LC_CZECH:
case LC_ROMANIA: case LC_ROMANIA:
case LC_HUNGARY: case LC_HUNGARY:
case LC_NETHERLANDS: case LC_NETHERLANDS:
case LC_USA: case LC_USA:
case LC_WE_KOREA: // 한국이지만 UK 버전 기반이므로 여기 넣음 case LC_WE_KOREA: // 한국이지만 UK 버전 기반이므로 여기 넣음
case LC_TAIWAN: // 대만이지만 WE_KOREA 버전 기반이므로 여기 넣음 case LC_TAIWAN: // 대만이지만 WE_KOREA 버전 기반이므로 여기 넣음
case LC_JAPAN: // 일본이지만 WE(World Edition -_-) 버전이므로 여기 넣음 case LC_JAPAN: // 일본이지만 WE(World Edition -_-) 버전이므로 여기 넣음
case LC_NEWCIBN: case LC_NEWCIBN:
case LC_CANADA: // 캐나다 GF에서 서비스 시작 case LC_CANADA: // 캐나다 GF에서 서비스 시작
return true; return true;
} }

View File

@ -86,10 +86,10 @@ void WriteMallocMessage(const char* p1, const char* p2, const char* p3, const ch
#endif #endif
// TRAFFIC_PROFILER // TRAFFIC_PROFILER
static const DWORD TRAFFIC_PROFILE_FLUSH_CYCLE = 3600; ///< TrafficProfiler 의 Flush cycle. 1시간 간격 static const DWORD TRAFFIC_PROFILE_FLUSH_CYCLE = 3600; ///< TrafficProfiler 의 Flush cycle. 1시간 간격
// END_OF_TRAFFIC_PROFILER // END_OF_TRAFFIC_PROFILER
// 게임과 연결되는 소켓 // 게임과 연결되는 소켓
volatile int num_events_called = 0; volatile int num_events_called = 0;
int max_bytes_written = 0; int max_bytes_written = 0;
int current_bytes_written = 0; int current_bytes_written = 0;
@ -227,7 +227,7 @@ void heartbeat(LPHEART ht, int pulse)
t = get_dword_time(); t = get_dword_time();
// 1초마다 // 1초마다
if (!(pulse % ht->passes_per_sec)) if (!(pulse % ht->passes_per_sec))
{ {
if (!g_bAuthServer) if (!g_bAuthServer)
@ -279,14 +279,14 @@ void heartbeat(LPHEART ht, int pulse)
} }
// //
// 25 PPS(Pulse per second) 라고 가정할 때 // 25 PPS(Pulse per second) 라고 가정할 때
// //
// 약 1.16초마다 // 약 1.16초마다
if (!(pulse % (passes_per_sec + 4))) if (!(pulse % (passes_per_sec + 4)))
CHARACTER_MANAGER::instance().ProcessDelayedSave(); CHARACTER_MANAGER::instance().ProcessDelayedSave();
// 약 5.08초마다 // 약 5.08초마다
if (!(pulse % (passes_per_sec * 5 + 2))) if (!(pulse % (passes_per_sec * 5 + 2)))
{ {
ITEM_MANAGER::instance().Update(); ITEM_MANAGER::instance().Update();
@ -849,7 +849,7 @@ int io_loop(event_base * base)
LPDESC d; LPDESC d;
int num_events, event_idx; int num_events, event_idx;
DESC_MANAGER::instance().DestroyClosed(); // PHASE_CLOSE인 접속들을 끊어준다. DESC_MANAGER::instance().DestroyClosed(); // PHASE_CLOSE인 접속들을 끊어준다.
DESC_MANAGER::instance().TryConnect(); DESC_MANAGER::instance().TryConnect();
// Process network events // Process network events

View File

@ -21,19 +21,19 @@ namespace marriage
DWORD dwVnum; DWORD dwVnum;
int value[MAX_LOVE_GRADE]; int value[MAX_LOVE_GRADE];
} g_ItemBonus[MAX_MARRIAGE_UNIQUE_ITEM] = { } g_ItemBonus[MAX_MARRIAGE_UNIQUE_ITEM] = {
{ 71069, { 4, 5, 6, 8, } }, // 관통 증가 { 71069, { 4, 5, 6, 8, } }, // 관통 증가
{ 71070, { 10, 12, 15, 20, } }, // 경험치 증가 { 71070, { 10, 12, 15, 20, } }, // 경험치 증가
{ 71071, { 4, 5, 6, 8, } }, // 크리티컬 증가 { 71071, { 4, 5, 6, 8, } }, // 크리티컬 증가
{ 71072, { -4, -5, -6, -8, } }, // 상대방 공격력 감소 { 71072, { -4, -5, -6, -8, } }, // 상대방 공격력 감소
{ 71073, { 20, 25, 30, 40, } }, // 공격력 증가 (절대값) { 71073, { 20, 25, 30, 40, } }, // 공격력 증가 (절대값)
{ 71074, { 12, 16, 20, 30, } }, // 방어력 증가 (절대값) { 71074, { 12, 16, 20, 30, } }, // 방어력 증가 (절대값)
//{ 71069, 1, 2, 3, 6, 8, }, // 관통 증가 //{ 71069, 1, 2, 3, 6, 8, }, // 관통 증가
//{ 71070, 5, 7, 10, 15, 20, }, // 경험치 증가 //{ 71070, 5, 7, 10, 15, 20, }, // 경험치 증가
//{ 71071, 1, 2, 3, 6, 8, }, // 크리티컬 증가 //{ 71071, 1, 2, 3, 6, 8, }, // 크리티컬 증가
//{ 71072, 5, 10, 15, 20, 30, }, // 상대방이 입은 데미지를 나에게로 //{ 71072, 5, 10, 15, 20, 30, }, // 상대방이 입은 데미지를 나에게로
//{ 71073, 10, 15, 20, 25, 40, }, // 공격력 증가 (절대값) //{ 71073, 10, 15, 20, 25, 40, }, // 공격력 증가 (절대값)
//{ 71074, 5, 10, 15, 20, 30, }, // 방어력 증가 (절대값) //{ 71074, 5, 10, 15, 20, 30, }, // 방어력 증가 (절대값)
}; };
const int MARRIAGE_POINT_PER_DAY = 1; const int MARRIAGE_POINT_PER_DAY = 1;
@ -101,17 +101,17 @@ namespace marriage
else else
days /= 86400; days /= 86400;
// 기본 50% // 기본 50%
// 원앙의 깃털 사용중일 때 : // 원앙의 깃털 사용중일 때 :
// 날짜에 의한 영향 80% 하루당 8% // 날짜에 의한 영향 80% 하루당 8%
// 전투에 의한 영향 80% // 전투에 의한 영향 80%
// 토탈 100% // 토탈 100%
// 비사용중일 때 : // 비사용중일 때 :
// 날짜에 의한 영향 60% 하루당 6% // 날짜에 의한 영향 60% 하루당 6%
// 전투에 의한 영향 60% // 전투에 의한 영향 60%
// 토탈 100% // 토탈 100%
return std::min(50 + std::min(days * point_per_day, max_limit) + std::min(love_point / 1000000, max_limit), 100); return std::min(50 + std::min(days * point_per_day, max_limit) + std::min(love_point / 1000000, max_limit), 100);
} }
@ -124,11 +124,11 @@ namespace marriage
return ch1->GetMapIndex() == ch2->GetMapIndex(); return ch1->GetMapIndex() == ch2->GetMapIndex();
// 파티 체크가 사라졌음 // 파티 체크가 사라졌음
/*if (!ch1->GetParty() || ch1->GetParty() != ch2->GetParty()) /*if (!ch1->GetParty() || ch1->GetParty() != ch2->GetParty())
return false;*/ return false;*/
// 거리 체크가 사라졌음 // 거리 체크가 사라졌음
/*const int DISTANCE = 5000; /*const int DISTANCE = 5000;
if (labs(ch1->GetX() - ch2->GetX()) > DISTANCE) if (labs(ch1->GetX() - ch2->GetX()) > DISTANCE)
@ -140,15 +140,15 @@ namespace marriage
return (DISTANCE_APPROX(ch1->GetX() - ch2->GetX(), ch1->GetY() - ch2->GetY()) < DISTANCE);*/ return (DISTANCE_APPROX(ch1->GetX() - ch2->GetX(), ch1->GetY() - ch2->GetY()) < DISTANCE);*/
} }
// 금슬 수치 // 금슬 수치
int TMarriage::GetBonus(DWORD dwItemVnum, bool bShare, LPCHARACTER me) int TMarriage::GetBonus(DWORD dwItemVnum, bool bShare, LPCHARACTER me)
{ {
if (!is_married) if (!is_married)
return 0; return 0;
// 주변에 없을때는 자기 기능만 적용된다. // 주변에 없을때는 자기 기능만 적용된다.
// 해당 아이템이 어떤 기능을 하는지 찾는다. // 해당 아이템이 어떤 기능을 하는지 찾는다.
int iFindedBonusIndex=0; int iFindedBonusIndex=0;
{ {
for (iFindedBonusIndex = 0; iFindedBonusIndex < MAX_MARRIAGE_UNIQUE_ITEM; ++iFindedBonusIndex) for (iFindedBonusIndex = 0; iFindedBonusIndex < MAX_MARRIAGE_UNIQUE_ITEM; ++iFindedBonusIndex)
@ -163,7 +163,7 @@ namespace marriage
if (bShare) if (bShare)
{ {
// 두명의 보너스를 합한다. // 두명의 보너스를 합한다.
int count = 0; int count = 0;
if (NULL != ch1 && ch1->IsEquipUniqueItem(dwItemVnum)) if (NULL != ch1 && ch1->IsEquipUniqueItem(dwItemVnum))
count ++; count ++;
@ -178,7 +178,7 @@ namespace marriage
} }
else else
{ {
// 상대방 것만 계산 // 상대방 것만 계산
int count = 0; int count = 0;
if (me != ch1 && NULL!= ch1 && ch1->IsEquipUniqueItem(dwItemVnum)) if (me != ch1 && NULL!= ch1 && ch1->IsEquipUniqueItem(dwItemVnum))
count ++; count ++;
@ -208,7 +208,7 @@ namespace marriage
SendLoverInfo(ch2, name1, GetMarriagePoint()); SendLoverInfo(ch2, name1, GetMarriagePoint());
} }
// 둘 다 이 프로세스에 로그인 중이면 포인터를 연결하고 이벤트 발생 // 둘 다 이 프로세스에 로그인 중이면 포인터를 연결하고 이벤트 발생
if (IsOnline()) if (IsOnline())
{ {
ch1->SetMarryPartner(ch2); ch1->SetMarryPartner(ch2);
@ -217,7 +217,7 @@ namespace marriage
StartNearCheckEvent(); StartNearCheckEvent();
} }
// 둘 다 로그인 되어 있다면 패킷을 보낸다. // 둘 다 로그인 되어 있다면 패킷을 보낸다.
if (is_married) if (is_married)
{ {
LPDESC d1, d2; LPDESC d1, d2;
@ -581,7 +581,7 @@ namespace marriage
if (A && B) if (A && B)
{ {
// 웨딩 맵 요청을 보낸다 // 웨딩 맵 요청을 보낸다
TPacketWeddingRequest p; TPacketWeddingRequest p;
p.dwPID1 = dwPID1; p.dwPID1 = dwPID1;
p.dwPID2 = dwPID2; p.dwPID2 = dwPID2;
@ -703,11 +703,11 @@ namespace marriage
if (!pwi) if (!pwi)
return; return;
// 결혼자들을 워프시켜야함 // 결혼자들을 워프시켜야함
pMarriage->WarpToWeddingMap(dwPID1); pMarriage->WarpToWeddingMap(dwPID1);
pMarriage->WarpToWeddingMap(dwPID2); pMarriage->WarpToWeddingMap(dwPID2);
// 등록해서 메뉴창에서 이름나와야함 // 등록해서 메뉴창에서 이름나와야함
m_setWedding.insert(make_pair(dwPID1, dwPID2)); m_setWedding.insert(make_pair(dwPID1, dwPID2));
} }
@ -726,7 +726,7 @@ namespace marriage
return; return;
} }
// 맵에서 빼내야합니다 // 맵에서 빼내야합니다
if (map_allow_find(WEDDING_MAP_INDEX)) if (map_allow_find(WEDDING_MAP_INDEX))
if (!WeddingManager::instance().End(pMarriage->pWeddingInfo->dwMapIndex)) if (!WeddingManager::instance().End(pMarriage->pWeddingInfo->dwMapIndex))
{ {

View File

@ -1,4 +1,4 @@
//#define __MATRIX_MAIN_ENABLE__ // define 되어 있으면 main 함수가 포함된다. Unit test 시에 사용 //#define __MATRIX_MAIN_ENABLE__ // define 되어 있으면 main 함수가 포함된다. Unit test 시에 사용
#ifndef __MATRIX_MAIN_ENABLE__ #ifndef __MATRIX_MAIN_ENABLE__
#include "stdafx.h" #include "stdafx.h"
#else #else

View File

@ -240,11 +240,11 @@ void MessengerManager::RemoveAllList(keyA account)
{ {
std::set<keyT> company(m_Relation[account]); std::set<keyT> company(m_Relation[account]);
/* SQL Data 삭제 */ /* SQL Data 삭제 */
DBManager::instance().Query("DELETE FROM messenger_list%s WHERE account='%s' OR companion='%s'", DBManager::instance().Query("DELETE FROM messenger_list%s WHERE account='%s' OR companion='%s'",
get_table_postfix(), account.c_str(), account.c_str()); get_table_postfix(), account.c_str(), account.c_str());
/* 내가 가지고있는 리스트 삭제 */ /* 내가 가지고있는 리스트 삭제 */
for (std::set<keyT>::iterator iter = company.begin(); for (std::set<keyT>::iterator iter = company.begin();
iter != company.end(); iter != company.end();
iter++ ) iter++ )
@ -252,7 +252,7 @@ void MessengerManager::RemoveAllList(keyA account)
this->RemoveFromList(account, *iter); this->RemoveFromList(account, *iter);
} }
/* 복사한 데이타 삭제 */ /* 복사한 데이타 삭제 */
for (std::set<keyT>::iterator iter = company.begin(); for (std::set<keyT>::iterator iter = company.begin();
iter != company.end(); iter != company.end();
) )

View File

@ -86,10 +86,10 @@ int CMonarch::HealMyEmpire(LPCHARACTER ch ,DWORD price)
f.m_bEmpire = Empire; f.m_bEmpire = Empire;
SECTREE_MANAGER::instance().for_each(iMapIndex, f); SECTREE_MANAGER::instance().for_each(iMapIndex, f);
// DB에 돈 삭감 보내기 // DB에 돈 삭감 보내기
SendtoDBDecMoney(price, Empire, ch); SendtoDBDecMoney(price, Empire, ch);
// 쿨타임 설정 // 쿨타임 설정
ch->SetMC(CHARACTER::MI_HEAL); ch->SetMC(CHARACTER::MI_HEAL);
if (test_server) if (test_server)
@ -139,7 +139,7 @@ bool CMonarch::SendtoDBDecMoney(int Money, BYTE bEmpire, LPCHARACTER ch)
if (GetMoney(bEmpire) - Money < 0) if (GetMoney(bEmpire) - Money < 0)
return false; return false;
// 실제 줄이는 부분은 서버에 갔다 온 다음에 처리된다 // 실제 줄이는 부분은 서버에 갔다 온 다음에 처리된다
int nEmpire = bEmpire; int nEmpire = bEmpire;
db_clientdesc->DBPacketHeader(HEADER_GD_DEC_MONARCH_MONEY, ch->GetDesc()->GetHandle(), sizeof(int) + sizeof(int)); db_clientdesc->DBPacketHeader(HEADER_GD_DEC_MONARCH_MONEY, ch->GetDesc()->GetHandle(), sizeof(int) + sizeof(int));
@ -153,7 +153,7 @@ bool CMonarch::AddMoney(int Money, BYTE bEmpire)
if (bEmpire >= _countof(m_MonarchInfo.money)) if (bEmpire >= _countof(m_MonarchInfo.money))
return false; return false;
// 20억 이상 입금 불가능 // 20억 이상 입금 불가능
if (GetMoney(bEmpire) + Money > 2000000000) if (GetMoney(bEmpire) + Money > 2000000000)
return false; return false;
@ -236,7 +236,7 @@ void CMonarch::PowerUp(BYTE Empire, bool On)
m_PowerUp[Empire] = On; m_PowerUp[Empire] = On;
// 군주 사자후 쿨타임 // 군주 사자후 쿨타임
m_PowerUpCT[Empire] = thecore_pulse() + PASSES_PER_SEC(60 * 10); m_PowerUpCT[Empire] = thecore_pulse() + PASSES_PER_SEC(60 * 10);
} }
@ -247,13 +247,13 @@ void CMonarch::DefenseUp(BYTE Empire, bool On)
m_DefenseUp[Empire] = On; m_DefenseUp[Empire] = On;
// 군주 금강권 쿨타임 // 군주 금강권 쿨타임
m_DefenseUpCT[Empire] = thecore_pulse() + PASSES_PER_SEC(60 * 10); m_DefenseUpCT[Empire] = thecore_pulse() + PASSES_PER_SEC(60 * 10);
} }
bool IsMonarchWarpZone (int map_idx) bool IsMonarchWarpZone (int map_idx)
{ {
// 아귀동굴, 천의동굴. // 아귀동굴, 천의동굴.
if (map_idx >= 10000) if (map_idx >= 10000)
map_idx /= 10000; map_idx /= 10000;
@ -263,9 +263,9 @@ bool IsMonarchWarpZone (int map_idx)
case 302: case 302:
case 303: case 303:
case 304: case 304:
//던전 //던전
case 351: // 적룡성 case 351: // 적룡성
case 352: // 백룡지성 case 352: // 백룡지성
return false; return false;
} }

View File

@ -476,7 +476,7 @@ bool CMotion::LoadMobSkillFromFile(const char * c_pszFileName, CMob* pMob, int i
continue; continue;
case MOTION_EVENT_TYPE_SPECIAL_ATTACKING: case MOTION_EVENT_TYPE_SPECIAL_ATTACKING:
// 구 데이터는 하나 라고 가정 // 구 데이터는 하나 라고 가정
if (!rkTextFileLoader.SetChildNode("spheredata", 0)) if (!rkTextFileLoader.SetChildNode("spheredata", 0))
{ {
SPDLOG_ERROR("Motion: no sphere data {}", c_pszFileName); SPDLOG_ERROR("Motion: no sphere data {}", c_pszFileName);

View File

@ -173,7 +173,7 @@ void P2P_MANAGER::Login(LPDESC d, const TPacketGGLogin * p)
CGuildManager::instance().P2PLoginMember(pkCCI->dwPID); CGuildManager::instance().P2PLoginMember(pkCCI->dwPID);
CPartyManager::instance().P2PLogin(pkCCI->dwPID, pkCCI->szName); CPartyManager::instance().P2PLogin(pkCCI->dwPID, pkCCI->szName);
// CCI가 생성시에만 메신저를 업데이트하면 된다. // CCI가 생성시에만 메신저를 업데이트하면 된다.
if (UpdateP2P) { if (UpdateP2P) {
std::string name(pkCCI->szName); std::string name(pkCCI->szName);
MessengerManager::instance().P2PLogin(name); MessengerManager::instance().P2PLogin(name);

View File

@ -84,7 +84,7 @@ void SendPanamaList(LPDESC d)
DWORD* ivs = (DWORD*)pack.abIV; DWORD* ivs = (DWORD*)pack.abIV;
for (int i = 0; i != 32 / sizeof(DWORD); i++) for (int i = 0; i != 32 / sizeof(DWORD); i++)
{ {
ivs[i] ^= d->GetPanamaKey() + i * 16777619; // 더블워드단위로 변형된 파나마 키를 XOR 해준다 ivs[i] ^= d->GetPanamaKey() + i * 16777619; // 더블워드단위로 변형된 파나마 키를 XOR 해준다
} }
++it; ++it;

View File

@ -34,7 +34,7 @@ void CPartyManager::DeleteAllParty()
} }
} }
bool CPartyManager::SetParty(LPCHARACTER ch) // PC만 사용해야 한다!! bool CPartyManager::SetParty(LPCHARACTER ch) // PC만 사용해야 한다!!
{ {
TPartyMap::iterator it = m_map_pkParty.find(ch->GetPlayerID()); TPartyMap::iterator it = m_map_pkParty.find(ch->GetPlayerID());
@ -295,7 +295,7 @@ void CParty::Destroy()
{ {
SPDLOG_TRACE("Party::Destroy"); SPDLOG_TRACE("Party::Destroy");
// PC가 만든 파티면 파티매니저에 맵에서 PID를 삭제해야 한다. // PC가 만든 파티면 파티매니저에 맵에서 PID를 삭제해야 한다.
if (m_bPCParty) if (m_bPCParty)
{ {
for (TMemberMap::iterator it = m_memberMap.begin(); it != m_memberMap.end(); ++it) for (TMemberMap::iterator it = m_memberMap.begin(); it != m_memberMap.end(); ++it)
@ -327,7 +327,7 @@ void CParty::Destroy()
} }
else else
{ {
// NPC일 경우 일정 시간 후 전투 중이 아닐 때 사라지게 하는 이벤트를 시작시킨다. // NPC일 경우 일정 시간 후 전투 중이 아닐 때 사라지게 하는 이벤트를 시작시킨다.
rMember.pCharacter->SetLastAttacked(dwTime); rMember.pCharacter->SetLastAttacked(dwTime);
rMember.pCharacter->StartDestroyWhenIdleEvent(); rMember.pCharacter->StartDestroyWhenIdleEvent();
} }
@ -458,7 +458,7 @@ void CParty::Join(DWORD dwPID)
TPacketPartyAdd p; TPacketPartyAdd p;
p.dwLeaderPID = GetLeaderPID(); p.dwLeaderPID = GetLeaderPID();
p.dwPID = dwPID; p.dwPID = dwPID;
p.bState = PARTY_ROLE_NORMAL; // #0000790: [M2EU] CZ 크래쉬 증가: 초기화 중요! p.bState = PARTY_ROLE_NORMAL; // #0000790: [M2EU] CZ 크래쉬 증가: 초기화 중요!
db_clientdesc->DBPacket(HEADER_GD_PARTY_ADD, 0, &p, sizeof(p)); db_clientdesc->DBPacket(HEADER_GD_PARTY_ADD, 0, &p, sizeof(p));
} }
} }
@ -504,11 +504,11 @@ void CParty::P2PQuit(DWORD dwPID)
if (m_bPCParty) if (m_bPCParty)
CPartyManager::instance().SetPartyMember(dwPID, NULL); CPartyManager::instance().SetPartyMember(dwPID, NULL);
// 리더가 나가면 파티는 해산되어야 한다. // 리더가 나가면 파티는 해산되어야 한다.
if (bRole == PARTY_ROLE_LEADER) if (bRole == PARTY_ROLE_LEADER)
CPartyManager::instance().DeleteParty(this); CPartyManager::instance().DeleteParty(this);
// 이 아래는 코드를 추가하지 말 것!!! 위 DeleteParty 하면 this는 없다. // 이 아래는 코드를 추가하지 말 것!!! 위 DeleteParty 하면 this는 없다.
} }
void CParty::Quit(DWORD dwPID) void CParty::Quit(DWORD dwPID)
@ -546,7 +546,7 @@ void CParty::Link(LPCHARACTER pkChr)
return; return;
} }
// 플레이어 파티일 경우 업데이트 이벤트 생성 // 플레이어 파티일 경우 업데이트 이벤트 생성
if (m_bPCParty && !m_eventUpdate) if (m_bPCParty && !m_eventUpdate)
{ {
party_update_event_info* info = AllocEventInfo<party_update_event_info>(); party_update_event_info* info = AllocEventInfo<party_update_event_info>();
@ -643,7 +643,7 @@ void CParty::Unlink(LPCHARACTER pkChr)
if (pkChr->IsPC()) if (pkChr->IsPC())
{ {
SendPartyUnlinkOneToAll(pkChr); SendPartyUnlinkOneToAll(pkChr);
//SendPartyUnlinkAllToOne(pkChr); // 끊기는 것이므로 구지 Unlink 패킷을 보낼 필요 없다. //SendPartyUnlinkAllToOne(pkChr); // 끊기는 것이므로 구지 Unlink 패킷을 보낼 필요 없다.
if (it->second.bRole == PARTY_ROLE_LEADER) if (it->second.bRole == PARTY_ROLE_LEADER)
{ {
@ -651,7 +651,7 @@ void CParty::Unlink(LPCHARACTER pkChr)
if (it->second.pCharacter->GetDungeon()) if (it->second.pCharacter->GetDungeon())
{ {
// TODO: 던젼에 있으면 나머지도 나간다 // TODO: 던젼에 있으면 나머지도 나간다
FExitDungeon f; FExitDungeon f;
ForEachNearMember(f); ForEachNearMember(f);
} }
@ -898,9 +898,9 @@ void CParty::SendMessage(LPCHARACTER ch, BYTE bMsg, DWORD dwArg1, DWORD dwArg2)
} }
break; break;
case PM_ATTACKED_BY: // 공격 받았음, 리더에게 도움을 요청 case PM_ATTACKED_BY: // 공격 받았음, 리더에게 도움을 요청
{ {
// 리더가 없을 때 // 리더가 없을 때
LPCHARACTER pkChrVictim = ch->GetVictim(); LPCHARACTER pkChrVictim = ch->GetVictim();
if (!pkChrVictim) if (!pkChrVictim)
@ -1067,7 +1067,7 @@ void CParty::RemoveBonusForOne(DWORD pid)
void CParty::HealParty() void CParty::HealParty()
{ {
// XXX DELETEME 클라이언트 완료될때까지 // XXX DELETEME 클라이언트 완료될때까지
{ {
return; return;
} }
@ -1355,7 +1355,7 @@ void CParty::Update()
bool bLongTimeExpBonusChanged = false; bool bLongTimeExpBonusChanged = false;
// 파티 결성 후 충분한 시간이 지나면 경험치 보너스를 받는다. // 파티 결성 후 충분한 시간이 지나면 경험치 보너스를 받는다.
if (!m_iLongTimeExpBonus && (get_dword_time() - m_dwPartyStartTime > PARTY_ENOUGH_MINUTE_FOR_EXP_BONUS * 60 * 1000 / (g_iUseLocale?1:2))) if (!m_iLongTimeExpBonus && (get_dword_time() - m_dwPartyStartTime > PARTY_ENOUGH_MINUTE_FOR_EXP_BONUS * 60 * 1000 / (g_iUseLocale?1:2)))
{ {
bLongTimeExpBonusChanged = true; bLongTimeExpBonusChanged = true;
@ -1400,9 +1400,9 @@ void CParty::Update()
if (!m_bCanUsePartyHeal && m_iLeadership >= 18) if (!m_bCanUsePartyHeal && m_iLeadership >= 18)
m_dwPartyHealTime = get_dword_time(); m_dwPartyHealTime = get_dword_time();
m_bCanUsePartyHeal = m_iLeadership >= 18; // 통솔력 18 이상은 힐을 사용할 수 있음. m_bCanUsePartyHeal = m_iLeadership >= 18; // 통솔력 18 이상은 힐을 사용할 수 있음.
// 통솔력 40이상은 파티 힐 쿨타임이 적다. // 통솔력 40이상은 파티 힐 쿨타임이 적다.
DWORD PartyHealCoolTime = (m_iLeadership >= 40) ? PARTY_HEAL_COOLTIME_SHORT * 60 * 1000 : PARTY_HEAL_COOLTIME_LONG * 60 * 1000; DWORD PartyHealCoolTime = (m_iLeadership >= 40) ? PARTY_HEAL_COOLTIME_SHORT * 60 * 1000 : PARTY_HEAL_COOLTIME_LONG * 60 * 1000;
if (m_bCanUsePartyHeal) if (m_bCanUsePartyHeal)
@ -1412,7 +1412,7 @@ void CParty::Update()
m_bPartyHealReady = true; m_bPartyHealReady = true;
// send heal ready // send heal ready
if (0) // XXX DELETEME 클라이언트 완료될때까지 if (0) // XXX DELETEME 클라이언트 완료될때까지
if (GetLeaderCharacter()) if (GetLeaderCharacter())
GetLeaderCharacter()->ChatPacket(CHAT_TYPE_COMMAND, "PartyHealReady"); GetLeaderCharacter()->ChatPacket(CHAT_TYPE_COMMAND, "PartyHealReady");
} }
@ -1681,7 +1681,7 @@ int CParty::ComputePartyBonusExpPercent()
if (leader && (leader->IsEquipUniqueItem(UNIQUE_ITEM_PARTY_BONUS_EXP) || leader->IsEquipUniqueItem(UNIQUE_ITEM_PARTY_BONUS_EXP_MALL) if (leader && (leader->IsEquipUniqueItem(UNIQUE_ITEM_PARTY_BONUS_EXP) || leader->IsEquipUniqueItem(UNIQUE_ITEM_PARTY_BONUS_EXP_MALL)
|| leader->IsEquipUniqueItem(UNIQUE_ITEM_PARTY_BONUS_EXP_GIFT) || leader->IsEquipUniqueGroup(10010))) || leader->IsEquipUniqueItem(UNIQUE_ITEM_PARTY_BONUS_EXP_GIFT) || leader->IsEquipUniqueGroup(10010)))
{ {
// 중국측 육도 적용을 확인해야한다. // 중국측 육도 적용을 확인해야한다.
if (g_iUseLocale) if (g_iUseLocale)
{ {
iBonusPartyExpFromItem = 30; iBonusPartyExpFromItem = 30;

View File

@ -64,7 +64,7 @@ bool CPolymorphUtils::PolymorphCharacter(LPCHARACTER pChar, LPITEM pItem, const
// dwDuration *= 60; // dwDuration *= 60;
// 변신 확률 = 캐릭터 레벨 - 몹 레벨 + 둔갑서 레벨 + 29 + 둔갑 스킬 레벨 // 변신 확률 = 캐릭터 레벨 - 몹 레벨 + 둔갑서 레벨 + 29 + 둔갑 스킬 레벨
iPolyPercent = pChar->GetLevel() - pMob->m_table.bLevel + pItem->GetSocket(2) + (29 + bySkillLevel); iPolyPercent = pChar->GetLevel() - pMob->m_table.bLevel + pItem->GetSocket(2) + (29 + bySkillLevel);
if (iPolyPercent <= 0) if (iPolyPercent <= 0)
@ -83,7 +83,7 @@ bool CPolymorphUtils::PolymorphCharacter(LPCHARACTER pChar, LPITEM pItem, const
pChar->AddAffect(AFFECT_POLYMORPH, POINT_POLYMORPH, pMob->m_table.dwVnum, AFF_POLYMORPH, dwDuration, 0, true); pChar->AddAffect(AFFECT_POLYMORPH, POINT_POLYMORPH, pMob->m_table.dwVnum, AFF_POLYMORPH, dwDuration, 0, true);
// 변신 보너스 = 둔갑 스킬 레벨 + 둔갑서 레벨 // 변신 보너스 = 둔갑 스킬 레벨 + 둔갑서 레벨
dwBonusPercent = bySkillLevel + pItem->GetSocket(2); dwBonusPercent = bySkillLevel + pItem->GetSocket(2);
switch (GetBonusType(pMob->m_table.dwVnum)) switch (GetBonusType(pMob->m_table.dwVnum))
@ -123,8 +123,8 @@ bool CPolymorphUtils::UpdateBookPracticeGrade(LPCHARACTER pChar, LPITEM pItem)
bool CPolymorphUtils::GiveBook(LPCHARACTER pChar, DWORD dwMobVnum, DWORD dwPracticeCount, BYTE BookLevel, BYTE LevelLimit) bool CPolymorphUtils::GiveBook(LPCHARACTER pChar, DWORD dwMobVnum, DWORD dwPracticeCount, BYTE BookLevel, BYTE LevelLimit)
{ {
// 소켓0 소켓1 소켓2 // 소켓0 소켓1 소켓2
// 둔갑할 몬스터 번호 수련정도 둔갑서 레벨 // 둔갑할 몬스터 번호 수련정도 둔갑서 레벨
if (pChar == NULL) if (pChar == NULL)
return false; return false;
@ -140,9 +140,9 @@ bool CPolymorphUtils::GiveBook(LPCHARACTER pChar, DWORD dwMobVnum, DWORD dwPract
return false; return false;
} }
pItem->SetSocket(0, dwMobVnum); // 둔갑할 몬스터 번호 pItem->SetSocket(0, dwMobVnum); // 둔갑할 몬스터 번호
pItem->SetSocket(1, dwPracticeCount); // 수련해야할 횟수 pItem->SetSocket(1, dwPracticeCount); // 수련해야할 횟수
pItem->SetSocket(2, BookLevel); // 수련레벨 pItem->SetSocket(2, BookLevel); // 수련레벨
return true; return true;
} }

View File

@ -225,7 +225,7 @@ void CPrivManager::RemoveCharacterPriv(DWORD pid, BYTE type)
int CPrivManager::GetPriv(LPCHARACTER ch, BYTE type) int CPrivManager::GetPriv(LPCHARACTER ch, BYTE type)
{ {
// 캐릭터의 변경 수치가 -라면 무조건 -만 적용되게 // 캐릭터의 변경 수치가 -라면 무조건 -만 적용되게
int val_ch = GetPrivByCharacter(ch->GetPlayerID(), type); int val_ch = GetPrivByCharacter(ch->GetPlayerID(), type);
if (val_ch < 0 && !ch->IsEquipUniqueItem(UNIQUE_ITEM_NO_BAD_LUCK_EFFECT)) if (val_ch < 0 && !ch->IsEquipUniqueItem(UNIQUE_ITEM_NO_BAD_LUCK_EFFECT))
@ -234,7 +234,7 @@ int CPrivManager::GetPriv(LPCHARACTER ch, BYTE type)
{ {
int val; int val;
// 개인, 제국, 길드, 전체 중 큰 값을 취한다. // 개인, 제국, 길드, 전체 중 큰 값을 취한다.
val = std::max(val_ch, GetPrivByEmpire(0, type)); val = std::max(val_ch, GetPrivByEmpire(0, type));
val = std::max(val, GetPrivByEmpire(ch->GetEmpire(), type)); val = std::max(val, GetPrivByEmpire(ch->GetEmpire(), type));

View File

@ -131,7 +131,7 @@ void CPVP::Win(DWORD dwPID)
m_bRevenge = true; m_bRevenge = true;
m_players[iSlot].bAgree = true; // 자동으로 동의 m_players[iSlot].bAgree = true; // 자동으로 동의
m_players[!iSlot].bCanRevenge = true; m_players[!iSlot].bCanRevenge = true;
m_players[!iSlot].bAgree = false; m_players[!iSlot].bAgree = false;
@ -180,7 +180,7 @@ void CPVPManager::Insert(LPCHARACTER pkChr, LPCHARACTER pkVictim)
if ((pkPVP = Find(kPVP.m_dwCRC))) if ((pkPVP = Find(kPVP.m_dwCRC)))
{ {
// 복수할 수 있으면 바로 싸움! // 복수할 수 있으면 바로 싸움!
if (pkPVP->Agree(pkChr->GetPlayerID())) if (pkPVP->Agree(pkChr->GetPlayerID()))
{ {
pkVictim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s\xB4\xD4\xB0\xFA\xC0\xC7 \xB4\xEB\xB0\xE1 \xBD\xC3\xC0\xDB!"), pkChr->GetName()); pkVictim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s\xB4\xD4\xB0\xFA\xC0\xC7 \xB4\xEB\xB0\xE1 \xBD\xC3\xC0\xDB!"), pkChr->GetName());
@ -299,8 +299,8 @@ void CPVPManager::GiveUp(LPCHARACTER pkChr, DWORD dwKillerPID) // This method is
} }
} }
// 리턴값: 0 = PK, 1 = PVP // 리턴값: 0 = PK, 1 = PVP
// PVP를 리턴하면 경험치나 아이템을 떨구고 PK면 떨구지 않는다. // PVP를 리턴하면 경험치나 아이템을 떨구고 PK면 떨구지 않는다.
bool CPVPManager::Dead(LPCHARACTER pkChr, DWORD dwKillerPID) bool CPVPManager::Dead(LPCHARACTER pkChr, DWORD dwKillerPID)
{ {
CPVPSetMap::iterator it = m_map_pkPVPSetByID.find(pkChr->GetPlayerID()); CPVPSetMap::iterator it = m_map_pkPVPSetByID.find(pkChr->GetPlayerID());
@ -354,7 +354,7 @@ bool CPVPManager::CanAttack(LPCHARACTER pkChr, LPCHARACTER pkVictim)
return false; return false;
} }
if (pkChr == pkVictim) // 내가 날 칠라고 하네 -_- if (pkChr == pkVictim) // 내가 날 칠라고 하네 -_-
return false; return false;
if (pkVictim->IsNPC() && pkChr->IsNPC() && !pkChr->IsGuardNPC()) if (pkVictim->IsNPC() && pkChr->IsNPC() && !pkChr->IsGuardNPC())
@ -380,7 +380,7 @@ bool CPVPManager::CanAttack(LPCHARACTER pkChr, LPCHARACTER pkVictim)
case 20116: case 20116:
case 20117: case 20117:
case 20118: case 20118:
//신규 탈것 고급 //신규 탈것 고급
case 20205: case 20205:
case 20206: case 20206:
case 20207: case 20207:
@ -389,21 +389,21 @@ bool CPVPManager::CanAttack(LPCHARACTER pkChr, LPCHARACTER pkVictim)
case 20210: case 20210:
case 20211: case 20211:
case 20212: case 20212:
case 20119: // 라마단 흑마 case 20119: // 라마단 흑마
case 20219: // 라마단 흑마 클론 (할로윈용) case 20219: // 라마단 흑마 클론 (할로윈용)
case 20220: // 크리스마스 탈것 case 20220: // 크리스마스 탈것
case 20221: // 전갑 백웅 case 20221: // 전갑 백웅
case 20222: // 전갑 팬더 case 20222: // 전갑 팬더
case 20120: case 20120:
case 20121: case 20121:
case 20122: case 20122:
case 20123: case 20123:
case 20124: case 20124:
case 20125: case 20125:
case 20214: // 난폭한 전갑순순록 case 20214: // 난폭한 전갑순순록
case 20215: // 용맹한 전갑순순록 case 20215: // 용맹한 전갑순순록
case 20217: // 난폭한 전갑암순록 case 20217: // 난폭한 전갑암순록
case 20218: // 용맹한 전갑암순록 case 20218: // 용맹한 전갑암순록
break; break;
default: default:
@ -460,7 +460,7 @@ bool CPVPManager::CanAttack(LPCHARACTER pkChr, LPCHARACTER pkVictim)
{ {
if (g_protectNormalPlayer) if (g_protectNormalPlayer)
{ {
// 범법자는 평화모드인 착한사람을 공격할 수 없다. // 범법자는 평화모드인 착한사람을 공격할 수 없다.
if (PK_MODE_PEACE == pkVictim->GetPKMode()) if (PK_MODE_PEACE == pkVictim->GetPKMode())
return false; return false;
} }
@ -592,7 +592,7 @@ void CPVPManager::SendList(LPDESC d)
if (!pkPVP->m_players[0].dwVID || !pkPVP->m_players[1].dwVID) if (!pkPVP->m_players[0].dwVID || !pkPVP->m_players[1].dwVID)
continue; continue;
// VID가 둘다 있을 경우에만 보낸다. // VID가 둘다 있을 경우에만 보낸다.
if (pkPVP->IsFight()) if (pkPVP->IsFight())
{ {
pack.bMode = PVP_MODE_FIGHT; pack.bMode = PVP_MODE_FIGHT;
@ -647,7 +647,7 @@ void CPVPManager::Process()
{ {
CPVP * pvp = (it++)->second; CPVP * pvp = (it++)->second;
if (get_dword_time() - pvp->GetLastFightTime() > 600000) // 10분 이상 싸움이 없었으면 if (get_dword_time() - pvp->GetLastFightTime() > 600000) // 10분 이상 싸움이 없었으면
{ {
pvp->Packet(true); pvp->Packet(true);
Delete(pvp); Delete(pvp);

View File

@ -35,7 +35,7 @@ namespace quest
if (!q.ServerTimer(info->npc_id, info->arg)) if (!q.ServerTimer(info->npc_id, info->arg))
return passes_per_sec / 2 + 1; return passes_per_sec / 2 + 1;
if (0 == info->time_cycle) // 루프가 아니라면 종료 시킨다. if (0 == info->time_cycle) // 루프가 아니라면 종료 시킨다.
{ {
q.ClearServerTimerNotCancel(info->name, info->arg); q.ClearServerTimerNotCancel(info->name, info->arg);
M2_DELETE_ARRAY(info->name); M2_DELETE_ARRAY(info->name);
@ -62,7 +62,7 @@ namespace quest
if (!CQuestManager::instance().Timer(info->player_id, info->npc_id)) if (!CQuestManager::instance().Timer(info->player_id, info->npc_id))
return (passes_per_sec / 2 + 1); return (passes_per_sec / 2 + 1);
if (0 == info->time_cycle) // 루프가 아니라면 종료 시킨다. if (0 == info->time_cycle) // 루프가 아니라면 종료 시킨다.
goto END_OF_TIMER_EVENT; goto END_OF_TIMER_EVENT;
} }
else else

View File

@ -443,7 +443,7 @@ namespace quest
} }
/** /**
* @version 05/06/08 Bang2ni - __get_guildid_byname 스크립트 함수 등록 * @version 05/06/08 Bang2ni - __get_guildid_byname 스크립트 함수 등록
*/ */
bool CQuestManager::InitializeLua() bool CQuestManager::InitializeLua()
{ {
@ -688,7 +688,7 @@ namespace quest
if (chReply) if (chReply)
{ {
// 시간 지나면 알아서 닫힘 // 시간 지나면 알아서 닫힘
} }
if (chWait) if (chWait)
@ -708,12 +708,12 @@ namespace quest
SPDLOG_DEBUG("GotoConfirmState vid {} msg '{}', timeout {}", dwVID, szMsg, iTimeout); SPDLOG_DEBUG("GotoConfirmState vid {} msg '{}', timeout {}", dwVID, szMsg, iTimeout);
// 1. 상대방에게 확인창 띄움 // 1. 상대방에게 확인창 띄움
// 2. 나에게 확인 기다린다고 표시하는 창 띄움 // 2. 나에게 확인 기다린다고 표시하는 창 띄움
// 3. 타임아웃 설정 (타임아웃 되면 상대방 창 닫고 나에게도 창 닫으라고 보냄) // 3. 타임아웃 설정 (타임아웃 되면 상대방 창 닫고 나에게도 창 닫으라고 보냄)
// 1 // 1
// 상대방이 없는 경우는 그냥 상대방에게 보내지 않는다. 타임아웃에 의해서 넘어가게됨 // 상대방이 없는 경우는 그냥 상대방에게 보내지 않는다. 타임아웃에 의해서 넘어가게됨
LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(dwVID); LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(dwVID);
if (ch && ch->IsPC()) if (ch && ch->IsPC())
{ {
@ -749,7 +749,7 @@ namespace quest
AddScript("[INPUT]"); AddScript("[INPUT]");
SendScript(); SendScript();
// 시간 제한을 검 // 시간 제한을 검
//event_create(input_timeout_event, dwEI, PASSES_PER_SEC(iTimeout)); //event_create(input_timeout_event, dwEI, PASSES_PER_SEC(iTimeout));
} }

View File

@ -31,7 +31,7 @@ namespace quest
return 0; return 0;
} }
if (ch->FindAffect(AFFECT_QUEST_START_IDX, applyOn)) // 퀘스트로 인해 같은 곳에 효과가 걸려있으면 스킵 if (ch->FindAffect(AFFECT_QUEST_START_IDX, applyOn)) // 퀘스트로 인해 같은 곳에 효과가 걸려있으면 스킵
return 0; return 0;
int value = (int) lua_tonumber(L, 2); int value = (int) lua_tonumber(L, 2);
@ -62,14 +62,14 @@ namespace quest
return 0; return 0;
} }
int affect_remove_bad(lua_State * L) // 나쁜 효과를 없앰 int affect_remove_bad(lua_State * L) // 나쁜 효과를 없앰
{ {
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
ch->RemoveBadAffect(); ch->RemoveBadAffect();
return 0; return 0;
} }
int affect_remove_good(lua_State * L) // 좋은 효과를 없앰 int affect_remove_good(lua_State * L) // 좋은 효과를 없앰
{ {
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
ch->RemoveGoodAffect(); ch->RemoveGoodAffect();
@ -104,7 +104,7 @@ namespace quest
return 0; return 0;
} }
int affect_remove_hair(lua_State * L) // 헤어 효과를 없앤다. int affect_remove_hair(lua_State * L) // 헤어 효과를 없앤다.
{ {
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
@ -123,7 +123,7 @@ namespace quest
return 1; return 1;
} }
// 현재 캐릭터가 AFFECT_TYPE affect를 갖고있으면 bApplyOn 값을 반환하고 없으면 nil을 반환하는 함수. // 현재 캐릭터가 AFFECT_TYPE affect를 갖고있으면 bApplyOn 값을 반환하고 없으면 nil을 반환하는 함수.
// usage : applyOn = affect.get_apply(AFFECT_TYPE) // usage : applyOn = affect.get_apply(AFFECT_TYPE)
int affect_get_apply_on(lua_State * L) int affect_get_apply_on(lua_State * L)
{ {

View File

@ -991,7 +991,7 @@ namespace quest
return 0; return 0;
} }
int dungeon_exit(lua_State* L) // 던전에 들어오기 전 위치로 보냄 int dungeon_exit(lua_State* L) // 던전에 들어오기 전 위치로 보냄
{ {
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
@ -999,7 +999,7 @@ namespace quest
return 0; return 0;
} }
int dungeon_exit_all(lua_State* L) // 던전에 있는 모든 사람을 던전에 들어오기 전 위치로 보냄 int dungeon_exit_all(lua_State* L) // 던전에 있는 모든 사람을 던전에 들어오기 전 위치로 보냄
{ {
CQuestManager& q = CQuestManager::instance(); CQuestManager& q = CQuestManager::instance();
LPDUNGEON pDungeon = q.GetCurrentDungeon(); LPDUNGEON pDungeon = q.GetCurrentDungeon();
@ -1127,7 +1127,7 @@ namespace quest
} }
}; };
int dungeon_exit_all_by_item_group (lua_State* L) // 특정 아이템 그룹에 속한 아이템이 없는사람은 강퇴 int dungeon_exit_all_by_item_group (lua_State* L) // 특정 아이템 그룹에 속한 아이템이 없는사람은 강퇴
{ {
if (!lua_isstring(L, 1)) if (!lua_isstring(L, 1))
{ {
@ -1192,7 +1192,7 @@ namespace quest
} }
}; };
int dungeon_delete_item_in_item_group_from_all(lua_State* L) // 특정 아이템을 던전 내 pc에게서 삭제. int dungeon_delete_item_in_item_group_from_all(lua_State* L) // 특정 아이템을 던전 내 pc에게서 삭제.
{ {
if (!lua_isstring(L, 1)) if (!lua_isstring(L, 1))
{ {

View File

@ -790,7 +790,7 @@ namespace quest
return 1; return 1;
} }
// 새로운 state를 만든다. // 새로운 state를 만든다.
int _set_quest_state(lua_State* L) int _set_quest_state(lua_State* L)
{ {
if (!lua_isstring(L, 1) || !lua_isstring(L, 2)) if (!lua_isstring(L, 1) || !lua_isstring(L, 2))
@ -1012,7 +1012,7 @@ namespace quest
return 0; return 0;
} }
//주의: 몹 리젠이 안되는 맵에서만 사용 //주의: 몹 리젠이 안되는 맵에서만 사용
int _regen_in_map( lua_State * L ) int _regen_in_map( lua_State * L )
{ {
int iMapIndex = static_cast<int>(lua_tonumber(L, 1)); int iMapIndex = static_cast<int>(lua_tonumber(L, 1));

View File

@ -297,12 +297,12 @@ namespace quest
int guild_change_master(lua_State* L) int guild_change_master(lua_State* L)
{ {
// 리턴값 // 리턴값
// 0 : 입력한 이름이 잘못되었음 ( 문자열이 아님 ) // 0 : 입력한 이름이 잘못되었음 ( 문자열이 아님 )
// 1 : 길드장이 아님 // 1 : 길드장이 아님
// 2 : 지정한 이름의 길드원이 없음 // 2 : 지정한 이름의 길드원이 없음
// 3 : 요청 성공 // 3 : 요청 성공
// 4 : 길드가 없음 // 4 : 길드가 없음
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
@ -338,23 +338,23 @@ namespace quest
int guild_change_master_with_limit(lua_State* L) int guild_change_master_with_limit(lua_State* L)
{ {
// 인자 // 인자
// arg0 : 새 길드장 이름 // arg0 : 새 길드장 이름
// arg1 : 새 길드장 레벨 제한 // arg1 : 새 길드장 레벨 제한
// arg2 : resign_limit 제한 시간 // arg2 : resign_limit 제한 시간
// arg3 : be_other_leader 제한 시간 // arg3 : be_other_leader 제한 시간
// arg4 : be_other_member 제한 시간 // arg4 : be_other_member 제한 시간
// arg5 : 캐시템인가 아닌가 // arg5 : 캐시템인가 아닌가
// //
// 리턴값 // 리턴값
// 0 : 입력한 이름이 잘못되었음 ( 문자열이 아님 ) // 0 : 입력한 이름이 잘못되었음 ( 문자열이 아님 )
// 1 : 길드장이 아님 // 1 : 길드장이 아님
// 2 : 지정한 이름의 길드원이 없음 // 2 : 지정한 이름의 길드원이 없음
// 3 : 요청 성공 // 3 : 요청 성공
// 4 : 길드가 없음 // 4 : 길드가 없음
// 5 : 지정한 이름이 온라인이 아님 // 5 : 지정한 이름이 온라인이 아님
// 6 : 지정한 캐릭터 레벨이 기준레벨보다 낮음 // 6 : 지정한 캐릭터 레벨이 기준레벨보다 낮음
// 7 : 새 길드장이 be_other_leader 제한에 걸림 // 7 : 새 길드장이 be_other_leader 제한에 걸림
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();

View File

@ -61,10 +61,10 @@ namespace quest
{ {
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
// 소환하면 멀리서부터 달려오는지 여부 // 소환하면 멀리서부터 달려오는지 여부
bool bFromFar = lua_isboolean(L, 1) ? lua_toboolean(L, 1) : false; bool bFromFar = lua_isboolean(L, 1) ? lua_toboolean(L, 1) : false;
// 소환수의 vnum // 소환수의 vnum
DWORD horseVnum= lua_isnumber(L, 2) ? lua_tonumber(L, 2) : 0; DWORD horseVnum= lua_isnumber(L, 2) ? lua_tonumber(L, 2) : 0;
const char* name = lua_isstring(L, 3) ? lua_tostring(L, 3) : 0; const char* name = lua_isstring(L, 3) ? lua_tostring(L, 3) : 0;
@ -212,10 +212,10 @@ namespace quest
int horse_set_name(lua_State* L) int horse_set_name(lua_State* L)
{ {
// 리턴값 // 리턴값
// 0 : 소유한 말이 없다 // 0 : 소유한 말이 없다
// 1 : 잘못된 이름이다 // 1 : 잘못된 이름이다
// 2 : 이름 바꾸기 성공 // 2 : 이름 바꾸기 성공
if ( lua_isstring(L, -1) != true ) return 0; if ( lua_isstring(L, -1) != true ) return 0;

View File

@ -437,7 +437,7 @@ namespace quest
ITEM_MANAGER::instance().FlushDelayedSave(pkNewItem); ITEM_MANAGER::instance().FlushDelayedSave(pkNewItem);
pkNewItem->AttrLog(); pkNewItem->AttrLog();
// 성공! // 성공!
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
} }

View File

@ -162,7 +162,7 @@ namespace quest
} }
if (pMarriage->pWeddingInfo) if (pMarriage->pWeddingInfo)
{ {
// 결혼식 끝내기 요청 // 결혼식 끝내기 요청
pMarriage->RequestEndWedding(); pMarriage->RequestEndWedding();
} }
return 0; return 0;

View File

@ -145,7 +145,7 @@ namespace quest
int HealPrice = quest::CQuestManager::instance().GetEventFlag("MonarchHealGold"); int HealPrice = quest::CQuestManager::instance().GetEventFlag("MonarchHealGold");
if (HealPrice == 0) if (HealPrice == 0)
HealPrice = 2000000; // 200만 HealPrice = 2000000; // 200만
if (CMonarch::instance().HealMyEmpire(ch, HealPrice)) if (CMonarch::instance().HealMyEmpire(ch, HealPrice))
{ {
@ -160,7 +160,7 @@ namespace quest
return 1; return 1;
} }
// 군주의 사자후 퀘스트 함수 // 군주의 사자후 퀘스트 함수
int monarch_powerup(lua_State * L) int monarch_powerup(lua_State * L)
{ {
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
@ -168,7 +168,7 @@ namespace quest
if (!ch) if (!ch)
return 0; return 0;
//군주 체크 //군주 체크
if (false==ch->IsMonarch()) if (false==ch->IsMonarch())
{ {
if (!ch->IsGM()) if (!ch->IsGM())
@ -179,8 +179,8 @@ namespace quest
} }
} }
//군주 국고 검사 //군주 국고 검사
int money_need = 5000000; // 500만 int money_need = 5000000; // 500만
if (!CMonarch::instance().IsMoneyOk(money_need, ch->GetEmpire())) if (!CMonarch::instance().IsMoneyOk(money_need, ch->GetEmpire()))
{ {
int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire());
@ -195,10 +195,10 @@ namespace quest
return 0; return 0;
} }
//군주의 사자후 적용 //군주의 사자후 적용
CMonarch::instance().PowerUp(ch->GetEmpire(), true); CMonarch::instance().PowerUp(ch->GetEmpire(), true);
//군주의 사자후 적용시간 //군주의 사자후 적용시간
int g_nMonarchPowerUpCT = 60 * 3; int g_nMonarchPowerUpCT = 60 * 3;
monarch_powerup_event_info* info = AllocEventInfo<monarch_powerup_event_info>(); monarch_powerup_event_info* info = AllocEventInfo<monarch_powerup_event_info>();
@ -216,7 +216,7 @@ namespace quest
return 1; return 1;
} }
// 군주의 금강권 퀘스트 함수 // 군주의 금강권 퀘스트 함수
int monarch_defenseup(lua_State * L) int monarch_defenseup(lua_State * L)
{ {
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
@ -225,7 +225,7 @@ namespace quest
return 0; return 0;
//군주 체크 //군주 체크
if (false==ch->IsMonarch()) if (false==ch->IsMonarch())
{ {
@ -237,7 +237,7 @@ namespace quest
} }
} }
int money_need = 5000000; // 500만 int money_need = 5000000; // 500만
if (!CMonarch::instance().IsMoneyOk(money_need, ch->GetEmpire())) if (!CMonarch::instance().IsMoneyOk(money_need, ch->GetEmpire()))
{ {
int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire());
@ -252,10 +252,10 @@ namespace quest
return 0; return 0;
} }
//군주의 금강권 적용 //군주의 금강권 적용
CMonarch::instance().DefenseUp(ch->GetEmpire(), true); CMonarch::instance().DefenseUp(ch->GetEmpire(), true);
//군주의 금강권 적용 시간 //군주의 금강권 적용 시간
int g_nMonarchDefenseUpCT = 60 * 3; int g_nMonarchDefenseUpCT = 60 * 3;
monarch_defenseup_event_info* info = AllocEventInfo<monarch_defenseup_event_info>(); monarch_defenseup_event_info* info = AllocEventInfo<monarch_defenseup_event_info>();
@ -326,9 +326,9 @@ namespace quest
int x = ch->GetX(); int x = ch->GetX();
int y = ch->GetY(); int y = ch->GetY();
#if 0 #if 0
if (11505 == mob_vnum) // 황금두꺼비 if (11505 == mob_vnum) // 황금두꺼비
{ {
//군주 국고 검사 //군주 국고 검사
if (!CMonarch::instance().IsMoneyOk(CASTLE_FROG_PRICE, ch->GetEmpire())) if (!CMonarch::instance().IsMoneyOk(CASTLE_FROG_PRICE, ch->GetEmpire()))
{ {
int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire());
@ -340,7 +340,7 @@ namespace quest
if (mob) if (mob)
{ {
// 국고감소 // 국고감소
CMonarch::instance().SendtoDBDecMoney(CASTLE_FROG_PRICE, ch->GetEmpire(), ch); CMonarch::instance().SendtoDBDecMoney(CASTLE_FROG_PRICE, ch->GetEmpire(), ch);
castle_save(); castle_save();
} }
@ -417,7 +417,7 @@ namespace quest
{ {
int money_need = castle_cost_of_hiring_guard(group_vnum); int money_need = castle_cost_of_hiring_guard(group_vnum);
//군주 국고 검사 //군주 국고 검사
if (!CMonarch::instance().IsMoneyOk(money_need, ch->GetEmpire())) if (!CMonarch::instance().IsMoneyOk(money_need, ch->GetEmpire()))
{ {
int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire());
@ -428,7 +428,7 @@ namespace quest
if (guard_leader) if (guard_leader)
{ {
// 국고감소 // 국고감소
CMonarch::instance().SendtoDBDecMoney(money_need, ch->GetEmpire(), ch); CMonarch::instance().SendtoDBDecMoney(money_need, ch->GetEmpire(), ch);
castle_save(); castle_save();
} }
@ -491,7 +491,7 @@ namespace quest
return 0; return 0;
} }
//군주 쿨타임 검사 //군주 쿨타임 검사
if (!ch->IsMCOK(CHARACTER::MI_WARP)) if (!ch->IsMCOK(CHARACTER::MI_WARP))
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d \xC3\xCA\xB0\xA3 \xC4\xF0\xC5\xB8\xC0\xD3\xC0\xCC \xC0\xFB\xBF\xEB\xC1\xDF\xC0\xD4\xB4\xCF\xB4\xD9."), ch->GetMCLTime(CHARACTER::MI_WARP)); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d \xC3\xCA\xB0\xA3 \xC4\xF0\xC5\xB8\xC0\xD3\xC0\xCC \xC0\xFB\xBF\xEB\xC1\xDF\xC0\xD4\xB4\xCF\xB4\xD9."), ch->GetMCLTime(CHARACTER::MI_WARP));
@ -499,10 +499,10 @@ namespace quest
} }
//군주 몹 소환 비용 //군주 몹 소환 비용
const int WarpPrice = 10000; const int WarpPrice = 10000;
//군주 국고 검사 //군주 국고 검사
if (!CMonarch::instance().IsMoneyOk(WarpPrice, ch->GetEmpire())) if (!CMonarch::instance().IsMoneyOk(WarpPrice, ch->GetEmpire()))
{ {
int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire());
@ -547,10 +547,10 @@ namespace quest
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s \xBF\xA1\xB0\xD4\xB7\xCE \xC0\xCC\xB5\xBF\xC7\xD5\xB4\xCF\xB4\xD9"), name.c_str()); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s \xBF\xA1\xB0\xD4\xB7\xCE \xC0\xCC\xB5\xBF\xC7\xD5\xB4\xCF\xB4\xD9"), name.c_str());
ch->WarpSet(pos.x, pos.y); ch->WarpSet(pos.x, pos.y);
//군주 돈 삭감 //군주 돈 삭감
CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch);
//쿨타임 초기화 //쿨타임 초기화
ch->SetMC(CHARACTER::MI_WARP); ch->SetMC(CHARACTER::MI_WARP);
} }
@ -584,10 +584,10 @@ namespace quest
ch->WarpSet(x,y); ch->WarpSet(x,y);
ch->Stop(); ch->Stop();
//군주 돈 삭감 //군주 돈 삭감
CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch);
//쿨타임 초기화 //쿨타임 초기화
ch->SetMC(CHARACTER::MI_WARP); ch->SetMC(CHARACTER::MI_WARP);
return 0; return 0;
@ -646,17 +646,17 @@ namespace quest
return 0; return 0;
} }
// 군주 쿨타임 검사 // 군주 쿨타임 검사
if (!ch->IsMCOK(CHARACTER::MI_TRANSFER)) if (!ch->IsMCOK(CHARACTER::MI_TRANSFER))
{ {
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d \xC3\xCA\xB0\xA3 \xC4\xF0\xC5\xB8\xC0\xD3\xC0\xCC \xC0\xFB\xBF\xEB\xC1\xDF\xC0\xD4\xB4\xCF\xB4\xD9."), ch->GetMCLTime(CHARACTER::MI_TRANSFER)); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d \xC3\xCA\xB0\xA3 \xC4\xF0\xC5\xB8\xC0\xD3\xC0\xCC \xC0\xFB\xBF\xEB\xC1\xDF\xC0\xD4\xB4\xCF\xB4\xD9."), ch->GetMCLTime(CHARACTER::MI_TRANSFER));
return 0; return 0;
} }
// 군주 워프 비용 // 군주 워프 비용
const int WarpPrice = 10000; const int WarpPrice = 10000;
// 군주 국고 검사 // 군주 국고 검사
if (!CMonarch::instance().IsMoneyOk(WarpPrice, ch->GetEmpire())) if (!CMonarch::instance().IsMoneyOk(WarpPrice, ch->GetEmpire()))
{ {
int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire());
@ -705,10 +705,10 @@ namespace quest
P2P_MANAGER::instance().Send(&pgg, sizeof(TPacketGGTransfer)); P2P_MANAGER::instance().Send(&pgg, sizeof(TPacketGGTransfer));
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s \xB4\xD4\xC0\xBB \xBC\xD2\xC8\xAF\xC7\xCF\xBF\xB4\xBD\xC0\xB4\xCF\xB4\xD9."), name.c_str()); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s \xB4\xD4\xC0\xBB \xBC\xD2\xC8\xAF\xC7\xCF\xBF\xB4\xBD\xC0\xB4\xCF\xB4\xD9."), name.c_str());
// 군주 돈 삭감 // 군주 돈 삭감
CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch);
// 쿨타임 초기화 // 쿨타임 초기화
ch->SetMC(CHARACTER::MI_TRANSFER); ch->SetMC(CHARACTER::MI_TRANSFER);
} }
else else
@ -743,9 +743,9 @@ namespace quest
} }
tch->WarpSet(ch->GetX(), ch->GetY(), ch->GetMapIndex()); tch->WarpSet(ch->GetX(), ch->GetY(), ch->GetMapIndex());
// 군주 돈 삭감 // 군주 돈 삭감
CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch);
// 쿨타임 초기화 // 쿨타임 초기화
ch->SetMC(CHARACTER::MI_TRANSFER); ch->SetMC(CHARACTER::MI_TRANSFER);
return 0; return 0;
} }

View File

@ -323,8 +323,8 @@ namespace quest
} }
}; };
// 파티 단위로 버프 주는 함수. // 파티 단위로 버프 주는 함수.
// 같은 맵에 있는 파티원만 영향을 받는다. // 같은 맵에 있는 파티원만 영향을 받는다.
int party_give_buff (lua_State* L) int party_give_buff (lua_State* L)
{ {
CQuestManager & q = CQuestManager::instance(); CQuestManager & q = CQuestManager::instance();
@ -405,7 +405,7 @@ namespace quest
{ "is_in_dungeon", party_is_in_dungeon }, { "is_in_dungeon", party_is_in_dungeon },
{ "give_buff", party_give_buff }, { "give_buff", party_give_buff },
{ "is_map_member_flag_lt", party_is_map_member_flag_lt }, { "is_map_member_flag_lt", party_is_map_member_flag_lt },
{ "get_member_pids", party_get_member_pids }, // 파티원들의 pid를 return { "get_member_pids", party_get_member_pids }, // 파티원들의 pid를 return
{ NULL, NULL } { NULL, NULL }
}; };

View File

@ -232,7 +232,7 @@ namespace quest
return; return;
} }
//PREVENT_PORTAL_AFTER_EXCHANGE //PREVENT_PORTAL_AFTER_EXCHANGE
//교환 후 시간체크 //교환 후 시간체크
if ( iPulse - pkChr->GetExchangeTime() < PASSES_PER_SEC(60) ) if ( iPulse - pkChr->GetExchangeTime() < PASSES_PER_SEC(60) )
{ {
pkChr->ChatPacket( CHAT_TYPE_INFO, LC_TEXT("\xB0\xC5\xB7\xA1 \xC8\xC4 1\xBA\xD0 \xC0\xCC\xB3\xBB\xBF\xA1\xB4\xC2 \xB4\xD9\xB8\xA5\xC1\xF6\xBF\xAA\xC0\xB8\xB7\xCE \xC0\xCC\xB5\xBF \xC7\xD2 \xBC\xF6 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9." ) ); pkChr->ChatPacket( CHAT_TYPE_INFO, LC_TEXT("\xB0\xC5\xB7\xA1 \xC8\xC4 1\xBA\xD0 \xC0\xCC\xB3\xBB\xBF\xA1\xB4\xC2 \xB4\xD9\xB8\xA5\xC1\xF6\xBF\xAA\xC0\xB8\xB7\xCE \xC0\xCC\xB5\xBF \xC7\xD2 \xBC\xF6 \xBE\xF8\xBD\xC0\xB4\xCF\xB4\xD9." ) );
@ -447,7 +447,7 @@ namespace quest
DWORD dwVnum; DWORD dwVnum;
if (lua_isnumber(L,2)) // 번호인경우 번호로 준다. if (lua_isnumber(L,2)) // 번호인경우 번호로 준다.
dwVnum = (int) lua_tonumber(L, 2); dwVnum = (int) lua_tonumber(L, 2);
else if (!ITEM_MANAGER::instance().GetVnum(lua_tostring(L, 2), dwVnum)) else if (!ITEM_MANAGER::instance().GetVnum(lua_tostring(L, 2), dwVnum))
{ {
@ -487,7 +487,7 @@ namespace quest
DWORD dwVnum; DWORD dwVnum;
if (lua_isnumber(L, 1)) // 번호인경우 번호로 준다. if (lua_isnumber(L, 1)) // 번호인경우 번호로 준다.
{ {
dwVnum = (int) lua_tonumber(L, 1); dwVnum = (int) lua_tonumber(L, 1);
} }
@ -543,7 +543,7 @@ namespace quest
DWORD dwVnum; DWORD dwVnum;
if (lua_isnumber(L, 1)) // 번호인경우 번호로 준다. if (lua_isnumber(L, 1)) // 번호인경우 번호로 준다.
{ {
dwVnum = (int) lua_tonumber(L, 1); dwVnum = (int) lua_tonumber(L, 1);
} }
@ -804,7 +804,7 @@ namespace quest
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
if (val > 0) // 증가시키는 것이므로 무조건 성공 리턴 if (val > 0) // 증가시키는 것이므로 무조건 성공 리턴
ch->PointChange(POINT_SP, val); ch->PointChange(POINT_SP, val);
else if (val < 0) else if (val < 0)
{ {
@ -857,18 +857,18 @@ namespace quest
PC* pPC = CQuestManager::instance().GetCurrentPC(); PC* pPC = CQuestManager::instance().GetCurrentPC();
LogManager::instance().QuestRewardLog(pPC->GetCurrentQuestName().c_str(), ch->GetPlayerID(), ch->GetLevel(), newLevel, 0); LogManager::instance().QuestRewardLog(pPC->GetCurrentQuestName().c_str(), ch->GetPlayerID(), ch->GetLevel(), newLevel, 0);
//포인트 : 스킬, 서브스킬, 스탯 //포인트 : 스킬, 서브스킬, 스탯
ch->PointChange(POINT_SKILL, newLevel - ch->GetLevel()); ch->PointChange(POINT_SKILL, newLevel - ch->GetLevel());
ch->PointChange(POINT_SUB_SKILL, newLevel < 10 ? 0 : newLevel - std::max(ch->GetLevel(), 9)); ch->PointChange(POINT_SUB_SKILL, newLevel < 10 ? 0 : newLevel - std::max(ch->GetLevel(), 9));
ch->PointChange(POINT_STAT, ((std::clamp(newLevel, 1, 90) - ch->GetLevel()) * 3) + ch->GetPoint(POINT_LEVEL_STEP)); ch->PointChange(POINT_STAT, ((std::clamp(newLevel, 1, 90) - ch->GetLevel()) * 3) + ch->GetPoint(POINT_LEVEL_STEP));
//레벨 //레벨
ch->PointChange(POINT_LEVEL, newLevel - ch->GetLevel(), false, true); ch->PointChange(POINT_LEVEL, newLevel - ch->GetLevel(), false, true);
//HP, SP //HP, SP
ch->SetRandomHP((newLevel - 1) * Random::get(JobInitialPoints[ch->GetJob()].hp_per_lv_begin, JobInitialPoints[ch->GetJob()].hp_per_lv_end)); ch->SetRandomHP((newLevel - 1) * Random::get(JobInitialPoints[ch->GetJob()].hp_per_lv_begin, JobInitialPoints[ch->GetJob()].hp_per_lv_end));
ch->SetRandomSP((newLevel - 1) * Random::get(JobInitialPoints[ch->GetJob()].sp_per_lv_begin, JobInitialPoints[ch->GetJob()].sp_per_lv_end)); ch->SetRandomSP((newLevel - 1) * Random::get(JobInitialPoints[ch->GetJob()].sp_per_lv_begin, JobInitialPoints[ch->GetJob()].sp_per_lv_end));
// 회복 // 회복
ch->PointChange(POINT_HP, ch->GetMaxHP() - ch->GetHP()); ch->PointChange(POINT_HP, ch->GetMaxHP() - ch->GetHP());
ch->PointChange(POINT_SP, ch->GetMaxSP() - ch->GetSP()); ch->PointChange(POINT_SP, ch->GetMaxSP() - ch->GetSP());
@ -931,8 +931,8 @@ namespace quest
return 1; return 1;
} }
// 20050725.myevan.은둔의 망토 사용중 혼석 수련시 선악치가 두배 소모되는 버그가 발생해 // 20050725.myevan.은둔의 망토 사용중 혼석 수련시 선악치가 두배 소모되는 버그가 발생해
// 실제 선악치를 이용해 계산을 하게 한다. // 실제 선악치를 이용해 계산을 하게 한다.
int pc_get_real_alignment(lua_State* L) int pc_get_real_alignment(lua_State* L)
{ {
lua_pushnumber(L, CQuestManager::instance().GetCurrentCharacterPtr()->GetRealAlignment()/10); lua_pushnumber(L, CQuestManager::instance().GetCurrentCharacterPtr()->GetRealAlignment()/10);
@ -1257,7 +1257,7 @@ namespace quest
ch->RemoveAffect(AFFECT_MOUNT); ch->RemoveAffect(AFFECT_MOUNT);
ch->RemoveAffect(AFFECT_MOUNT_BONUS); ch->RemoveAffect(AFFECT_MOUNT_BONUS);
// 말이 소환되어 따라다니는 상태라면 말부터 없앰 // 말이 소환되어 따라다니는 상태라면 말부터 없앰
if (ch->GetHorse()) if (ch->GetHorse())
ch->HorseSummon(false); ch->HorseSummon(false);
@ -1525,7 +1525,7 @@ namespace quest
if (pct == 100 || Random::get(1, 100) <= pct) if (pct == 100 || Random::get(1, 100) <= pct)
{ {
// 개량 성공 // 개량 성공
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
LPITEM pkNewItem = ITEM_MANAGER::instance().CreateItem(item->GetRefinedVnum(), 1, 0, false); LPITEM pkNewItem = ITEM_MANAGER::instance().CreateItem(item->GetRefinedVnum(), 1, 0, false);
@ -1562,7 +1562,7 @@ namespace quest
} }
else else
{ {
// 개량 실패 // 개량 실패
lua_pushboolean(L, 0); lua_pushboolean(L, 0);
} }
@ -1599,7 +1599,7 @@ namespace quest
pdw[1] = 1; pdw[1] = 1;
pdw[2] = q.GetEventFlag("lotto_round"); pdw[2] = q.GetEventFlag("lotto_round");
// 추첨서는 소켓을 설정한다 // 추첨서는 소켓을 설정한다
DBManager::instance().ReturnQuery(QID_LOTTO, ch->GetPlayerID(), pdw, DBManager::instance().ReturnQuery(QID_LOTTO, ch->GetPlayerID(), pdw,
"INSERT INTO lotto_list VALUES(0, 'server%s', %u, NOW())", "INSERT INTO lotto_list VALUES(0, 'server%s', %u, NOW())",
get_table_postfix(), ch->GetPlayerID()); get_table_postfix(), ch->GetPlayerID());
@ -1848,14 +1848,14 @@ namespace quest
return 0; return 0;
} }
//텔레포트 //텔레포트
int pc_teleport ( lua_State * L ) int pc_teleport ( lua_State * L )
{ {
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
int x=0,y=0; int x=0,y=0;
if ( lua_isnumber(L, 1) ) if ( lua_isnumber(L, 1) )
{ {
// 지역명 워프 // 지역명 워프
const int TOWN_NUM = 10; const int TOWN_NUM = 10;
struct warp_by_town_name struct warp_by_town_name
{ {
@ -2056,13 +2056,13 @@ teleport_area:
int pc_change_name(lua_State* L) int pc_change_name(lua_State* L)
{ {
// 리턴값 // 리턴값
// 0: 새이름을 설정한 뒤 로그아웃을 안했음 // 0: 새이름을 설정한 뒤 로그아웃을 안했음
// 1: 스크립트에서 문자열이 넘어오지 않았음 // 1: 스크립트에서 문자열이 넘어오지 않았음
// 2: check_name 을 통과하지 못했음 // 2: check_name 을 통과하지 못했음
// 3: 이미 같은 이름이 사용중 // 3: 이미 같은 이름이 사용중
// 4: 성공 // 4: 성공
// 5: 해당 기능 지원하지 않음 // 5: 해당 기능 지원하지 않음
if ( LC_IsEurope() ) if ( LC_IsEurope() )
{ {
lua_pushnumber(L, 5); lua_pushnumber(L, 5);
@ -2102,7 +2102,7 @@ teleport_area:
int count = 0; int count = 0;
str_to_number(count, row[0]); str_to_number(count, row[0]);
// 이미 해당 이름을 가진 캐릭터가 있음 // 이미 해당 이름을 가진 캐릭터가 있음
if ( count != 0 ) if ( count != 0 )
{ {
lua_pushnumber(L, 3); lua_pushnumber(L, 3);
@ -2353,8 +2353,8 @@ teleport_area:
int idx = 1; int idx = 1;
// 용혼석 슬롯은 할 필요 없을 듯. // 용혼석 슬롯은 할 필요 없을 듯.
// 이 함수는 탈석서용 함수인 듯 하다. // 이 함수는 탈석서용 함수인 듯 하다.
for ( int i=0; i < INVENTORY_MAX_NUM + WEAR_MAX_NUM; i++ ) for ( int i=0; i < INVENTORY_MAX_NUM + WEAR_MAX_NUM; i++ )
{ {
LPITEM pItem = pChar->GetInventoryItem(i); LPITEM pItem = pChar->GetInventoryItem(i);
@ -2743,7 +2743,7 @@ teleport_area:
return 1; return 1;
} }
int pc_get_informer_type(lua_State* L) //독일 선물 기능 int pc_get_informer_type(lua_State* L) //독일 선물 기능
{ {
LPCHARACTER pChar = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER pChar = CQuestManager::instance().GetCurrentCharacterPtr();
@ -2986,17 +2986,17 @@ teleport_area:
{ "charge_cash", pc_charge_cash }, { "charge_cash", pc_charge_cash },
{ "get_informer_type", pc_get_informer_type }, //독일 선물 기능 { "get_informer_type", pc_get_informer_type }, //독일 선물 기능
{ "get_informer_item", pc_get_informer_item }, { "get_informer_item", pc_get_informer_item },
{ "give_award", pc_give_award }, //일본 계정당 한번씩 금괴 지급 { "give_award", pc_give_award }, //일본 계정당 한번씩 금괴 지급
{ "give_award_socket", pc_give_award_socket }, //몰 인벤토리에 아이템 지급. 소켓 설정을 위한 함수. { "give_award_socket", pc_give_award_socket }, //몰 인벤토리에 아이템 지급. 소켓 설정을 위한 함수.
{ "get_killee_drop_pct", pc_get_killee_drop_pct }, /* mob_vnum.kill 이벤트에서 killee와 pc와의 level 차이, pc의 프리미엄 드랍률 등등을 고려한 아이템 드랍 확률. { "get_killee_drop_pct", pc_get_killee_drop_pct }, /* mob_vnum.kill 이벤트에서 killee와 pc와의 level 차이, pc의 프리미엄 드랍률 등등을 고려한 아이템 드랍 확률.
* return 값은 (분자, 분모). * return 값은 (분자, 분모).
* (말이 복잡한데, CreateDropItem의 GetDropPct의 iDeltaPercent, iRandRange를 return한다고 보면 됨.) * (말이 복잡한데, CreateDropItem의 GetDropPct의 iDeltaPercent, iRandRange를 return한다고 보면 됨.)
* (이 말이 더 어려울라나 ㅠㅠ) * (이 말이 더 어려울라나 ㅠㅠ)
* 주의사항 : kill event에서만 사용할 것! * 주의사항 : kill event에서만 사용할 것!
*/ */
{ NULL, NULL } { NULL, NULL }

View File

@ -34,13 +34,13 @@ namespace quest
return 1; return 1;
} }
// 소환수의 vnum // 소환수의 vnum
DWORD mobVnum= lua_isnumber(L, 1) ? lua_tonumber(L, 1) : 0; DWORD mobVnum= lua_isnumber(L, 1) ? lua_tonumber(L, 1) : 0;
// 소환수의 이름 // 소환수의 이름
const char* petName = lua_isstring(L, 2) ? lua_tostring(L, 2) : 0; const char* petName = lua_isstring(L, 2) ? lua_tostring(L, 2) : 0;
// 소환하면 멀리서부터 달려오는지 여부 // 소환하면 멀리서부터 달려오는지 여부
bool bFromFar = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : false; bool bFromFar = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : false;
CPetActor* pet = petSystem->Summon(mobVnum, pItem, petName, bFromFar); CPetActor* pet = petSystem->Summon(mobVnum, pItem, petName, bFromFar);
@ -62,7 +62,7 @@ namespace quest
if (0 == petSystem) if (0 == petSystem)
return 0; return 0;
// 소환수의 vnum // 소환수의 vnum
DWORD mobVnum= lua_isnumber(L, 1) ? lua_tonumber(L, 1) : 0; DWORD mobVnum= lua_isnumber(L, 1) ? lua_tonumber(L, 1) : 0;
petSystem->Unsummon(mobVnum); petSystem->Unsummon(mobVnum);
@ -94,7 +94,7 @@ namespace quest
if (0 == petSystem) if (0 == petSystem)
return 0; return 0;
// 소환수의 vnum // 소환수의 vnum
DWORD mobVnum= lua_isnumber(L, 1) ? lua_tonumber(L, 1) : 0; DWORD mobVnum= lua_isnumber(L, 1) ? lua_tonumber(L, 1) : 0;
CPetActor* petActor = petSystem->GetByVnum(mobVnum); CPetActor* petActor = petSystem->GetByVnum(mobVnum);

View File

@ -140,7 +140,7 @@ namespace quest
int quest_coroutine_yield(lua_State * L) int quest_coroutine_yield(lua_State * L)
{ {
CQuestManager& q = CQuestManager::instance(); CQuestManager& q = CQuestManager::instance();
// other_pc_block 내부에서는 yield가 일어나서는 안된다. 절대로. // other_pc_block 내부에서는 yield가 일어나서는 안된다. 절대로.
if (q.IsInOtherPCBlock()) if (q.IsInOtherPCBlock())
{ {
quest_err("FATAL ERROR! Yield occur in other_pc_block."); quest_err("FATAL ERROR! Yield occur in other_pc_block.");
@ -214,10 +214,10 @@ namespace quest
{ "done", quest_done }, { "done", quest_done },
{ "getcurrentquestindex", quest_get_current_quest_index }, { "getcurrentquestindex", quest_get_current_quest_index },
{ "no_send", quest_no_send }, { "no_send", quest_no_send },
// begin_other_pc_block(pid), end_other_pc_block 사이를 other_pc_block이라고 하자. // begin_other_pc_block(pid), end_other_pc_block 사이를 other_pc_block이라고 하자.
// other_pc_block에서는 current_pc가 pid로 변경된다. // other_pc_block에서는 current_pc가 pid로 변경된다.
// 끝나면 다시 원래의 current_pc로 돌아간다. // 끝나면 다시 원래의 current_pc로 돌아간다.
/* 이런 것을 위해 만듬. /* 이런 것을 위해 만듬.
for i, pid in next, pids, nil do for i, pid in next, pids, nil do
q.begin_other_pc_block(pid) q.begin_other_pc_block(pid)
if pc.count_item(PASS_TICKET) < 1 then if pc.count_item(PASS_TICKET) < 1 then
@ -227,7 +227,7 @@ namespace quest
q.end_other_pc_block() q.end_other_pc_block()
end end
*/ */
// 주의 : other_pc_block 내부에서는 절대로 yield가 일어나서는 안된다.(ex. wait, select, input, ...) // 주의 : other_pc_block 내부에서는 절대로 yield가 일어나서는 안된다.(ex. wait, select, input, ...)
{ "begin_other_pc_block", quest_begin_other_pc_block }, { "begin_other_pc_block", quest_begin_other_pc_block },
{ "end_other_pc_block", quest_end_other_pc_block }, { "end_other_pc_block", quest_end_other_pc_block },
{ NULL, NULL } { NULL, NULL }

View File

@ -69,7 +69,7 @@ namespace quest
return 0; return 0;
} }
// 현재 퀘스트에 등록된 타겟을 삭제 한다. // 현재 퀘스트에 등록된 타겟을 삭제 한다.
int target_delete(lua_State* L) int target_delete(lua_State* L)
{ {
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
@ -86,7 +86,7 @@ namespace quest
return 0; return 0;
} }
// 현재 퀘스트 인덱스로 되어있는 타겟을 모두 삭제한다. // 현재 퀘스트 인덱스로 되어있는 타겟을 모두 삭제한다.
int target_clear(lua_State* L) int target_clear(lua_State* L)
{ {
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();

View File

@ -57,29 +57,29 @@ namespace quest
m_pSelectedDungeon = NULL; m_pSelectedDungeon = NULL;
m_mapEventName.insert(TEventNameMap::value_type("click", QUEST_CLICK_EVENT)); // NPC를 클릭 m_mapEventName.insert(TEventNameMap::value_type("click", QUEST_CLICK_EVENT)); // NPC를 클릭
m_mapEventName.insert(TEventNameMap::value_type("kill", QUEST_KILL_EVENT)); // Mob을 사냥 m_mapEventName.insert(TEventNameMap::value_type("kill", QUEST_KILL_EVENT)); // Mob을 사냥
m_mapEventName.insert(TEventNameMap::value_type("timer", QUEST_TIMER_EVENT)); // 미리 지정해둔 시간이 지남 m_mapEventName.insert(TEventNameMap::value_type("timer", QUEST_TIMER_EVENT)); // 미리 지정해둔 시간이 지남
m_mapEventName.insert(TEventNameMap::value_type("levelup", QUEST_LEVELUP_EVENT)); // 레벨업을 함 m_mapEventName.insert(TEventNameMap::value_type("levelup", QUEST_LEVELUP_EVENT)); // 레벨업을 함
m_mapEventName.insert(TEventNameMap::value_type("login", QUEST_LOGIN_EVENT)); // 로그인 시 m_mapEventName.insert(TEventNameMap::value_type("login", QUEST_LOGIN_EVENT)); // 로그인 시
m_mapEventName.insert(TEventNameMap::value_type("logout", QUEST_LOGOUT_EVENT)); // 로그아웃 시 m_mapEventName.insert(TEventNameMap::value_type("logout", QUEST_LOGOUT_EVENT)); // 로그아웃 시
m_mapEventName.insert(TEventNameMap::value_type("button", QUEST_BUTTON_EVENT)); // 퀘스트 버튼을 누름 m_mapEventName.insert(TEventNameMap::value_type("button", QUEST_BUTTON_EVENT)); // 퀘스트 버튼을 누름
m_mapEventName.insert(TEventNameMap::value_type("info", QUEST_INFO_EVENT)); // 퀘스트 정보창을 염 m_mapEventName.insert(TEventNameMap::value_type("info", QUEST_INFO_EVENT)); // 퀘스트 정보창을 염
m_mapEventName.insert(TEventNameMap::value_type("chat", QUEST_CHAT_EVENT)); // 특정 키워드로 대화를 함 m_mapEventName.insert(TEventNameMap::value_type("chat", QUEST_CHAT_EVENT)); // 특정 키워드로 대화를 함
m_mapEventName.insert(TEventNameMap::value_type("in", QUEST_ATTR_IN_EVENT)); // 맵의 특정 속성에 들어감 m_mapEventName.insert(TEventNameMap::value_type("in", QUEST_ATTR_IN_EVENT)); // 맵의 특정 속성에 들어감
m_mapEventName.insert(TEventNameMap::value_type("out", QUEST_ATTR_OUT_EVENT)); // 맵의 특정 속성에서 나옴 m_mapEventName.insert(TEventNameMap::value_type("out", QUEST_ATTR_OUT_EVENT)); // 맵의 특정 속성에서 나옴
m_mapEventName.insert(TEventNameMap::value_type("use", QUEST_ITEM_USE_EVENT)); // 퀘스트 아이템을 사용 m_mapEventName.insert(TEventNameMap::value_type("use", QUEST_ITEM_USE_EVENT)); // 퀘스트 아이템을 사용
m_mapEventName.insert(TEventNameMap::value_type("server_timer", QUEST_SERVER_TIMER_EVENT)); // 서버 타이머 (아직 테스트 안됐음) m_mapEventName.insert(TEventNameMap::value_type("server_timer", QUEST_SERVER_TIMER_EVENT)); // 서버 타이머 (아직 테스트 안됐음)
m_mapEventName.insert(TEventNameMap::value_type("enter", QUEST_ENTER_STATE_EVENT)); // 현재 스테이트가 됨 m_mapEventName.insert(TEventNameMap::value_type("enter", QUEST_ENTER_STATE_EVENT)); // 현재 스테이트가 됨
m_mapEventName.insert(TEventNameMap::value_type("leave", QUEST_LEAVE_STATE_EVENT)); // 현재 스테이트에서 다른 스테이트로 바뀜 m_mapEventName.insert(TEventNameMap::value_type("leave", QUEST_LEAVE_STATE_EVENT)); // 현재 스테이트에서 다른 스테이트로 바뀜
m_mapEventName.insert(TEventNameMap::value_type("letter", QUEST_LETTER_EVENT)); // 로긴 하거나 스테이트가 바껴 새로 정보를 세팅해줘야함 m_mapEventName.insert(TEventNameMap::value_type("letter", QUEST_LETTER_EVENT)); // 로긴 하거나 스테이트가 바껴 새로 정보를 세팅해줘야함
m_mapEventName.insert(TEventNameMap::value_type("take", QUEST_ITEM_TAKE_EVENT)); // 아이템을 받음 m_mapEventName.insert(TEventNameMap::value_type("take", QUEST_ITEM_TAKE_EVENT)); // 아이템을 받음
m_mapEventName.insert(TEventNameMap::value_type("target", QUEST_TARGET_EVENT)); // 타겟 m_mapEventName.insert(TEventNameMap::value_type("target", QUEST_TARGET_EVENT)); // 타겟
m_mapEventName.insert(TEventNameMap::value_type("party_kill", QUEST_PARTY_KILL_EVENT)); // 파티 멤버가 몬스터를 사냥 (리더에게 옴) m_mapEventName.insert(TEventNameMap::value_type("party_kill", QUEST_PARTY_KILL_EVENT)); // 파티 멤버가 몬스터를 사냥 (리더에게 옴)
m_mapEventName.insert(TEventNameMap::value_type("unmount", QUEST_UNMOUNT_EVENT)); m_mapEventName.insert(TEventNameMap::value_type("unmount", QUEST_UNMOUNT_EVENT));
m_mapEventName.insert(TEventNameMap::value_type("pick", QUEST_ITEM_PICK_EVENT)); // 떨어져있는 아이템을 습득함. m_mapEventName.insert(TEventNameMap::value_type("pick", QUEST_ITEM_PICK_EVENT)); // 떨어져있는 아이템을 습득함.
m_mapEventName.insert(TEventNameMap::value_type("sig_use", QUEST_SIG_USE_EVENT)); // Special item group에 속한 아이템을 사용함. m_mapEventName.insert(TEventNameMap::value_type("sig_use", QUEST_SIG_USE_EVENT)); // Special item group에 속한 아이템을 사용함.
m_mapEventName.insert(TEventNameMap::value_type("item_informer", QUEST_ITEM_INFORMER_EVENT)); // 독일선물기능테스트 m_mapEventName.insert(TEventNameMap::value_type("item_informer", QUEST_ITEM_INFORMER_EVENT)); // 독일선물기능테스트
m_bNoSend = false; m_bNoSend = false;
@ -253,9 +253,9 @@ namespace quest
if (!pPC->GetRunningQuestState()->chat_scripts.empty()) if (!pPC->GetRunningQuestState()->chat_scripts.empty())
{ {
// 채팅 이벤트인 경우 // 채팅 이벤트인 경우
// 현재 퀘스트는 어느 퀘스트를 실행할 것인가를 고르는 퀘스트 이므로 // 현재 퀘스트는 어느 퀘스트를 실행할 것인가를 고르는 퀘스트 이므로
// 끝내고 선택된 퀘스트를 실행한다. // 끝내고 선택된 퀘스트를 실행한다.
QuestState& old_qs = *pPC->GetRunningQuestState(); QuestState& old_qs = *pPC->GetRunningQuestState();
CloseState(old_qs); CloseState(old_qs);
@ -368,7 +368,7 @@ namespace quest
pPC->CancelRunning(); pPC->CancelRunning();
} }
// 지우기 전에 로그아웃 한다. // 지우기 전에 로그아웃 한다.
Logout(ch->GetPlayerID()); Logout(ch->GetPlayerID());
if (ch == m_pCurrentCharacter) if (ch == m_pCurrentCharacter)
@ -380,7 +380,7 @@ namespace quest
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// //
// Quest Event 관련 // Quest Event 관련
// //
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
void CQuestManager::Login(unsigned int pc, const char * c_pszQuest) void CQuestManager::Login(unsigned int pc, const char * c_pszQuest)
@ -427,9 +427,9 @@ namespace quest
if (!CheckQuestLoaded(pPC)) if (!CheckQuestLoaded(pPC))
return; return;
/* [hyo] 몹 kill시 중복 카운팅 이슈 관련한 수정사항 /* [hyo] 몹 kill시 중복 카운팅 이슈 관련한 수정사항
quest script에 when 171.kill begin ... 등의 코드로 인하여 스크립트가 처리되었더라도 quest script에 when 171.kill begin ... 등의 코드로 인하여 스크립트가 처리되었더라도
바로 return하지 않고 다른 검사도 수행하도록 변경함. (2011/07/21) 바로 return하지 않고 다른 검사도 수행하도록 변경함. (2011/07/21)
*/ */
// call script // call script
m_mapNPC[npc].OnKill(*pPC); m_mapNPC[npc].OnKill(*pPC);
@ -684,7 +684,7 @@ namespace quest
} }
} }
// Speical Item Group에 정의된 Group Use // Speical Item Group에 정의된 Group Use
bool CQuestManager::SIGUse(unsigned int pc, DWORD sig_vnum, LPITEM item, bool bReceiveAll) bool CQuestManager::SIGUse(unsigned int pc, DWORD sig_vnum, LPITEM item, bool bReceiveAll)
{ {
SPDLOG_TRACE("questmanager::SIGUse Start : itemVnum : {} PC : {}", item->GetOriginalVnum(), pc); SPDLOG_TRACE("questmanager::SIGUse Start : itemVnum : {} PC : {}", item->GetOriginalVnum(), pc);
@ -826,7 +826,7 @@ namespace quest
else else
SPDLOG_ERROR("QUEST no such pc id : {}", pc); SPDLOG_ERROR("QUEST no such pc id : {}", pc);
} }
//독일 선물 기능 테스트 //독일 선물 기능 테스트
void CQuestManager::ItemInformer(unsigned int pc,unsigned int vnum) void CQuestManager::ItemInformer(unsigned int pc,unsigned int vnum)
{ {
@ -836,7 +836,7 @@ namespace quest
m_mapNPC[QUEST_NO_NPC].OnItemInformer(*pPC,vnum); m_mapNPC[QUEST_NO_NPC].OnItemInformer(*pPC,vnum);
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// END OF 퀘스트 이벤트 처리 // END OF 퀘스트 이벤트 처리
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -1258,19 +1258,19 @@ namespace quest
continue; continue;
if (value) if (value)
{ {
// 밤 // 밤
ch->ChatPacket(CHAT_TYPE_COMMAND, "DayMode dark"); ch->ChatPacket(CHAT_TYPE_COMMAND, "DayMode dark");
} }
else else
{ {
// 낮 // 낮
ch->ChatPacket(CHAT_TYPE_COMMAND, "DayMode light"); ch->ChatPacket(CHAT_TYPE_COMMAND, "DayMode light");
} }
} }
if (value && !prev_value) if (value && !prev_value)
{ {
// 없으면 만들어준다 // 없으면 만들어준다
struct SNPCSellFireworkPosition struct SNPCSellFireworkPosition
{ {
int lMapIndex; int lMapIndex;
@ -1306,7 +1306,7 @@ namespace quest
} }
else if (!value && prev_value) else if (!value && prev_value)
{ {
// 있으면 지워준다 // 있으면 지워준다
CharacterVectorInteractor i; CharacterVectorInteractor i;
if (CHARACTER_MANAGER::instance().GetCharactersByRaceNum(xmas::MOB_XMAS_FIRWORK_SELLER_VNUM, i)) if (CHARACTER_MANAGER::instance().GetCharactersByRaceNum(xmas::MOB_XMAS_FIRWORK_SELLER_VNUM, i))
@ -1395,7 +1395,7 @@ namespace quest
} }
else if (name == "new_xmas_event") else if (name == "new_xmas_event")
{ {
// 20126 new산타. // 20126 new산타.
static DWORD new_santa = 20126; static DWORD new_santa = 20126;
if (value != 0) if (value != 0)
{ {
@ -1534,12 +1534,12 @@ namespace quest
bool CQuestManager::ExecuteQuestScript(PC& pc, const string& quest_name, const int state, const char* code, const int code_size, vector<AArgScript*>* pChatScripts, bool bUseCache) bool CQuestManager::ExecuteQuestScript(PC& pc, const string& quest_name, const int state, const char* code, const int code_size, vector<AArgScript*>* pChatScripts, bool bUseCache)
{ {
// 실행공간을 생성 // 실행공간을 생성
QuestState qs = CQuestManager::instance().OpenState(quest_name, state); QuestState qs = CQuestManager::instance().OpenState(quest_name, state);
if (pChatScripts) if (pChatScripts)
qs.chat_scripts.swap(*pChatScripts); qs.chat_scripts.swap(*pChatScripts);
// 코드를 읽어들임 // 코드를 읽어들임
if (bUseCache) if (bUseCache)
{ {
lua_getglobal(qs.co, "__codecache"); lua_getglobal(qs.co, "__codecache");
@ -1578,10 +1578,10 @@ namespace quest
else else
luaL_loadbuffer(qs.co, code, code_size, quest_name.c_str()); luaL_loadbuffer(qs.co, code, code_size, quest_name.c_str());
// 플레이어와 연결 // 플레이어와 연결
pc.SetQuest(quest_name, qs); pc.SetQuest(quest_name, qs);
// 실행 // 실행
QuestState& rqs = *pc.GetRunningQuestState(); QuestState& rqs = *pc.GetRunningQuestState();
if (!CQuestManager::instance().RunState(rqs)) if (!CQuestManager::instance().RunState(rqs))
{ {

View File

@ -131,7 +131,7 @@ namespace quest
// //
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// 순서 Index (여러개 있을 수 있으므로 있는 것임, 실제 index 값은 쓰지 않음) // 순서 Index (여러개 있을 수 있으므로 있는 것임, 실제 index 값은 쓰지 않음)
j = i; j = i;
i = s.find('.', i + 1); i = s.find('.', i + 1);
@ -410,7 +410,7 @@ namespace quest
void operator()(PC::QuestInfoIterator& itPCQuest, NPC::QuestMapType::iterator& itQuestMap) void operator()(PC::QuestInfoIterator& itPCQuest, NPC::QuestMapType::iterator& itQuestMap)
{ {
// 없으니 새로 시작 // 없으니 새로 시작
DWORD dwQuestIndex = itQuestMap->first; DWORD dwQuestIndex = itQuestMap->first;
if (NPC::HasStartState(itQuestMap->second) && CQuestManager::instance().CanStartQuest(dwQuestIndex)) if (NPC::HasStartState(itQuestMap->second) && CQuestManager::instance().CanStartQuest(dwQuestIndex))
@ -494,8 +494,8 @@ namespace quest
for (int i = 0; i < fMatch.size; i++) for (int i = 0; i < fMatch.size; i++)
{ {
if ( i != 0 ) { if ( i != 0 ) {
//2012.05.14 <김용욱> : 퀘스트 매니저의 m_pCurrentPC가 바뀌는 경우가 발생하여, //2012.05.14 <김용욱> : 퀘스트 매니저의 m_pCurrentPC가 바뀌는 경우가 발생하여,
//두개 이상의 스크립트를 실행시, 두번째 부터는 퀘스트 매니저의 PC 값을 새로 셋팅한다. //두개 이상의 스크립트를 실행시, 두번째 부터는 퀘스트 매니저의 PC 값을 새로 셋팅한다.
PC * pPC = CQuestManager::instance().GetPC(pc.GetID()); PC * pPC = CQuestManager::instance().GetPC(pc.GetID());
} }
@ -805,7 +805,7 @@ namespace quest
QuestMapType & rmapEventOwnQuest = m_mapOwnQuest[EventIndex]; QuestMapType & rmapEventOwnQuest = m_mapOwnQuest[EventIndex];
QuestMapType::iterator itQuestMap = rmapEventOwnQuest.find(quest_index); QuestMapType::iterator itQuestMap = rmapEventOwnQuest.find(quest_index);
// 그런 퀘스트가 없음 // 그런 퀘스트가 없음
if (itQuestMap == rmapEventOwnQuest.end()) if (itQuestMap == rmapEventOwnQuest.end())
return false; return false;
@ -817,7 +817,7 @@ namespace quest
} }
else else
{ {
// 새로 시작할까요? // 새로 시작할까요?
if (CQuestManager::instance().CanStartQuest(itQuestMap->first, pc) && HasStartState(itQuestMap->second)) if (CQuestManager::instance().CanStartQuest(itQuestMap->first, pc) && HasStartState(itQuestMap->second))
iState = 0; iState = 0;
else else
@ -962,7 +962,7 @@ namespace quest
else else
return HandleEvent(pc, QUEST_ITEM_PICK_EVENT); return HandleEvent(pc, QUEST_ITEM_PICK_EVENT);
} }
//독일 선물 기능 테스트 //독일 선물 기능 테스트
bool NPC::OnItemInformer(PC& pc, unsigned int vnum) bool NPC::OnItemInformer(PC& pc, unsigned int vnum)
{ {
return HandleEvent(pc, QUEST_ITEM_INFORMER_EVENT); return HandleEvent(pc, QUEST_ITEM_INFORMER_EVENT);

View File

@ -307,10 +307,10 @@ namespace quest
{ {
LPCHARACTER npc = CQuestManager::instance().GetCurrentNPCCharacterPtr(); LPCHARACTER npc = CQuestManager::instance().GetCurrentNPCCharacterPtr();
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
// npc 있었던 경우 // npc 있었던 경우
if (npc && !npc->IsPC()) if (npc && !npc->IsPC())
{ {
// 그 엔피씨가 나에게 락인 경우 // 그 엔피씨가 나에게 락인 경우
if (ch->GetPlayerID() == npc->GetQuestNPCID()) if (ch->GetPlayerID() == npc->GetQuestNPCID())
{ {
npc->SetQuestNPCID(0); npc->SetQuestNPCID(0);

View File

@ -24,7 +24,7 @@ enum ERegenModes
MODE_VNUM MODE_VNUM
}; };
static bool get_word(FILE *fp, char *buf) // 워드단위로 받는다. static bool get_word(FILE *fp, char *buf) // 워드단위로 받는다.
{ {
int i = 0; int i = 0;
int c; int c;
@ -172,7 +172,7 @@ static bool read_line(FILE *fp, LPREGEN regen)
case MODE_Z_SECTION: case MODE_Z_SECTION:
str_to_number(regen->z_section, szTmp); str_to_number(regen->z_section, szTmp);
// 익셉션 이면 나가주자. // 익셉션 이면 나가주자.
if (regen->type == REGEN_TYPE_EXCEPTION) if (regen->type == REGEN_TYPE_EXCEPTION)
return true; return true;
@ -500,7 +500,7 @@ bool regen_do(const char* filename, int lMapIndex, int base_x, int base_y, LPDUN
// before the call to CHARACTER::SetRegen() // before the call to CHARACTER::SetRegen()
} }
// 처음엔 무조건 리젠 해준다. // 처음엔 무조건 리젠 해준다.
regen_spawn_dungeon(regen, pDungeon, bOnce); regen_spawn_dungeon(regen, pDungeon, bOnce);
} }
@ -576,7 +576,7 @@ bool regen_load_in_file(const char* filename, int lMapIndex, int base_x, int bas
} }
} }
// 처음엔 무조건 리젠 해준다. // 처음엔 무조건 리젠 해준다.
regen_spawn(regen, true); regen_spawn(regen, true);
} }
} }
@ -683,11 +683,11 @@ bool regen_load(const char* filename, int lMapIndex, int base_x, int base_y)
} }
//NO_REGEN //NO_REGEN
// Desc: regen.txt (외 리젠관련 텍스트 ) 에서 리젠 시간을 0으로 세팅할시 // Desc: regen.txt (외 리젠관련 텍스트 ) 에서 리젠 시간을 0으로 세팅할시
// 리젠을 하지 안한다. // 리젠을 하지 안한다.
if (regen->time != 0) if (regen->time != 0)
{ {
// 처음엔 무조건 리젠 해준다. // 처음엔 무조건 리젠 해준다.
regen_spawn(regen, false); regen_spawn(regen, false);
regen_event_info* info = AllocEventInfo<regen_event_info>(); regen_event_info* info = AllocEventInfo<regen_event_info>();
@ -752,14 +752,14 @@ void regen_reset(int x, int y)
if (!regen->event) if (!regen->event)
continue; continue;
// 좌표가 있으면 좌표 내에 있는 리젠 리스트만 리젠 시킨다. // 좌표가 있으면 좌표 내에 있는 리젠 리스트만 리젠 시킨다.
if (x != 0 || y != 0) if (x != 0 || y != 0)
{ {
if (x >= regen->sx && x <= regen->ex) if (x >= regen->sx && x <= regen->ex)
if (y >= regen->sy && y <= regen->ey) if (y >= regen->sy && y <= regen->ey)
event_reset_time(regen->event, 1); event_reset_time(regen->event, 1);
} }
// 없으면 전부 리젠 // 없으면 전부 리젠
else else
event_reset_time(regen->event, 1); event_reset_time(regen->event, 1);
} }

Some files were not shown because too many files have changed in this diff Show More