Cringe
-
Posts
11 -
Joined
-
Last visited
-
Feedback
0%
Content Type
Forums
Store
Third Party - Providers Directory
Feature Plan
Release Notes
Docs
Events
Posts posted by Cringe
-
-
-
7 hours ago, WeedHex said:
Change whole source or at least the code about wolfman. Char_skill there is a chaos.
char_skill.cpp
Spoiler#include "stdafx.h"
#include <sstream>#include "utils.h"
#include "config.h"
#include "vector.h"
#include "char.h"
#include "char_manager.h"
#include "battle.h"
#include "desc.h"
#include "desc_manager.h"
#include "packet.h"
#include "affect.h"
#include "item.h"
#include "sectree_manager.h"
#include "mob_manager.h"
#include "start_position.h"
#include "party.h"
#include "buffer_manager.h"
#include "guild.h"
#include "log.h"
#include "unique_item.h"
#include "questmanager.h"extern int test_server;
static const DWORD s_adwSubSkillVnums[] =
{
SKILL_LEADERSHIP,
SKILL_COMBO,
SKILL_MINING,
SKILL_LANGUAGE1,
SKILL_LANGUAGE2,
SKILL_LANGUAGE3,
SKILL_POLYMORPH,
SKILL_HORSE,
SKILL_HORSE_SUMMON,
SKILL_HORSE_WILDATTACK,
SKILL_HORSE_CHARGE,
SKILL_HORSE_ESCAPE,
SKILL_HORSE_WILDATTACK_RANGE,
SKILL_ADD_HP,
SKILL_RESIST_PENETRATE
};struct FPartyPIDCollector
{
std::vector <DWORD> vecPIDs;
FPartyPIDCollector()
{
}
void operator () (LPCHARACTER ch)
{
vecPIDs.push_back(ch->GetPlayerID());
}
};time_t CHARACTER::GetSkillNextReadTime(DWORD dwVnum) const
{
if (dwVnum >= SKILL_MAX_NUM)
{
sys_err("vnum overflow (vnum: %u)", dwVnum);
return 0;
}return m_pSkillLevels ? m_pSkillLevels[dwVnum].tNextRead : 0;
}void CHARACTER::SetSkillNextReadTime(DWORD dwVnum, time_t time)
{
if (m_pSkillLevels && dwVnum < SKILL_MAX_NUM)
m_pSkillLevels[dwVnum].tNextRead = time;
}bool TSkillUseInfo::HitOnce(DWORD dwVnum)
{
// 쓰지도않았으면 때리지도 못한다.
if (!bUsed)
return false;sys_log(1, "__HitOnce NextUse %u current %u count %d scount %d", dwNextSkillUsableTime, get_dword_time(), iHitCount, iSplashCount);
if (dwNextSkillUsableTime && dwNextSkillUsableTime<get_dword_time() && dwVnum != SKILL_MUYEONG && dwVnum != SKILL_HORSE_WILDATTACK)
{
sys_log(1, "__HitOnce can't hit");return false;
}if (iHitCount == -1)
{
sys_log(1, "__HitOnce OK %d %d %d", dwNextSkillUsableTime, get_dword_time(), iHitCount);
return true;
}if (iHitCount)
{
sys_log(1, "__HitOnce OK %d %d %d", dwNextSkillUsableTime, get_dword_time(), iHitCount);
iHitCount--;
return true;
}
return false;
}bool TSkillUseInfo::UseSkill(bool isGrandMaster, DWORD vid, DWORD dwCooltime, int splashcount, int hitcount, int range)
{
this->isGrandMaster = isGrandMaster;
DWORD dwCur = get_dword_time();// 아직 쿨타임이 끝나지 않았다.
if (bUsed && dwNextSkillUsableTime > dwCur)
{
sys_log(0, "cooltime is not over delta %u", dwNextSkillUsableTime - dwCur);
iHitCount = 0;
return false;
}bUsed = true;
if (dwCooltime)
dwNextSkillUsableTime = dwCur + dwCooltime;
else
dwNextSkillUsableTime = 0;iRange = range;
iMaxHitCount = iHitCount = hitcount;if (test_server)
sys_log(0, "UseSkill NextUse %u current %u cooltime %d hitcount %d/%d", dwNextSkillUsableTime, dwCur, dwCooltime, iHitCount, iMaxHitCount);dwVID = vid;
iSplashCount = splashcount;
return true;
}int CHARACTER::GetChainLightningMaxCount() const
{
return aiChainLightningCountBySkillLevel[MIN(SKILL_MAX_LEVEL, GetSkillLevel(SKILL_CHAIN))];
}void CHARACTER::SetAffectedEunhyung()
{
m_dwAffectedEunhyungLevel = GetSkillPower(SKILL_EUNHYUNG);
}void CHARACTER::SetSkillGroup(BYTE bSkillGroup)
{
if (bSkillGroup > 2)
return;if (GetLevel() < 5)
return;m_points.skill_group = bSkillGroup;
TPacketGCChangeSkillGroup p;
p.header = HEADER_GC_SKILL_GROUP;
p.skill_group = m_points.skill_group;GetDesc()->Packet(&p, sizeof(TPacketGCChangeSkillGroup));
}int CHARACTER::ComputeCooltime(int time)
{
return CalculateDuration(GetPoint(POINT_CASTING_SPEED), time);
}void CHARACTER::SkillLevelPacket()
{
if (!GetDesc())
return;TPacketGCSkillLevel pack;
pack.bHeader = HEADER_GC_SKILL_LEVEL;
thecore_memcpy(&pack.skills, m_pSkillLevels, sizeof(TPlayerSkill) * SKILL_MAX_NUM);
GetDesc()->Packet(&pack, sizeof(TPacketGCSkillLevel));
}void CHARACTER::SetSkillLevel(DWORD dwVnum, BYTE bLev)
{
if (NULL == m_pSkillLevels)
return;if (dwVnum >= SKILL_MAX_NUM)
{
sys_err("vnum overflow (vnum %u)", dwVnum);
return;
}m_pSkillLevels[dwVnum].bLevel = MIN(40, bLev);
if (bLev >= 40)
m_pSkillLevels[dwVnum].bMasterType = SKILL_PERFECT_MASTER;
else if (bLev >= 30)
m_pSkillLevels[dwVnum].bMasterType = SKILL_GRAND_MASTER;
else if (bLev >= 20)
m_pSkillLevels[dwVnum].bMasterType = SKILL_MASTER;
else
m_pSkillLevels[dwVnum].bMasterType = SKILL_NORMAL;
}bool CHARACTER::IsLearnableSkill(DWORD dwSkillVnum) const
{
const CSkillProto * pkSkill = CSkillManager::instance().Get(dwSkillVnum);
if (!pkSkill)
return false;if (GetSkillLevel(dwSkillVnum) >= SKILL_MAX_LEVEL)
return false;if (pkSkill->dwType == 0)
{
if (GetSkillLevel(dwSkillVnum) >= pkSkill->bMaxLevel)
return false;return true;
}if (pkSkill->dwType == 5)
{
if (dwSkillVnum == SKILL_HORSE_WILDATTACK_RANGE && GetJob() != JOB_ASSASSIN)
return false;return true;
}if (GetSkillGroup() == 0)
return false;if (pkSkill->dwType - 1 == GetJob())
return true;if (pkSkill->dwType == 5)
{
if (SKILL_7_A_ANTI_TANHWAN <= dwSkillVnum && dwSkillVnum <= SKILL_7_D_ANTI_YONGBI)
{
for (int i = 0 ; i < 4 ; i++)
{
if (unsigned(SKILL_7_A_ANTI_TANHWAN + i) != dwSkillVnum)
{
if (0 != GetSkillLevel(SKILL_7_A_ANTI_TANHWAN + i))
{
return false;
}
}
}return true;
}if (SKILL_8_A_ANTI_GIGONGCHAM <= dwSkillVnum && dwSkillVnum <= SKILL_8_D_ANTI_BYEURAK)
{
for (int i = 0 ; i < 4 ; i++)
{
if (unsigned(SKILL_8_A_ANTI_GIGONGCHAM + i) != dwSkillVnum)
{
if (0 != GetSkillLevel(SKILL_8_A_ANTI_GIGONGCHAM + i))
return false;
}
}
return true;
}
}if (pkSkill->dwType == 6)
{
if (dwSkillVnum >= SKILL_CHAYEOL && dwSkillVnum <= SKILL_CHEONGRANG)
{
return true;
}
}return false;
}// ADD_GRANDMASTER_SKILL
bool CHARACTER::LearnGrandMasterSkill(DWORD dwSkillVnum)
{
CSkillProto * pkSk = CSkillManager::instance().Get(dwSkillVnum);if (!pkSk)
return false;if (!IsLearnableSkill(dwSkillVnum))
{
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("수련할 수 없는 스킬입니다."));
return false;
}sys_log(0, "learn grand master skill[%d] cur %d, next %d", dwSkillVnum, get_global_time(), GetSkillNextReadTime(dwSkillVnum));
/*
if (get_global_time() < GetSkillNextReadTime(dwSkillVnum))
{
if (!(test_server && quest::CQuestManager::instance().GetEventFlag("no_read_delay")))
{
if (FindAffect(AFFECT_SKILL_NO_BOOK_DELAY))
{
// 주안술서 사용중에는 시간 제한 무시
RemoveAffect(AFFECT_SKILL_NO_BOOK_DELAY);
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("주안술서를 통해 주화입마에서 빠져나왔습니다."));
}
else
{
SkillLearnWaitMoreTimeMessage(GetSkillNextReadTime(dwSkillVnum) - get_global_time());
return false;
}
}
}
*/// bType이 0이면 처음부터 책으로 수련 가능
if (pkSk->dwType == 0)
{
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("그랜드 마스터 수련을 할 수 없는 스킬입니다."));
return false;
}if (GetSkillMasterType(dwSkillVnum) != SKILL_GRAND_MASTER)
{
if (GetSkillMasterType(dwSkillVnum) > SKILL_GRAND_MASTER)
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("퍼펙트 마스터된 스킬입니다. 더 이상 수련 할 수 없습니다."));
else
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("이 스킬은 아직 그랜드 마스터 수련을 할 경지에 이르지 않았습니다."));
return false;
}std::string strTrainSkill;
{
std::ostringstream os;
os << "training_grandmaster_skill.skill" << dwSkillVnum;
strTrainSkill = os.str();
}// 여기서 확률을 계산합니다.
BYTE bLastLevel = GetSkillLevel(dwSkillVnum);int idx = MIN(9, GetSkillLevel(dwSkillVnum) - 30);
sys_log(0, "LearnGrandMasterSkill %s table idx %d value %d", GetName(), idx, aiGrandMasterSkillBookCountForLevelUp[idx]);
int iTotalReadCount = GetQuestFlag(strTrainSkill) + 1;
SetQuestFlag(strTrainSkill, iTotalReadCount);int iMinReadCount = aiGrandMasterSkillBookMinCount[idx];
int iMaxReadCount = aiGrandMasterSkillBookMaxCount[idx];int iBookCount = aiGrandMasterSkillBookCountForLevelUp[idx];
if ( LC_IsYMIR() == true || LC_IsKorea() == true )
{
const int aiGrandMasterSkillBookCountForLevelUp_euckr[10] =
{
3, 3, 4, 5, 6, 7, 8, 9, 10, 15,
};const int aiGrandMasterSkillBookMinCount_euckr[10] =
{
1, 1, 1, 2, 2, 2, 3, 3, 4, 5
};const int aiGrandMasterSkillBookMaxCount_euckr[10] =
{
5, 7, 9, 11, 13, 15, 18, 23, 25, 30
};iMinReadCount = aiGrandMasterSkillBookMinCount_euckr[idx];
iMaxReadCount = aiGrandMasterSkillBookMaxCount_euckr[idx];
iBookCount = aiGrandMasterSkillBookCountForLevelUp_euckr[idx];
}if (FindAffect(AFFECT_SKILL_BOOK_BONUS))
{
if (iBookCount&1)
iBookCount = iBookCount / 2 + 1;
else
iBookCount = iBookCount / 2;RemoveAffect(AFFECT_SKILL_BOOK_BONUS);
}int n = number(1, iBookCount);
sys_log(0, "Number(%d)", n);DWORD nextTime = get_global_time() + number(28800, 43200);
sys_log(0, "GrandMaster SkillBookCount min %d cur %d max %d (next_time=%d)", iMinReadCount, iTotalReadCount, iMaxReadCount, nextTime);
bool bSuccess = n == 2;
if (iTotalReadCount < iMinReadCount)
bSuccess = false;
if (iTotalReadCount > iMaxReadCount)
bSuccess = true;if (bSuccess)
{
SkillLevelUp(dwSkillVnum, SKILL_UP_BY_QUEST);
}SetSkillNextReadTime(dwSkillVnum, nextTime);
if (bLastLevel == GetSkillLevel(dwSkillVnum))
{
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("크윽, 기가 역류하고 있어! 이거 설마 주화입마인가!? 젠장!"));
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("수련이 실패로 끝났습니다. 다시 도전해주시기 바랍니다."));
LogManager::instance().CharLog(this, dwSkillVnum, "GM_READ_FAIL", "");
return false;
}ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("몸에서 뭔가 힘이 터져 나오는 기분이야!"));
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("뜨거운 무엇이 계속 용솟음치고 있어! 이건, 이것은!"));
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("더 높은 경지의 수련을 성공적으로 끝내셨습니다."));
LogManager::instance().CharLog(this, dwSkillVnum, "GM_READ_SUCCESS", "");
return true;
}
// END_OF_ADD_GRANDMASTER_SKILLstatic bool FN_should_check_exp(LPCHARACTER ch)
{
if (LC_IsCanada())
return ch->GetLevel() < gPlayerMaxLevel;if (!LC_IsYMIR())
return true;return false;
}
bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb)
{
const CSkillProto* pkSk = CSkillManager::instance().Get(dwSkillVnum);if (!pkSk)
return false;if (!IsLearnableSkill(dwSkillVnum))
{
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("수련할 수 없는 스킬입니다."));
return false;
}DWORD need_exp = 0;
if (FN_should_check_exp(this))
{
need_exp = 0;if ( GetExp() < need_exp )
{
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("경험치가 부족하여 책을 읽을 수 없습니다."));
return false;
}
}// bType이 0이면 처음부터 책으로 수련 가능
if (pkSk->dwType != 0)
{
if (GetSkillMasterType(dwSkillVnum) != SKILL_MASTER)
{
if (GetSkillMasterType(dwSkillVnum) > SKILL_MASTER)
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("이 스킬은 책으로 더이상 수련할 수 없습니다."));
else
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("이 스킬은 아직 책으로 수련할 경지에 이르지 않았습니다."));
return false;
}
}if (get_global_time() < GetSkillNextReadTime(dwSkillVnum))
{
if (!(test_server && quest::CQuestManager::instance().GetEventFlag("no_read_delay")))
{
if (FindAffect(AFFECT_SKILL_NO_BOOK_DELAY))
{
// 주안술서 사용중에는 시간 제한 무시
RemoveAffect(AFFECT_SKILL_NO_BOOK_DELAY);
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("주안술서를 통해 주화입마에서 빠져나왔습니다."));
}
else
{
SkillLearnWaitMoreTimeMessage(GetSkillNextReadTime(dwSkillVnum) - get_global_time());
return false;
}
}
}// 여기서 확률을 계산합니다.
BYTE bLastLevel = GetSkillLevel(dwSkillVnum);if (bProb != 0)
{
// SKILL_BOOK_BONUS
if (FindAffect(AFFECT_SKILL_BOOK_BONUS))
{
bProb += bProb / 2;
RemoveAffect(AFFECT_SKILL_BOOK_BONUS);
}
// END_OF_SKILL_BOOK_BONUSsys_log(0, "LearnSkillByBook Pct %u prob %d", dwSkillVnum, bProb);
if (number(1, 100) <= bProb)
{
if (test_server)
sys_log(0, "LearnSkillByBook %u SUCC", dwSkillVnum);SkillLevelUp(dwSkillVnum, SKILL_UP_BY_BOOK);
}
else
{
if (test_server)
sys_log(0, "LearnSkillByBook %u FAIL", dwSkillVnum);
}
}
else
{
int idx = MIN(9, GetSkillLevel(dwSkillVnum) - 20);sys_log(0, "LearnSkillByBook %s table idx %d value %d", GetName(), idx, aiSkillBookCountForLevelUp[idx]);
if (!LC_IsYMIR())
{
int need_bookcount = GetSkillLevel(dwSkillVnum) - 20;PointChange(POINT_EXP, -need_exp);
quest::CQuestManager& q = quest::CQuestManager::instance();
quest::PC* pPC = q.GetPC(GetPlayerID());if (pPC)
{
char flag[128+1];
memset(flag, 0, sizeof(flag));
snprintf(flag, sizeof(flag), "traning_master_skill.%u.read_count", dwSkillVnum);int read_count = pPC->GetFlag(flag);
int percent = 65;if (FindAffect(AFFECT_SKILL_BOOK_BONUS))
{
percent = 0;
RemoveAffect(AFFECT_SKILL_BOOK_BONUS);
}if (number(1, 100) > percent)
{
// 책읽기에 성공
if (read_count >= need_bookcount)
{
SkillLevelUp(dwSkillVnum, SKILL_UP_BY_BOOK);
pPC->SetFlag(flag, 0);ChatPacket(CHAT_TYPE_INFO, LC_TEXT("책으로 더 높은 경지의 수련을 성공적으로 끝내셨습니다."));
LogManager::instance().CharLog(this, dwSkillVnum, "READ_SUCCESS", "");
return true;
}
else
{
pPC->SetFlag(flag, read_count + 1);switch (number(1, 3))
{
case 1:
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("어느정도 이 기술에 대해 이해가 되었지만 조금 부족한듯 한데.."));
break;
case 2:
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("드디어 끝이 보이는 건가... 이 기술은 이해하기가 너무 힘들어.."));
break;case 3:
default:
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("열심히 하는 배움을 가지는 것만이 기술을 배울수 있는 유일한 길이다.."));
break;
}ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d 권을 더 읽어야 수련을 완료 할 수 있습니다."), need_bookcount - read_count);
return true;
}
}
}
else
{
// 사용자의 퀘스트 정보 로드 실패
}
}
// INTERNATIONAL_VERSION
else
{
int iBookCount = 99;if (LC_IsYMIR() == true)
{
const int aiSkillBookCountForLevelUp_euckr[10] =
{
2, 2, 3, 3, 3, 3, 3, 3, 4, 5
};iBookCount = aiSkillBookCountForLevelUp_euckr[idx];
}
else
iBookCount = aiSkillBookCountForLevelUp[idx];if (FindAffect(AFFECT_SKILL_BOOK_BONUS))
{
if (iBookCount & 1) // iBookCount % 2
iBookCount = iBookCount / 2 + 1;
else
iBookCount = iBookCount / 2;RemoveAffect(AFFECT_SKILL_BOOK_BONUS);
}if (number(1, iBookCount) == 2)
SkillLevelUp(dwSkillVnum, SKILL_UP_BY_BOOK);
}
// END_OF_INTERNATIONAL_VERSION
}if (bLastLevel != GetSkillLevel(dwSkillVnum))
{
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("몸에서 뭔가 힘이 터져 나오는 기분이야!"));
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("뜨거운 무엇이 계속 용솟음치고 있어! 이건, 이것은!"));
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("책으로 더 높은 경지의 수련을 성공적으로 끝내셨습니다."));
LogManager::instance().CharLog(this, dwSkillVnum, "READ_SUCCESS", "");
}
else
{
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("크윽, 기가 역류하고 있어! 이거 설마 주화입마인가!? 젠장!"));
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("수련이 실패로 끝났습니다. 다시 도전해주시기 바랍니다."));
LogManager::instance().CharLog(this, dwSkillVnum, "READ_FAIL", "");
}return true;
}bool CHARACTER::SkillLevelDown(DWORD dwVnum)
{
if (NULL == m_pSkillLevels)
return false;if (g_bSkillDisable)
return false;if (IsPolymorphed())
return false;CSkillProto * pkSk = CSkillManager::instance().Get(dwVnum);
if (!pkSk)
{
sys_err("There is no such skill by number %u", dwVnum);
return false;
}if (!IsLearnableSkill(dwVnum))
return false;if (GetSkillMasterType(pkSk->dwVnum) != SKILL_NORMAL)
return false;if (!GetSkillGroup())
return false;if (pkSk->dwVnum >= SKILL_MAX_NUM)
return false;if (m_pSkillLevels[pkSk->dwVnum].bLevel == 0)
return false;int idx = POINT_SKILL;
switch (pkSk->dwType)
{
case 0:
idx = POINT_SUB_SKILL;
break;
case 1:
case 2:
case 3:
case 4:
case 6:
idx = POINT_SKILL;
break;
case 5:
idx = POINT_HORSE_SKILL;
break;
default:
sys_err("Wrong skill type %d skill vnum %d", pkSk->dwType, pkSk->dwVnum);
return false;}
PointChange(idx, +1);
SetSkillLevel(pkSk->dwVnum, m_pSkillLevels[pkSk->dwVnum].bLevel - 1);sys_log(0, "SkillDown: %s %u %u %u type %u", GetName(), pkSk->dwVnum, m_pSkillLevels[pkSk->dwVnum].bMasterType, m_pSkillLevels[pkSk->dwVnum].bLevel, pkSk->dwType);
Save();ComputePoints();
SkillLevelPacket();
return true;
}void CHARACTER::SkillLevelUp(DWORD dwVnum, BYTE bMethod)
{
if (NULL == m_pSkillLevels)
return;if (g_bSkillDisable)
return;if (IsPolymorphed())
{
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("둔갑 중에는 능력을 올릴 수 없습니다."));
return;
}if (SKILL_7_A_ANTI_TANHWAN <= dwVnum && dwVnum <= SKILL_8_D_ANTI_BYEURAK)
{
if (0 == GetSkillLevel(dwVnum))
return;
}const CSkillProto* pkSk = CSkillManager::instance().Get(dwVnum);
if (!pkSk)
{
sys_err("There is no such skill by number (vnum %u)", dwVnum);
return;
}if (pkSk->dwVnum >= SKILL_MAX_NUM)
{
sys_err("Skill Vnum overflow (vnum %u)", dwVnum);
return;
}if (!IsLearnableSkill(dwVnum))
return;// 그랜드 마스터는 퀘스트로만 수행가능
if (pkSk->dwType != 0)
{
switch (GetSkillMasterType(pkSk->dwVnum))
{
case SKILL_GRAND_MASTER:
if (bMethod != SKILL_UP_BY_QUEST)
return;
break;case SKILL_PERFECT_MASTER:
return;
}
}if (bMethod == SKILL_UP_BY_POINT)
{
// 마스터가 아닌 상태에서만 수련가능
if (GetSkillMasterType(pkSk->dwVnum) != SKILL_NORMAL)
return;if (IS_SET(pkSk->dwFlag, SKILL_FLAG_DISABLE_BY_POINT_UP))
return;
}
else if (bMethod == SKILL_UP_BY_BOOK)
{
if (pkSk->dwType != 0) // 직업에 속하지 않았거나 포인트로 올릴수 없는 스킬은 처음부터 책으로 배울 수 있다.
if (GetSkillMasterType(pkSk->dwVnum) != SKILL_MASTER)
return;
}if (GetLevel() < pkSk->bLevelLimit)
return;if (pkSk->preSkillVnum)
if (GetSkillMasterType(pkSk->preSkillVnum) == SKILL_NORMAL &&
GetSkillLevel(pkSk->preSkillVnum) < pkSk->preSkillLevel)
return;if (!GetSkillGroup())
return;if (bMethod == SKILL_UP_BY_POINT)
{
int idx;switch (pkSk->dwType)
{
case 0:
idx = POINT_SUB_SKILL;
break;case 1:
case 2:
case 3:
case 4:
case 6:
idx = POINT_SKILL;
break;case 5:
idx = POINT_HORSE_SKILL;
break;default:
sys_err("Wrong skill type %d skill vnum %d", pkSk->dwType, pkSk->dwVnum);
return;
}if (GetPoint(idx) < 1)
return;PointChange(idx, -1);
}int SkillPointBefore = GetSkillLevel(pkSk->dwVnum);
SetSkillLevel(pkSk->dwVnum, m_pSkillLevels[pkSk->dwVnum].bLevel + 1);if (pkSk->dwType != 0)
{
// 갑자기 그레이드 업하는 코딩
switch (GetSkillMasterType(pkSk->dwVnum))
{
case SKILL_NORMAL:
// 번섭은 스킬 업그레이드 17~20 사이 랜덤 마스터 수련
if (GetSkillLevel(pkSk->dwVnum) >= 17)
{
if (GetQuestFlag("reset_scroll.force_to_master_skill") > 0)
{
SetSkillLevel(pkSk->dwVnum, 20);
SetQuestFlag("reset_scroll.force_to_master_skill", 0);
}
else
{
//if (number(1, 21 - MIN(20, GetSkillLevel(pkSk->dwVnum))) == 1)
SetSkillLevel(pkSk->dwVnum, 20);
}
}
break;case SKILL_MASTER:
if (GetSkillLevel(pkSk->dwVnum) >= 30)
{
if (number(1, 31 - MIN(30, GetSkillLevel(pkSk->dwVnum))) == 1)
SetSkillLevel(pkSk->dwVnum, 30);
}
break;case SKILL_GRAND_MASTER:
if (GetSkillLevel(pkSk->dwVnum) >= 40)
{
SetSkillLevel(pkSk->dwVnum, 40);
}
break;
}
}char szSkillUp[1024];
snprintf(szSkillUp, sizeof(szSkillUp), "SkillUp: %s %u %d %d[Before:%d] type %u",
GetName(), pkSk->dwVnum, m_pSkillLevels[pkSk->dwVnum].bMasterType, m_pSkillLevels[pkSk->dwVnum].bLevel, SkillPointBefore, pkSk->dwType);sys_log(0, "%s", szSkillUp);
LogManager::instance().CharLog(this, pkSk->dwVnum, "SKILLUP", szSkillUp);
Save();ComputePoints();
SkillLevelPacket();
}void CHARACTER::ComputeSkillPoints()
{
if (g_bSkillDisable)
return;
}void CHARACTER::ResetSkill()
{
if (NULL == m_pSkillLevels)
return;// 보조 스킬은 리셋시키지 않는다
std::vector<std::pair<DWORD, TPlayerSkill> > vec;
size_t count = sizeof(s_adwSubSkillVnums) / sizeof(s_adwSubSkillVnums[0]);for (size_t i = 0; i < count; ++i)
{
if (s_adwSubSkillVnums >= SKILL_MAX_NUM)
continue;vec.push_back(std::make_pair(s_adwSubSkillVnums, m_pSkillLevels[s_adwSubSkillVnums]));
}memset(m_pSkillLevels, 0, sizeof(TPlayerSkill) * SKILL_MAX_NUM);
std::vector<std::pair<DWORD, TPlayerSkill> >::const_iterator iter = vec.begin();
while (iter != vec.end())
{
const std::pair<DWORD, TPlayerSkill>& pair = *(iter++);
m_pSkillLevels[pair.first] = pair.second;
}ComputePoints();
SkillLevelPacket();
}void CHARACTER::ComputePassiveSkill(DWORD dwVnum)
{
if (g_bSkillDisable)
return;if (GetSkillLevel(dwVnum) == 0)
return;CSkillProto * pkSk = CSkillManager::instance().Get(dwVnum);
pkSk->SetPointVar("k", GetSkillLevel(dwVnum));
int iAmount = (int) pkSk->kPointPoly.Eval();sys_log(2, "%s passive #%d on %d amount %d", GetName(), dwVnum, pkSk->bPointOn, iAmount);
PointChange(pkSk->bPointOn, iAmount);
}struct FFindNearVictim
{
FFindNearVictim(LPCHARACTER center, LPCHARACTER attacker, const CHARACTER_SET& excepts_set = empty_set_)
: m_pkChrCenter(center),
m_pkChrNextTarget(NULL),
m_pkChrAttacker(attacker),
m_count(0),
m_excepts_set(excepts_set)
{
}void operator ()(LPENTITY ent)
{
if (!ent->IsType(ENTITY_CHARACTER))
return;LPCHARACTER pkChr = (LPCHARACTER) ent;
if (!m_excepts_set.empty()) {
if (m_excepts_set.find(pkChr) != m_excepts_set.end())
return;
}if (m_pkChrCenter == pkChr)
return;if (!battle_is_attackable(m_pkChrAttacker, pkChr))
{
return;
}if (abs(m_pkChrCenter->GetX() - pkChr->GetX()) > 1000 || abs(m_pkChrCenter->GetY() - pkChr->GetY()) > 1000)
return;float fDist = DISTANCE_APPROX(m_pkChrCenter->GetX() - pkChr->GetX(), m_pkChrCenter->GetY() - pkChr->GetY());
if (fDist < 1000)
{
++m_count;if ((m_count == 1) || number(1, m_count) == 1)
m_pkChrNextTarget = pkChr;
}
}LPCHARACTER GetVictim()
{
return m_pkChrNextTarget;
}LPCHARACTER m_pkChrCenter;
LPCHARACTER m_pkChrNextTarget;
LPCHARACTER m_pkChrAttacker;
int m_count;
const CHARACTER_SET & m_excepts_set;
private:
static CHARACTER_SET empty_set_;
};CHARACTER_SET FFindNearVictim::empty_set_;
EVENTINFO(chain_lightning_event_info)
{
DWORD dwVictim;
DWORD dwChr;chain_lightning_event_info()
: dwVictim(0)
, dwChr(0)
{
}
};EVENTFUNC(ChainLightningEvent)
{
chain_lightning_event_info * info = dynamic_cast<chain_lightning_event_info *>( event->info );LPCHARACTER pkChrVictim = CHARACTER_MANAGER::instance().Find(info->dwVictim);
LPCHARACTER pkChr = CHARACTER_MANAGER::instance().Find(info->dwChr);
LPCHARACTER pkTarget = NULL;if (!pkChr || !pkChrVictim)
{
sys_log(1, "use chainlighting, but no character");
return 0;
}sys_log(1, "chainlighting event %s", pkChr->GetName());
if (pkChrVictim->GetParty()) // 파티 먼저
{
pkTarget = pkChrVictim->GetParty()->GetNextOwnership(NULL, pkChrVictim->GetX(), pkChrVictim->GetY());
if (pkTarget == pkChrVictim || !number(0, 2) || pkChr->GetChainLightingExcept().find(pkTarget) != pkChr->GetChainLightingExcept().end())
pkTarget = NULL;
}if (!pkTarget)
{
// 1. Find Next victim
FFindNearVictim f(pkChrVictim, pkChr, pkChr->GetChainLightingExcept());if (pkChrVictim->GetSectree())
{
pkChrVictim->GetSectree()->ForEachAround(f);
// 2. If exist, compute it again
pkTarget = f.GetVictim();
}
}if (pkTarget)
{
pkChrVictim->CreateFly(FLY_CHAIN_LIGHTNING, pkTarget);
pkChr->ComputeSkill(SKILL_CHAIN, pkTarget);
pkChr->AddChainLightningExcept(pkTarget);
}
else
{
sys_log(1, "%s use chainlighting, but find victim failed near %s", pkChr->GetName(), pkChrVictim->GetName());
}return 0;
}void SetPolyVarForAttack(LPCHARACTER ch, CSkillProto * pkSk, LPITEM pkWeapon)
{
if (ch->IsPC())
{
if (pkWeapon && pkWeapon->GetType() == ITEM_WEAPON)
{
int iWep = number(pkWeapon->GetValue(3), pkWeapon->GetValue(4));
iWep += pkWeapon->GetValue(5);int iMtk = number(pkWeapon->GetValue(1), pkWeapon->GetValue(2));
iMtk += pkWeapon->GetValue(5);pkSk->SetPointVar("wep", iWep);
pkSk->SetPointVar("mtk", iMtk);
pkSk->SetPointVar("mwep", iMtk);
}
else
{
pkSk->SetPointVar("wep", 0);
pkSk->SetPointVar("mtk", 0);
pkSk->SetPointVar("mwep", 0);
}
}
else
{
int iWep = number(ch->GetMobDamageMin(), ch->GetMobDamageMax());
pkSk->SetPointVar("wep", iWep);
pkSk->SetPointVar("mwep", iWep);
pkSk->SetPointVar("mtk", iWep);
}
}struct FuncSplashDamage
{
FuncSplashDamage(int x, int y, CSkillProto * pkSk, LPCHARACTER pkChr, int iAmount, int iAG, int iMaxHit, LPITEM pkWeapon, bool bDisableCooltime, TSkillUseInfo* pInfo, BYTE bUseSkillPower)
:
m_x(x), m_y(y), m_pkSk(pkSk), m_pkChr(pkChr), m_iAmount(iAmount), m_iAG(iAG), m_iCount(0), m_iMaxHit(iMaxHit), m_pkWeapon(pkWeapon), m_bDisableCooltime(bDisableCooltime), m_pInfo(pInfo), m_bUseSkillPower(bUseSkillPower)
{
}void operator () (LPENTITY ent)
{
if (!ent->IsType(ENTITY_CHARACTER))
{
return;
}LPCHARACTER pkChrVictim = (LPCHARACTER) ent;
if (DISTANCE_APPROX(m_x - pkChrVictim->GetX(), m_y - pkChrVictim->GetY()) > m_pkSk->iSplashRange)
{
if(test_server)
sys_log(0, "XXX target too far %s", m_pkChr->GetName());
return;
}if (!battle_is_attackable(m_pkChr, pkChrVictim))
{
if(test_server)
sys_log(0, "XXX target not attackable %s", m_pkChr->GetName());
return;
}if (m_pkChr->IsPC())
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(test_server)
sys_log(0, "check guild skill %s", m_pkChr->GetName());
return;
}++m_iCount;
int iDam;m_pkSk->SetPointVar("k", 1.0 * m_bUseSkillPower * m_pkSk->bMaxLevel / 100);
m_pkSk->SetPointVar("lv", m_pkChr->GetLevel());
m_pkSk->SetPointVar("iq", m_pkChr->GetPoint(POINT_IQ));
m_pkSk->SetPointVar("str", m_pkChr->GetPoint(POINT_ST));
m_pkSk->SetPointVar("dex", m_pkChr->GetPoint(POINT_DX));
m_pkSk->SetPointVar("con", m_pkChr->GetPoint(POINT_HT));
m_pkSk->SetPointVar("def", m_pkChr->GetPoint(POINT_DEF_GRADE));
m_pkSk->SetPointVar("odef", m_pkChr->GetPoint(POINT_DEF_GRADE) - m_pkChr->GetPoint(POINT_DEF_GRADE_BONUS));
m_pkSk->SetPointVar("horse_level", m_pkChr->GetHorseLevel());bool bIgnoreDefense = false;
if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_PENETRATE))
{
int iPenetratePct = (int) m_pkSk->kPointPoly2.Eval();
if (number(1, 100) <= iPenetratePct)
bIgnoreDefense = true;
}bool bIgnoreTargetRating = false;
if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_IGNORE_TARGET_RATING))
{
int iPct = (int) m_pkSk->kPointPoly2.Eval();
if (number(1, 100) <= iPct)
bIgnoreTargetRating = true;
}m_pkSk->SetPointVar("ar", CalcAttackRating(m_pkChr, pkChrVictim, bIgnoreTargetRating));
if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_USE_MELEE_DAMAGE))
m_pkSk->SetPointVar("atk", CalcMeleeDamage(m_pkChr, pkChrVictim, true, bIgnoreTargetRating));
else if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_USE_ARROW_DAMAGE))
{
LPITEM pkBow, pkArrow;
if (1 == m_pkChr->GetArrowAndBow(&pkBow, &pkArrow, 1))
m_pkSk->SetPointVar("atk", CalcArrowDamage(m_pkChr, pkChrVictim, pkBow, pkArrow, true));
else
m_pkSk->SetPointVar("atk", 0);
}if (m_pkSk->bPointOn == POINT_MOV_SPEED)
m_pkSk->kPointPoly.SetVar("maxv", pkChrVictim->GetLimitPoint(POINT_MOV_SPEED));m_pkSk->SetPointVar("maxhp", pkChrVictim->GetMaxHP());
m_pkSk->SetPointVar("maxsp", pkChrVictim->GetMaxSP());m_pkSk->SetPointVar("chain", m_pkChr->GetChainLightningIndex());
m_pkChr->IncChainLightningIndex();bool bUnderEunhyung = m_pkChr->GetAffectedEunhyung() > 0;
m_pkSk->SetPointVar("ek", m_pkChr->GetAffectedEunhyung()*1./100);
SetPolyVarForAttack(m_pkChr, m_pkSk, m_pkWeapon);int iAmount = 0;
if (m_pkChr->GetUsedSkillMasterType(m_pkSk->dwVnum) >= SKILL_GRAND_MASTER)
{
iAmount = (int) m_pkSk->kMasterBonusPoly.Eval();
}
else
{
iAmount = (int) m_pkSk->kPointPoly.Eval();
}if (test_server && iAmount == 0 && m_pkSk->bPointOn != POINT_NONE)
{
m_pkChr->ChatPacket(CHAT_TYPE_INFO, "효과가 없습니다. 스킬 공식을 확인하세요");
}iAmount = -iAmount;
if (m_pkSk->dwVnum == SKILL_AMSEOP)
{
float fDelta = GetDegreeDelta(m_pkChr->GetRotation(), pkChrVictim->GetRotation());
float adjust;
if (fDelta < 35.0f)
{
adjust = 1.5f;
if (bUnderEunhyung)
adjust += 0.5f;if (m_pkChr->GetWear(WEAR_WEAPON) && m_pkChr->GetWear(WEAR_WEAPON)->GetSubType() == WEAPON_DAGGER)
{
if ( LC_IsYMIR() )
adjust += 1.0f;
else
adjust += 0.5f;
}
}
else
{
adjust = 1.0f;
if ( !LC_IsYMIR() )
{
if (bUnderEunhyung)
adjust += 0.5f;if (m_pkChr->GetWear(WEAR_WEAPON) && m_pkChr->GetWear(WEAR_WEAPON)->GetSubType() == WEAPON_DAGGER)
adjust += 0.5f;
}
}iAmount = (int) (iAmount * adjust);
}
else if (m_pkSk->dwVnum == SKILL_GUNGSIN)
{
float adjust = 1.0;
if (m_pkChr->GetWear(WEAR_WEAPON) && m_pkChr->GetWear(WEAR_WEAPON)->GetSubType() == WEAPON_DAGGER)
{
if ( LC_IsYMIR() )
adjust = 1.4f;
else
adjust = 1.35f;
}iAmount = (int) (iAmount * adjust);
}
else if (m_pkSk->dwVnum == SKILL_GONGDAB)
{
float adjust = 1.0;
if (m_pkChr->GetWear(WEAR_WEAPON) && m_pkChr->GetWear(WEAR_WEAPON)->GetSubType() == WEAPON_CLAW)
{
adjust = 1.35f;
}iAmount = (int)(iAmount * adjust);
}iDam = CalcBattleDamage(iAmount, m_pkChr->GetLevel(), pkChrVictim->GetLevel());
if (m_pkChr->IsPC() && m_pkChr->m_SkillUseInfo[m_pkSk->dwVnum].GetMainTargetVID() != (DWORD) pkChrVictim->GetVID())
{
iDam = (int) (iDam * m_pkSk->kSplashAroundDamageAdjustPoly.Eval());
}int reduce_resist_magic = 0;
EDamageType dt = DAMAGE_TYPE_NONE;
switch (m_pkSk->bSkillAttrType)
{
case SKILL_ATTR_TYPE_NORMAL:
break;case SKILL_ATTR_TYPE_MELEE:
{
dt = DAMAGE_TYPE_MELEE;LPITEM pkWeapon = m_pkChr->GetWear(WEAR_WEAPON);
if (pkWeapon)
switch (pkWeapon->GetSubType())
{
case WEAPON_SWORD:
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_SWORD)) / 100;
break;case WEAPON_TWO_HANDED:
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_TWOHAND)) / 100;
break;case WEAPON_DAGGER:
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_DAGGER)) / 100;
break;case WEAPON_BELL:
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_BELL)) / 100;
break;case WEAPON_FAN:
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_FAN)) / 100;
break;case WEAPON_CLAW:
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_CLAW)) / 100;
break;
}if (!bIgnoreDefense)
iDam -= pkChrVictim->GetPoint(POINT_DEF_GRADE);
}
break;case SKILL_ATTR_TYPE_RANGE:
dt = DAMAGE_TYPE_RANGE;
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_BOW)) / 100;
break;case SKILL_ATTR_TYPE_MAGIC:
dt = DAMAGE_TYPE_MAGIC;
iDam = CalcAttBonus(m_pkChr, pkChrVictim, iDam);
reduce_resist_magic = pkChrVictim->GetPoint(POINT_RESIST_MAGIC);
#ifdef __ANTI_RESIST_MAGIC_BONUS__
if (m_pkChr->GetPoint(POINT_ANTI_RESIST_MAGIC) > 0)
{
// Fix Magic Resistance : If player have more than 100% magic resistance, will be modified to 100%;
int fix_magic_resistance = (pkChrVictim->GetPoint(POINT_RESIST_MAGIC) > 100) ? (int)(100) : (int)(pkChrVictim->GetPoint(POINT_RESIST_MAGIC));
// End Fix;
reduce_resist_magic = fix_magic_resistance - m_pkChr->GetPoint(POINT_ANTI_RESIST_MAGIC);
if (reduce_resist_magic < 1)
reduce_resist_magic = 0;
}
#endif
iDam = iDam * (100 - reduce_resist_magic) / 100;
break;default:
sys_err("Unknown skill attr type %u vnum %u", m_pkSk->bSkillAttrType, m_pkSk->dwVnum);
break;
}if (pkChrVictim->IsNPC())
{
if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_WIND))
{
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_WIND)) / 100;
}if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_ELEC))
{
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_ELEC)) / 100;
}if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_FIRE))
{
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_FIRE)) / 100;
}
}if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_COMPUTE_MAGIC_DAMAGE))
dt = DAMAGE_TYPE_MAGIC;if (pkChrVictim->CanBeginFight())
pkChrVictim->BeginFight(m_pkChr);if (m_pkSk->dwVnum == SKILL_CHAIN)
sys_log(0, "%s CHAIN INDEX %d DAM %d DT %d", m_pkChr->GetName(), m_pkChr->GetChainLightningIndex() - 1, iDam, dt);{
BYTE AntiSkillID = 0;
switch (m_pkSk->dwVnum)
{
case SKILL_TANHWAN:
AntiSkillID = SKILL_7_A_ANTI_TANHWAN;
break;case SKILL_AMSEOP:
AntiSkillID = SKILL_7_B_ANTI_AMSEOP;
break;case SKILL_SWAERYUNG:
AntiSkillID = SKILL_7_C_ANTI_SWAERYUNG;
break;case SKILL_YONGBI:
AntiSkillID = SKILL_7_D_ANTI_YONGBI;
break;case SKILL_GIGONGCHAM:
AntiSkillID = SKILL_8_A_ANTI_GIGONGCHAM;
break;case SKILL_YEONSA:
AntiSkillID = SKILL_8_B_ANTI_YEONSA;
break;case SKILL_MAHWAN:
AntiSkillID = SKILL_8_C_ANTI_MAHWAN;
break;case SKILL_BYEURAK:
AntiSkillID = SKILL_8_D_ANTI_BYEURAK;
break;
}if (0 != AntiSkillID)
{
BYTE AntiSkillLevel = pkChrVictim->GetSkillLevel(AntiSkillID);
if (0 != AntiSkillLevel)
{
CSkillProto* pkSk = CSkillManager::instance().Get(AntiSkillID);
if (!pkSk)
{
sys_err ("There is no anti skill(%d) in skill proto", AntiSkillID);
}
else
{
pkSk->SetPointVar("k", 1.0f * pkChrVictim->GetSkillPower(AntiSkillID) * pkSk->bMaxLevel / 100);
double ResistAmount = pkSk->kPointPoly.Eval();sys_log(0, "ANTI_SKILL: Resist(%lf) Orig(%d) Reduce(%d)", ResistAmount, iDam, int(iDam * (ResistAmount/100.0)));
iDam -= iDam * (ResistAmount/100.0);
}
}
}
}if (!pkChrVictim->Damage(m_pkChr, iDam, dt) && !pkChrVictim->IsStun())
{
if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_REMOVE_GOOD_AFFECT))
{
int iAmount2 = (int) m_pkSk->kPointPoly2.Eval();
int iDur2 = (int) m_pkSk->kDurationPoly2.Eval();
iDur2 += m_pkChr->GetPoint(POINT_PARTY_BUFFER_BONUS);if (number(1, 100) <= iAmount2)
{
pkChrVictim->RemoveGoodAffect();
pkChrVictim->AddAffect(m_pkSk->dwVnum, POINT_NONE, 0, AFF_PABEOP, iDur2, 0, true);
}
}if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_SLOW | SKILL_FLAG_STUN | SKILL_FLAG_FIRE_CONT | SKILL_FLAG_POISON | SKILL_FLAG_BLEEDING))
{
int iPct = (int) m_pkSk->kPointPoly2.Eval();
int iDur = (int) m_pkSk->kDurationPoly2.Eval();iDur += m_pkChr->GetPoint(POINT_PARTY_BUFFER_BONUS);
if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_STUN))
{
SkillAttackAffect(pkChrVictim, iPct, IMMUNE_STUN, AFFECT_STUN, POINT_NONE, 0, AFF_STUN, iDur, m_pkSk->szName);
}
else if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_SLOW))
{
SkillAttackAffect(pkChrVictim, iPct, IMMUNE_SLOW, AFFECT_SLOW, POINT_MOV_SPEED, -30, AFF_SLOW, iDur, m_pkSk->szName);
}
else if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_FIRE_CONT))
{
m_pkSk->SetDurationVar("k", 1.0 * m_bUseSkillPower * m_pkSk->bMaxLevel / 100);
m_pkSk->SetDurationVar("iq", m_pkChr->GetPoint(POINT_IQ));iDur = (int)m_pkSk->kDurationPoly2.Eval();
int bonus = m_pkChr->GetPoint(POINT_PARTY_BUFFER_BONUS);if (bonus != 0)
{
iDur += bonus / 2;
}if (number(1, 100) <= iDur)
{
pkChrVictim->AttackedByFire(m_pkChr, iPct, 5);
}
}
else if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_POISON))
{
if (number(1, 100) <= iPct && !pkChrVictim->IsAffectFlag(AFF_BLEEDING))
pkChrVictim->AttackedByPoison(m_pkChr);
}
else if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_BLEEDING))
{
if (number(1, 100) <= iPct && !pkChrVictim->IsAffectFlag(AFF_POISON))
pkChrVictim->AttackedByBleeding(m_pkChr);
}
}if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_CRUSH | SKILL_FLAG_CRUSH_LONG) &&
!IS_SET(pkChrVictim->GetAIFlag(), AIFLAG_NOMOVE))
{
float fCrushSlidingLength = 200;if (m_pkChr->IsNPC())
fCrushSlidingLength = 400;if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_CRUSH_LONG))
fCrushSlidingLength *= 2;float fx, fy;
float degree = GetDegreeFromPositionXY(m_pkChr->GetX(), m_pkChr->GetY(), pkChrVictim->GetX(), pkChrVictim->GetY());if (m_pkSk->dwVnum == SKILL_HORSE_WILDATTACK)
{
degree -= m_pkChr->GetRotation();
degree = fmod(degree, 360.0f) - 180.0f;if (degree > 0)
degree = m_pkChr->GetRotation() + 90.0f;
else
degree = m_pkChr->GetRotation() - 90.0f;
}GetDeltaByDegree(degree, fCrushSlidingLength, &fx, &fy);
sys_log(0, "CRUSH! %s -> %s (%d %d) -> (%d %d)", m_pkChr->GetName(), pkChrVictim->GetName(), pkChrVictim->GetX(), pkChrVictim->GetY(), (long)(pkChrVictim->GetX()+fx), (long)(pkChrVictim->GetY()+fy));
long tx = (long)(pkChrVictim->GetX()+fx);
long ty = (long)(pkChrVictim->GetY()+fy);pkChrVictim->Sync(tx, ty);
pkChrVictim->Goto(tx, ty);
pkChrVictim->CalculateMoveDuration();if (m_pkChr->IsPC() && m_pkChr->m_SkillUseInfo[m_pkSk->dwVnum].GetMainTargetVID() == (DWORD) pkChrVictim->GetVID())
{
//if (!g_iUseLocale)
if (LC_IsYMIR())
SkillAttackAffect(pkChrVictim, 1000, IMMUNE_STUN, m_pkSk->dwVnum, POINT_NONE, 0, AFF_STUN, 3, m_pkSk->szName);
else
SkillAttackAffect(pkChrVictim, 1000, IMMUNE_STUN, m_pkSk->dwVnum, POINT_NONE, 0, AFF_STUN, 4, m_pkSk->szName);
}
else
{
pkChrVictim->SyncPacket();
}
}
}if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_HP_ABSORB))
{
int iPct = (int) m_pkSk->kPointPoly2.Eval();
m_pkChr->PointChange(POINT_HP, iDam * iPct / 100);
}if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_SP_ABSORB))
{
int iPct = (int) m_pkSk->kPointPoly2.Eval();
m_pkChr->PointChange(POINT_SP, iDam * iPct / 100);
}if (m_pkSk->dwVnum == SKILL_CHAIN && m_pkChr->GetChainLightningIndex() < m_pkChr->GetChainLightningMaxCount())
{
chain_lightning_event_info* info = AllocEventInfo<chain_lightning_event_info>();info->dwVictim = pkChrVictim->GetVID();
info->dwChr = m_pkChr->GetVID();event_create(ChainLightningEvent, info, passes_per_sec / 5);
}
if(test_server)
sys_log(0, "FuncSplashDamage End :%s ", m_pkChr->GetName());
}int m_x;
int m_y;
CSkillProto * m_pkSk;
LPCHARACTER m_pkChr;
int m_iAmount;
int m_iAG;
int m_iCount;
int m_iMaxHit;
LPITEM m_pkWeapon;
bool m_bDisableCooltime;
TSkillUseInfo* m_pInfo;
BYTE m_bUseSkillPower;
};struct FuncSplashAffect
{
FuncSplashAffect(LPCHARACTER ch, int x, int y, int iDist, DWORD dwVnum, BYTE bPointOn, int iAmount, DWORD dwAffectFlag, int iDuration, int iSPCost, bool bOverride, int iMaxHit)
{
m_x = x;
m_y = y;
m_iDist = iDist;
m_dwVnum = dwVnum;
m_bPointOn = bPointOn;
m_iAmount = iAmount;
m_dwAffectFlag = dwAffectFlag;
m_iDuration = iDuration;
m_iSPCost = iSPCost;
m_bOverride = bOverride;
m_pkChrAttacker = ch;
m_iMaxHit = iMaxHit;
m_iCount = 0;
}void operator () (LPENTITY ent)
{
if (m_iMaxHit && m_iMaxHit <= m_iCount)
return;if (ent->IsType(ENTITY_CHARACTER))
{
LPCHARACTER pkChr = (LPCHARACTER) ent;if (test_server)
sys_log(0, "FuncSplashAffect step 1 : name:%s vnum:%d iDur:%d", pkChr->GetName(), m_dwVnum, m_iDuration);
if (DISTANCE_APPROX(m_x - pkChr->GetX(), m_y - pkChr->GetY()) < m_iDist)
{
if (test_server)
sys_log(0, "FuncSplashAffect step 2 : name:%s vnum:%d iDur:%d", pkChr->GetName(), m_dwVnum, m_iDuration);
if (m_dwVnum == SKILL_TUSOK)
if (pkChr->CanBeginFight())
pkChr->BeginFight(m_pkChrAttacker);if (pkChr->IsPC() && m_dwVnum == SKILL_TUSOK)
pkChr->AddAffect(m_dwVnum, m_bPointOn, m_iAmount, m_dwAffectFlag, m_iDuration/3, m_iSPCost, m_bOverride);
else
pkChr->AddAffect(m_dwVnum, m_bPointOn, m_iAmount, m_dwAffectFlag, m_iDuration, m_iSPCost, m_bOverride);m_iCount ++;
}
}
}LPCHARACTER m_pkChrAttacker;
int m_x;
int m_y;
int m_iDist;
DWORD m_dwVnum;
BYTE m_bPointOn;
int m_iAmount;
DWORD m_dwAffectFlag;
int m_iDuration;
int m_iSPCost;
bool m_bOverride;
int m_iMaxHit;
int m_iCount;
};EVENTINFO(skill_gwihwan_info)
{
DWORD pid;
BYTE bsklv;skill_gwihwan_info()
: pid( 0 )
, bsklv( 0 )
{
}
};EVENTFUNC(skill_gwihwan_event)
{
skill_gwihwan_info* info = dynamic_cast<skill_gwihwan_info*>( event->info );if ( info == NULL )
{
sys_err( "skill_gwihwan_event> <Factor> Null pointer" );
return 0;
}DWORD pid = info->pid;
BYTE sklv= info->bsklv;
LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(pid);if (!ch)
return 0;int percent = 20 * sklv - 1;
if (number(1, 100) <= percent)
{
PIXEL_POSITION pos;// 성공
if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(ch->GetMapIndex(), ch->GetEmpire(), pos))
{
sys_log(1, "Recall: %s %d %d -> %d %d", ch->GetName(), ch->GetX(), ch->GetY(), pos.x, pos.y);
ch->WarpSet(pos.x, pos.y);
}
else
{
sys_err("CHARACTER::UseItem : cannot find spawn position (name %s, %d x %d)", ch->GetName(), ch->GetX(), ch->GetY());
ch->WarpSet(EMPIRE_START_X(ch->GetEmpire()), EMPIRE_START_Y(ch->GetEmpire()));
}
}
else
{
//실패
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("귀환에 실패하였습니다."));
}
return 0;
}int CHARACTER::ComputeSkillAtPosition(DWORD dwVnum, const PIXEL_POSITION& posTarget, BYTE bSkillLevel)
{
if (GetMountVnum())
return BATTLE_NONE;if (IsPolymorphed())
return BATTLE_NONE;if (g_bSkillDisable)
return BATTLE_NONE;CSkillProto * pkSk = CSkillManager::instance().Get(dwVnum);
if (!pkSk)
return BATTLE_NONE;if (test_server)
{
sys_log(0, "ComputeSkillAtPosition %s vnum %d x %d y %d level %d",
GetName(), dwVnum, posTarget.x, posTarget.y, bSkillLevel);
}// 나에게 쓰는 스킬은 내 위치를 쓴다.
//if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY))
// posTarget = GetXYZ();// 스플래쉬가 아닌 스킬은 주위이면 이상하다
if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
return BATTLE_NONE;if (0 == bSkillLevel)
{
if ((bSkillLevel = GetSkillLevel(pkSk->dwVnum)) == 0)
{
return BATTLE_NONE;
}
}const float k = 1.0 * GetSkillPower(pkSk->dwVnum, bSkillLevel) * pkSk->bMaxLevel / 100;
pkSk->SetPointVar("k", k);
pkSk->kSplashAroundDamageAdjustPoly.SetVar("k", k);if (IS_SET(pkSk->dwFlag, SKILL_FLAG_USE_MELEE_DAMAGE))
{
pkSk->SetPointVar("atk", CalcMeleeDamage(this, this, true, false));
}
else if (IS_SET(pkSk->dwFlag, SKILL_FLAG_USE_MAGIC_DAMAGE))
{
pkSk->SetPointVar("atk", CalcMagicDamage(this, this));
}
else if (IS_SET(pkSk->dwFlag, SKILL_FLAG_USE_ARROW_DAMAGE))
{
LPITEM pkBow, pkArrow;
if (1 == GetArrowAndBow(&pkBow, &pkArrow, 1))
{
pkSk->SetPointVar("atk", CalcArrowDamage(this, this, pkBow, pkArrow, true));
}
else
{
pkSk->SetPointVar("atk", 0);
}
}if (pkSk->bPointOn == POINT_MOV_SPEED)
{
pkSk->SetPointVar("maxv", this->GetLimitPoint(POINT_MOV_SPEED));
}pkSk->SetPointVar("lv", GetLevel());
pkSk->SetPointVar("iq", GetPoint(POINT_IQ));
pkSk->SetPointVar("str", GetPoint(POINT_ST));
pkSk->SetPointVar("dex", GetPoint(POINT_DX));
pkSk->SetPointVar("con", GetPoint(POINT_HT));
pkSk->SetPointVar("maxhp", this->GetMaxHP());
pkSk->SetPointVar("maxsp", this->GetMaxSP());
pkSk->SetPointVar("chain", 0);
pkSk->SetPointVar("ar", CalcAttackRating(this, this));
pkSk->SetPointVar("def", GetPoint(POINT_DEF_GRADE));
pkSk->SetPointVar("odef", GetPoint(POINT_DEF_GRADE) - GetPoint(POINT_DEF_GRADE_BONUS));
pkSk->SetPointVar("horse_level", GetHorseLevel());if (pkSk->bSkillAttrType != SKILL_ATTR_TYPE_NORMAL)
OnMove(true);LPITEM pkWeapon = GetWear(WEAR_WEAPON);
SetPolyVarForAttack(this, pkSk, pkWeapon);
pkSk->SetDurationVar("k", k/*bSkillLevel*/);
int iAmount = (int) pkSk->kPointPoly.Eval();
int iAmount2 = (int) pkSk->kPointPoly2.Eval();// ADD_GRANDMASTER_SKILL
int iAmount3 = (int) pkSk->kPointPoly3.Eval();if (GetUsedSkillMasterType(pkSk->dwVnum) >= SKILL_GRAND_MASTER)
{
/*
if (iAmount >= 0)
iAmount += (int) m_pkSk->kMasterBonusPoly.Eval();
else
iAmount -= (int) m_pkSk->kMasterBonusPoly.Eval();
*/
iAmount = (int) pkSk->kMasterBonusPoly.Eval();
}if (test_server && iAmount == 0 && pkSk->bPointOn != POINT_NONE)
{
ChatPacket(CHAT_TYPE_INFO, "효과가 없습니다. 스킬 공식을 확인하세요");
}if (IS_SET(pkSk->dwFlag, SKILL_FLAG_REMOVE_BAD_AFFECT))
{
if (number(1, 100) <= iAmount2)
{
RemoveBadAffect();
}
}
// END_OF_ADD_GRANDMASTER_SKILLif (IS_SET(pkSk->dwFlag, SKILL_FLAG_ATTACK | SKILL_FLAG_USE_MELEE_DAMAGE | SKILL_FLAG_USE_MAGIC_DAMAGE))
{
//
// 공격 스킬일 경우
//
bool bAdded = false;if (pkSk->bPointOn == POINT_HP && iAmount < 0)
{
int iAG = 0;FuncSplashDamage f(posTarget.x, posTarget.y, pkSk, this, iAmount, iAG, pkSk->lMaxHit, pkWeapon, m_bDisableCooltime, IsPC()?&m_SkillUseInfo[dwVnum]:NULL, GetSkillPower(dwVnum, bSkillLevel));
if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
{
if (GetSectree())
GetSectree()->ForEachAround(f);
}
else
{
//if (dwVnum == SKILL_CHAIN) sys_log(0, "CHAIN skill call FuncSplashDamage %s", GetName());
f(this);
}
}
else
{
//if (dwVnum == SKILL_CHAIN) sys_log(0, "CHAIN skill no damage %d %s", iAmount, GetName());
int iDur = (int) pkSk->kDurationPoly.Eval();if (IsPC())
if (!(dwVnum >= GUILD_SKILL_START && dwVnum <= GUILD_SKILL_END)) // 길드 스킬은 쿨타임 처리를 하지 않는다.
if (!m_bDisableCooltime && !m_SkillUseInfo[dwVnum].HitOnce(dwVnum) && dwVnum != SKILL_MUYEONG)
{
//if (dwVnum == SKILL_CHAIN) sys_log(0, "CHAIN skill cannot hit %s", GetName());
return BATTLE_NONE;
}
if (iDur > 0)
{
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
AddAffect(pkSk->dwVnum, pkSk->bPointOn, iAmount, pkSk->dwAffectFlag, iDur, 0, true);
else
{
if (GetSectree())
{
FuncSplashAffect f(this, posTarget.x, posTarget.y, pkSk->iSplashRange, pkSk->dwVnum, pkSk->bPointOn, iAmount, pkSk->dwAffectFlag, iDur, 0, true, pkSk->lMaxHit);
GetSectree()->ForEachAround(f);
}
}
bAdded = true;
}
}if (pkSk->bPointOn2 != POINT_NONE)
{
int iDur = (int) pkSk->kDurationPoly2.Eval();sys_log(1, "try second %u %d %d", pkSk->dwVnum, pkSk->bPointOn2, iDur);
if (iDur > 0)
{
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
AddAffect(pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag2, iDur, 0, !bAdded);
else
{
if (GetSectree())
{
FuncSplashAffect f(this, posTarget.x, posTarget.y, pkSk->iSplashRange, pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag2, iDur, 0, !bAdded, pkSk->lMaxHit);
GetSectree()->ForEachAround(f);
}
}
bAdded = true;
}
else
{
PointChange(pkSk->bPointOn2, iAmount2);
}
}// ADD_GRANDMASTER_SKILL
if (GetUsedSkillMasterType(pkSk->dwVnum) >= SKILL_GRAND_MASTER && pkSk->bPointOn3 != POINT_NONE)
{
int iDur = (int) pkSk->kDurationPoly3.Eval();if (iDur > 0)
{
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
AddAffect(pkSk->dwVnum, pkSk->bPointOn3, iAmount3, 0 /*pkSk->dwAffectFlag3*/, iDur, 0, !bAdded);
else
{
if (GetSectree())
{
FuncSplashAffect f(this, posTarget.x, posTarget.y, pkSk->iSplashRange, pkSk->dwVnum, pkSk->bPointOn3, iAmount3, 0 /*pkSk->dwAffectFlag3*/, iDur, 0, !bAdded, pkSk->lMaxHit);
GetSectree()->ForEachAround(f);
}
}
}
else
{
PointChange(pkSk->bPointOn3, iAmount3);
}
}
// END_OF_ADD_GRANDMASTER_SKILLreturn BATTLE_DAMAGE;
}
else
{
bool bAdded = false;
int iDur = (int) pkSk->kDurationPoly.Eval();if (iDur > 0)
{
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
// AffectFlag가 없거나, toggle 하는 것이 아니라면..
pkSk->kDurationSPCostPoly.SetVar("k", k/*bSkillLevel*/);AddAffect(pkSk->dwVnum,
pkSk->bPointOn,
iAmount,
pkSk->dwAffectFlag,
iDur,
(long) pkSk->kDurationSPCostPoly.Eval(),
!bAdded);bAdded = true;
}
else
{
PointChange(pkSk->bPointOn, iAmount);
}if (pkSk->bPointOn2 != POINT_NONE)
{
int iDur = (int) pkSk->kDurationPoly2.Eval();if (iDur > 0)
{
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
AddAffect(pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag2, iDur, 0, !bAdded);
bAdded = true;
}
else
{
PointChange(pkSk->bPointOn2, iAmount2);
}
}// ADD_GRANDMASTER_SKILL
if (GetUsedSkillMasterType(pkSk->dwVnum) >= SKILL_GRAND_MASTER && pkSk->bPointOn3 != POINT_NONE)
{
int iDur = (int) pkSk->kDurationPoly3.Eval();if (iDur > 0)
{
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
AddAffect(pkSk->dwVnum, pkSk->bPointOn3, iAmount3, 0 /*pkSk->dwAffectFlag3*/, iDur, 0, !bAdded);
}
else
{
PointChange(pkSk->bPointOn3, iAmount3);
}
}
// END_OF_ADD_GRANDMASTER_SKILLreturn BATTLE_NONE;
}
}// bSkillLevel 인자가 0이 아닐 경우에는 m_abSkillLevels를 사용하지 않고 강제로
// bSkillLevel로 계산한다.
int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel)
{
const bool bCanUseHorseSkill = CanUseHorseSkill();// 말을 타고있지만 스킬은 사용할 수 없는 상태라면 return
if (false == bCanUseHorseSkill && true == IsRiding())
return BATTLE_NONE;if (IsPolymorphed())
return BATTLE_NONE;if (g_bSkillDisable)
return BATTLE_NONE;CSkillProto* pkSk = CSkillManager::instance().Get(dwVnum);
if (!pkSk)
return BATTLE_NONE;if (bCanUseHorseSkill && pkSk->dwType != SKILL_TYPE_HORSE)
return BATTLE_NONE;if (!bCanUseHorseSkill && pkSk->dwType == SKILL_TYPE_HORSE)
return BATTLE_NONE;
// 상대방에게 쓰는 것이 아니면 나에게 써야 한다.
if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY))
pkVictim = this;if (IS_SET(pkSk->dwFlag, SKILL_FLAG_PARTY) && !GetParty())
pkVictim = this;if (!pkVictim)
{
if (test_server)
sys_log(0, "ComputeSkill: %s Victim == null, skill %d", GetName(), dwVnum);return BATTLE_NONE;
}if (pkSk->dwTargetRange && DISTANCE_SQRT(GetX() - pkVictim->GetX(), GetY() - pkVictim->GetY()) >= pkSk->dwTargetRange + 50)
{
if (test_server)
sys_log(0, "ComputeSkill: Victim too far, skill %d : %s to %s (distance %u limit %u)",
dwVnum,
GetName(),
pkVictim->GetName(),
(long)DISTANCE_SQRT(GetX() - pkVictim->GetX(), GetY() - pkVictim->GetY()),
pkSk->dwTargetRange);return BATTLE_NONE;
}if (0 == bSkillLevel)
{
if ((bSkillLevel = GetSkillLevel(pkSk->dwVnum)) == 0)
{
if (test_server)
sys_log(0, "ComputeSkill : name:%s vnum:%d skillLevelBySkill : %d ", GetName(), pkSk->dwVnum, bSkillLevel);
return BATTLE_NONE;
}
}if (pkVictim->IsAffectFlag(AFF_PABEOP) && pkVictim->IsGoodAffect(dwVnum))
{
return BATTLE_NONE;
}const float k = 1.0 * GetSkillPower(pkSk->dwVnum, bSkillLevel) * pkSk->bMaxLevel / 100;
pkSk->SetPointVar("k", k);
pkSk->kSplashAroundDamageAdjustPoly.SetVar("k", k);if (pkSk->dwType == SKILL_TYPE_HORSE)
{
LPITEM pkBow, pkArrow;
if (1 == GetArrowAndBow(&pkBow, &pkArrow, 1))
{
pkSk->SetPointVar("atk", CalcArrowDamage(this, pkVictim, pkBow, pkArrow, true));
}
else
{
pkSk->SetPointVar("atk", CalcMeleeDamage(this, pkVictim, true, false));
}
}
else if (IS_SET(pkSk->dwFlag, SKILL_FLAG_USE_MELEE_DAMAGE))
{
pkSk->SetPointVar("atk", CalcMeleeDamage(this, pkVictim, true, false));
}
else if (IS_SET(pkSk->dwFlag, SKILL_FLAG_USE_MAGIC_DAMAGE))
{
pkSk->SetPointVar("atk", CalcMagicDamage(this, pkVictim));
}
else if (IS_SET(pkSk->dwFlag, SKILL_FLAG_USE_ARROW_DAMAGE))
{
LPITEM pkBow, pkArrow;
if (1 == GetArrowAndBow(&pkBow, &pkArrow, 1))
{
pkSk->SetPointVar("atk", CalcArrowDamage(this, pkVictim, pkBow, pkArrow, true));
}
else
{
pkSk->SetPointVar("atk", 0);
}
}if (pkSk->bPointOn == POINT_MOV_SPEED)
{
pkSk->SetPointVar("maxv", pkVictim->GetLimitPoint(POINT_MOV_SPEED));
}pkSk->SetPointVar("lv", GetLevel());
pkSk->SetPointVar("iq", GetPoint(POINT_IQ));
pkSk->SetPointVar("str", GetPoint(POINT_ST));
pkSk->SetPointVar("dex", GetPoint(POINT_DX));
pkSk->SetPointVar("con", GetPoint(POINT_HT));
pkSk->SetPointVar("maxhp", pkVictim->GetMaxHP());
pkSk->SetPointVar("maxsp", pkVictim->GetMaxSP());
pkSk->SetPointVar("chain", 0);
pkSk->SetPointVar("ar", CalcAttackRating(this, pkVictim));
pkSk->SetPointVar("def", GetPoint(POINT_DEF_GRADE));
pkSk->SetPointVar("odef", GetPoint(POINT_DEF_GRADE) - GetPoint(POINT_DEF_GRADE_BONUS));
pkSk->SetPointVar("horse_level", GetHorseLevel());if (pkSk->bSkillAttrType != SKILL_ATTR_TYPE_NORMAL)
OnMove(true);LPITEM pkWeapon = GetWear(WEAR_WEAPON);
SetPolyVarForAttack(this, pkSk, pkWeapon);
pkSk->kDurationPoly.SetVar("k", k/*bSkillLevel*/);
pkSk->kDurationPoly2.SetVar("k", k/*bSkillLevel*/);int iAmount = (int) pkSk->kPointPoly.Eval();
int iAmount2 = (int) pkSk->kPointPoly2.Eval();
int iAmount3 = (int) pkSk->kPointPoly3.Eval();if (test_server && IsPC())
sys_log(0, "iAmount: %d %d %d , atk:%f skLevel:%f k:%f GetSkillPower(%d) MaxLevel:%d Per:%f",
iAmount, iAmount2, iAmount3,
pkSk->kPointPoly.GetVar("atk"),
pkSk->kPointPoly.GetVar("k"),
k,
GetSkillPower(pkSk->dwVnum, bSkillLevel),
pkSk->bMaxLevel,
pkSk->bMaxLevel/100
);// ADD_GRANDMASTER_SKILL
if (GetUsedSkillMasterType(pkSk->dwVnum) >= SKILL_GRAND_MASTER)
{
iAmount = (int) pkSk->kMasterBonusPoly.Eval();
}if (test_server && iAmount == 0 && pkSk->bPointOn != POINT_NONE)
{
ChatPacket(CHAT_TYPE_INFO, "효과가 없습니다. 스킬 공식을 확인하세요");
}
// END_OF_ADD_GRANDMASTER_SKILL//sys_log(0, "XXX SKILL Calc %d Amount %d", dwVnum, iAmount);
// REMOVE_BAD_AFFECT_BUG_FIX
if (IS_SET(pkSk->dwFlag, SKILL_FLAG_REMOVE_BAD_AFFECT))
{
if (number(1, 100) <= iAmount2)
{
pkVictim->RemoveBadAffect();
}
}
// END_OF_REMOVE_BAD_AFFECT_BUG_FIXif (IS_SET(pkSk->dwFlag, SKILL_FLAG_ATTACK | SKILL_FLAG_USE_MELEE_DAMAGE | SKILL_FLAG_USE_MAGIC_DAMAGE) &&
!(pkSk->dwVnum == SKILL_MUYEONG && pkVictim == this) && !(pkSk->IsChargeSkill() && pkVictim == this))
{
bool bAdded = false;if (pkSk->bPointOn == POINT_HP && iAmount < 0)
{
int iAG = 0;
FuncSplashDamage f(pkVictim->GetX(), pkVictim->GetY(), pkSk, this, iAmount, iAG, pkSk->lMaxHit, pkWeapon, m_bDisableCooltime, IsPC()?&m_SkillUseInfo[dwVnum]:NULL, GetSkillPower(dwVnum, bSkillLevel));
if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
{
if (pkVictim->GetSectree())
pkVictim->GetSectree()->ForEachAround(f);
}
else
{
f(pkVictim);
}
}
else
{
pkSk->kDurationPoly.SetVar("k", k/*bSkillLevel*/);
int iDur = (int) pkSk->kDurationPoly.Eval();
if (IsPC())
if (!(dwVnum >= GUILD_SKILL_START && dwVnum <= GUILD_SKILL_END)) // 길드 스킬은 쿨타임 처리를 하지 않는다.
if (!m_bDisableCooltime && !m_SkillUseInfo[dwVnum].HitOnce(dwVnum) && dwVnum != SKILL_MUYEONG)
{
return BATTLE_NONE;
}if (iDur > 0)
{
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
pkVictim->AddAffect(pkSk->dwVnum, pkSk->bPointOn, iAmount, pkSk->dwAffectFlag, iDur, 0, true);
else
{
if (pkVictim->GetSectree())
{
FuncSplashAffect f(this, pkVictim->GetX(), pkVictim->GetY(), pkSk->iSplashRange, pkSk->dwVnum, pkSk->bPointOn, iAmount, pkSk->dwAffectFlag, iDur, 0, true, pkSk->lMaxHit);
pkVictim->GetSectree()->ForEachAround(f);
}
}
bAdded = true;
}
}if (pkSk->bPointOn2 != POINT_NONE && !pkSk->IsChargeSkill())
{
pkSk->kDurationPoly2.SetVar("k", k/*bSkillLevel*/);
int iDur = (int) pkSk->kDurationPoly2.Eval();if (iDur > 0)
{
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
pkVictim->AddAffect(pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag2, iDur, 0, !bAdded);
else
{
if (pkVictim->GetSectree())
{
FuncSplashAffect f(this, pkVictim->GetX(), pkVictim->GetY(), pkSk->iSplashRange, pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag2, iDur, 0, !bAdded, pkSk->lMaxHit);
pkVictim->GetSectree()->ForEachAround(f);
}
}bAdded = true;
}
else
{
pkVictim->PointChange(pkSk->bPointOn2, iAmount2);
}
}// ADD_GRANDMASTER_SKILL
if (pkSk->bPointOn3 != POINT_NONE && !pkSk->IsChargeSkill() && GetUsedSkillMasterType(pkSk->dwVnum) >= SKILL_GRAND_MASTER)
{
pkSk->kDurationPoly3.SetVar("k", k/*bSkillLevel*/);
int iDur = (int) pkSk->kDurationPoly3.Eval();
if (iDur > 0)
{
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
pkVictim->AddAffect(pkSk->dwVnum, pkSk->bPointOn3, iAmount3, /*pkSk->dwAffectFlag3*/ 0, iDur, 0, !bAdded);
else
{
if (pkVictim->GetSectree())
{
FuncSplashAffect f(this, pkVictim->GetX(), pkVictim->GetY(), pkSk->iSplashRange, pkSk->dwVnum, pkSk->bPointOn3, iAmount3, /*pkSk->dwAffectFlag3*/ 0, iDur, 0, !bAdded, pkSk->lMaxHit);
pkVictim->GetSectree()->ForEachAround(f);
}
}bAdded = true;
}
else
{
pkVictim->PointChange(pkSk->bPointOn3, iAmount3);
}
}
// END_OF_ADD_GRANDMASTER_SKILLreturn BATTLE_DAMAGE;
}
else
{
if (dwVnum == SKILL_MUYEONG)
{
pkSk->kDurationPoly.SetVar("k", k/*bSkillLevel*/);
pkSk->kDurationSPCostPoly.SetVar("k", k/*bSkillLevel*/);int iDur = (long) pkSk->kDurationPoly.Eval();
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);if (pkVictim == this)
AddAffect(dwVnum,
POINT_NONE, 0,
AFF_MUYEONG,
iDur,
(long) pkSk->kDurationSPCostPoly.Eval(),
true);return BATTLE_NONE;
}bool bAdded = false;
pkSk->kDurationPoly.SetVar("k", k/*bSkillLevel*/);
int iDur = (int) pkSk->kDurationPoly.Eval();if (iDur > 0)
{
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
// AffectFlag가 없거나, toggle 하는 것이 아니라면..
pkSk->kDurationSPCostPoly.SetVar("k", k/*bSkillLevel*/);if (pkSk->bPointOn2 != POINT_NONE)
{
pkVictim->RemoveAffect(pkSk->dwVnum);int iDur2 = (int) pkSk->kDurationPoly2.Eval();
if (iDur2 > 0)
{
if (test_server)
sys_log(0, "SKILL_AFFECT: %s %s Dur:%d To:%d Amount:%d",
GetName(),
pkSk->szName,
iDur2,
pkSk->bPointOn2,
iAmount2);iDur2 += GetPoint(POINT_PARTY_BUFFER_BONUS);
pkVictim->AddAffect(pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag2, iDur2, 0, false);
}
else
{
pkVictim->PointChange(pkSk->bPointOn2, iAmount2);
}DWORD affact_flag = pkSk->dwAffectFlag;
// ADD_GRANDMASTER_SKILL
//if (g_iUseLocale)
if ( !LC_IsYMIR() )
{
if ((pkSk->dwVnum == SKILL_CHUNKEON && GetUsedSkillMasterType(pkSk->dwVnum) < SKILL_GRAND_MASTER))
affact_flag = AFF_CHEONGEUN_WITH_FALL;
}
else
{
if ((pkSk->dwVnum == SKILL_CHUNKEON && GetUsedSkillMasterType(pkSk->dwVnum) < SKILL_MASTER))
affact_flag = AFF_CHEONGEUN_WITH_FALL;
}
// END_OF_ADD_GRANDMASTER_SKILLpkVictim->AddAffect(pkSk->dwVnum,
pkSk->bPointOn,
iAmount,
affact_flag,
iDur,
(long) pkSk->kDurationSPCostPoly.Eval(),
false);
}
else
{
if (test_server)
sys_log(0, "SKILL_AFFECT: %s %s Dur:%d To:%d Amount:%d",
GetName(),
pkSk->szName,
iDur,
pkSk->bPointOn,
iAmount);pkVictim->AddAffect(pkSk->dwVnum,
pkSk->bPointOn,
iAmount,
pkSk->dwAffectFlag,
iDur,
(long) pkSk->kDurationSPCostPoly.Eval(),
// ADD_GRANDMASTER_SKILL
!bAdded);
// END_OF_ADD_GRANDMASTER_SKILL
}bAdded = true;
}
else
{
if (!pkSk->IsChargeSkill())
pkVictim->PointChange(pkSk->bPointOn, iAmount);if (pkSk->bPointOn2 != POINT_NONE)
{
pkVictim->RemoveAffect(pkSk->dwVnum);int iDur2 = (int) pkSk->kDurationPoly2.Eval();
if (iDur2 > 0)
{
iDur2 += GetPoint(POINT_PARTY_BUFFER_BONUS);if (pkSk->IsChargeSkill())
pkVictim->AddAffect(pkSk->dwVnum, pkSk->bPointOn2, iAmount2, AFF_TANHWAN_DASH, iDur2, 0, false);
else
pkVictim->AddAffect(pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag2, iDur2, 0, false);
}
else
{
pkVictim->PointChange(pkSk->bPointOn2, iAmount2);
}}
}// ADD_GRANDMASTER_SKILL
if (pkSk->bPointOn3 != POINT_NONE && !pkSk->IsChargeSkill() && GetUsedSkillMasterType(pkSk->dwVnum) >= SKILL_GRAND_MASTER)
{pkSk->kDurationPoly3.SetVar("k", k/*bSkillLevel*/);
int iDur = (int) pkSk->kDurationPoly3.Eval();sys_log(0, "try third %u %d %d %d 1894", pkSk->dwVnum, pkSk->bPointOn3, iDur, iAmount3);
if (iDur > 0)
{
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
pkVictim->AddAffect(pkSk->dwVnum, pkSk->bPointOn3, iAmount3, /*pkSk->dwAffectFlag3*/ 0, iDur, 0, !bAdded);
else
{
if (pkVictim->GetSectree())
{
FuncSplashAffect f(this, pkVictim->GetX(), pkVictim->GetY(), pkSk->iSplashRange, pkSk->dwVnum, pkSk->bPointOn3, iAmount3, /*pkSk->dwAffectFlag3*/ 0, iDur, 0, !bAdded, pkSk->lMaxHit);
pkVictim->GetSectree()->ForEachAround(f);
}
}bAdded = true;
}
else
{
pkVictim->PointChange(pkSk->bPointOn3, iAmount3);
}
}
// END_OF_ADD_GRANDMASTER_SKILLreturn BATTLE_NONE;
}
}bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaster)
{
// int pTableSkill[] = {94, 95, 96, 109, 110, 111};
// for (int skill = 0; skill < _countof(pTableSkill); skill++)
// {
// if (pTableSkill[skill] == dwVnum && IsGM() && !pkVictim->IsGM())
// {
// ChatPacket(CHAT_TYPE_NOTICE, "<<Debug>> You try to give buff for player [%s], and this is player, you can't make that, the buff was returned to you.", pkVictim->GetName());
// pkVictim = this;
// }
// }
if (false == CanUseSkill(dwVnum))
return false;if ((dwVnum == SKILL_GEOMKYUNG || dwVnum == SKILL_GWIGEOM) && !GetWear(WEAR_WEAPON))
return false;
// NO_GRANDMASTER
if (test_server)
{
if (quest::CQuestManager::instance().GetEventFlag("no_grand_master"))
{
bUseGrandMaster = false;
}
}
// END_OF_NO_GRANDMASTERif (g_bSkillDisable)
return false;if (IsObserverMode())
return false;if (!CanMove())
return false;if (IsPolymorphed())
return false;const bool bCanUseHorseSkill = CanUseHorseSkill();
if (dwVnum == SKILL_HORSE_SUMMON)
{
if (GetSkillLevel(dwVnum) == 0)
return false;if (GetHorseLevel() <= 0)
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말이 없습니다. 마굿간 경비병을 찾아가세요."));
else
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말 소환 아이템을 사용하세요."));return true;
}// 말을 타고있지만 스킬은 사용할 수 없는 상태라면 return false
if (false == bCanUseHorseSkill && true == IsRiding())
return false;CSkillProto * pkSk = CSkillManager::instance().Get(dwVnum);
sys_log(0, "%s: USE_SKILL: %d pkVictim %p", GetName(), dwVnum, get_pointer(pkVictim));if (!pkSk)
return false;if (bCanUseHorseSkill && pkSk->dwType != SKILL_TYPE_HORSE)
return BATTLE_NONE;if (!bCanUseHorseSkill && pkSk->dwType == SKILL_TYPE_HORSE)
return BATTLE_NONE;if (GetSkillLevel(dwVnum) == 0)
return false;
// NO_GRANDMASTER
if (GetSkillMasterType(dwVnum) < SKILL_GRAND_MASTER)
bUseGrandMaster = false;
// END_OF_NO_GRANDMASTER// MINING
if (GetWear(WEAR_WEAPON) && (GetWear(WEAR_WEAPON)->GetType() == ITEM_ROD || GetWear(WEAR_WEAPON)->GetType() == ITEM_PICK))
return false;
// END_OF_MININGm_SkillUseInfo[dwVnum].TargetVIDMap.clear();
if (pkSk->IsChargeSkill())
{
if (IsAffectFlag(AFF_TANHWAN_DASH) || pkVictim && pkVictim != this)
{
if (!pkVictim)
return false;if (!IsAffectFlag(AFF_TANHWAN_DASH))
{
if (!UseSkill(dwVnum, this))
return false;
}m_SkillUseInfo[dwVnum].SetMainTargetVID(pkVictim->GetVID());
// DASH 상태의 탄환격은 공격기술
ComputeSkill(dwVnum, pkVictim);
RemoveAffect(dwVnum);
return true;
}
}if (dwVnum == SKILL_COMBO)
{
if (m_bComboIndex)
m_bComboIndex = 0;
else
m_bComboIndex = GetSkillLevel(SKILL_COMBO);ChatPacket(CHAT_TYPE_COMMAND, "combo %d", m_bComboIndex);
return true;
}// Toggle 할 때는 SP를 쓰지 않음 (SelfOnly로 구분)
if ((0 != pkSk->dwAffectFlag || pkSk->dwVnum == SKILL_MUYEONG) && (pkSk->dwFlag & SKILL_FLAG_TOGGLE) && RemoveAffect(pkSk->dwVnum))
{
return true;
}if (IsAffectFlag(AFF_REVIVE_INVISIBLE))
RemoveAffect(AFFECT_REVIVE_INVISIBLE);const float k = 1.0 * GetSkillPower(pkSk->dwVnum) * pkSk->bMaxLevel / 100;
pkSk->SetPointVar("k", k);
pkSk->kSplashAroundDamageAdjustPoly.SetVar("k", k);// 쿨타임 체크
pkSk->kCooldownPoly.SetVar("k", k);
int iCooltime = (int) pkSk->kCooldownPoly.Eval();
int lMaxHit = pkSk->lMaxHit ? pkSk->lMaxHit : -1;pkSk->SetSPCostVar("k", k);
DWORD dwCur = get_dword_time();
if (dwVnum == SKILL_TERROR && m_SkillUseInfo[dwVnum].bUsed && m_SkillUseInfo[dwVnum].dwNextSkillUsableTime > dwCur )
{
sys_log(0, " SKILL_TERROR's Cooltime is not delta over %u", m_SkillUseInfo[dwVnum].dwNextSkillUsableTime - dwCur );
return false;
}int iNeededSP = 0;
if (IS_SET(pkSk->dwFlag, SKILL_FLAG_USE_HP_AS_COST))
{
pkSk->SetSPCostVar("maxhp", GetMaxHP());
pkSk->SetSPCostVar("v", GetHP());
iNeededSP = (int) pkSk->kSPCostPoly.Eval();// ADD_GRANDMASTER_SKILL
if (GetSkillMasterType(dwVnum) >= SKILL_GRAND_MASTER && bUseGrandMaster)
{
iNeededSP = (int) pkSk->kGrandMasterAddSPCostPoly.Eval();
}
// END_OF_ADD_GRANDMASTER_SKILLif (GetHP() < iNeededSP)
return false;PointChange(POINT_HP, -iNeededSP);
}
else
{
// SKILL_FOMULA_REFACTORING
pkSk->SetSPCostVar("maxhp", GetMaxHP());
pkSk->SetSPCostVar("maxv", GetMaxSP());
pkSk->SetSPCostVar("v", GetSP());iNeededSP = (int) pkSk->kSPCostPoly.Eval();
if (GetSkillMasterType(dwVnum) >= SKILL_GRAND_MASTER && bUseGrandMaster)
{
iNeededSP = (int) pkSk->kGrandMasterAddSPCostPoly.Eval();
}
// END_OF_SKILL_FOMULA_REFACTORINGif (GetSP() < iNeededSP)
return false;if (test_server)
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s SP소모: %d"), pkSk->szName, iNeededSP);PointChange(POINT_SP, -iNeededSP);
}if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY))
pkVictim = this;if (IS_SET(pkSk->dwFlag, SKILL_FLAG_PARTY) && !GetParty())
pkVictim = this;if (pkSk->dwVnum == SKILL_MUYEONG || pkSk->IsChargeSkill() && !IsAffectFlag(AFF_TANHWAN_DASH) && !pkVictim)
{
// 처음 사용하는 무영진은 자신에게 Affect를 붙인다.
pkVictim = this;
}int iSplashCount = 1;
if (false == m_bDisableCooltime)
{
if (false ==
m_SkillUseInfo[dwVnum].UseSkill(
bUseGrandMaster,
(NULL != pkVictim && SKILL_HORSE_WILDATTACK != dwVnum) ? pkVictim->GetVID() : NULL,
ComputeCooltime(iCooltime * 1000),
iSplashCount,
lMaxHit))
{
if (test_server)
ChatPacket(CHAT_TYPE_NOTICE, "cooltime not finished %s %d", pkSk->szName, iCooltime);return false;
}
}if (dwVnum == SKILL_CHAIN)
{
ResetChainLightningIndex();
AddChainLightningExcept(pkVictim);
}
if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY))
ComputeSkill(dwVnum, this);
else if (IS_SET(pkSk->dwFlag, SKILL_FLAG_PARTY) && !GetParty())ComputeSkill(dwVnum, this);
else if (IS_SET(pkSk->dwFlag, SKILL_FLAG_PARTY) && GetParty())
{
FPartyPIDCollector f;
GetParty()->ForEachOnMapMember(f, GetMapIndex());
for (std::vector <DWORD>::iterator it = f.vecPIDs.begin(); it != f.vecPIDs.end(); it++)
{
LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(*it);
ComputeSkill(dwVnum, ch);
}
}
else if (IS_SET(pkSk->dwFlag, SKILL_FLAG_PARTY) && !GetParty())
ComputeSkill(dwVnum, this);
else if (IS_SET(pkSk->dwFlag, SKILL_FLAG_PARTYALL) && GetParty())
{
FPartyPIDCollector f;
GetParty()->ForEachOnMapMember(f, GetMapIndex());
for (std::vector <DWORD>::iterator it = f.vecPIDs.begin(); it != f.vecPIDs.end(); it++)
{
LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(*it);
ComputeSkill(dwVnum, ch);
}
}
else if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_ATTACK))
ComputeSkill(dwVnum, pkVictim);
else if (dwVnum == SKILL_BYEURAK)
ComputeSkill(dwVnum, pkVictim);
else if (dwVnum == SKILL_MUYEONG || pkSk->IsChargeSkill())
ComputeSkill(dwVnum, pkVictim);m_dwLastSkillTime = get_dword_time();
return true;
}int CHARACTER::GetUsedSkillMasterType(DWORD dwVnum)
{
const TSkillUseInfo& rInfo = m_SkillUseInfo[dwVnum];if (GetSkillMasterType(dwVnum) < SKILL_GRAND_MASTER)
return GetSkillMasterType(dwVnum);if (rInfo.isGrandMaster)
return GetSkillMasterType(dwVnum);return MIN(GetSkillMasterType(dwVnum), SKILL_MASTER);
}int CHARACTER::GetSkillMasterType(DWORD dwVnum) const
{
if (!IsPC())
return 0;if (dwVnum >= SKILL_MAX_NUM)
{
sys_err("%s skill vnum overflow %u", GetName(), dwVnum);
return 0;
}return m_pSkillLevels ? m_pSkillLevels[dwVnum].bMasterType:SKILL_NORMAL;
}int CHARACTER::GetSkillPower(DWORD dwVnum, BYTE bLevel) const
{
// 인어반지 아이템
if (dwVnum >= SKILL_LANGUAGE1 && dwVnum <= SKILL_LANGUAGE3 && IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE))
{
return 100;
}if (dwVnum >= GUILD_SKILL_START && dwVnum <= GUILD_SKILL_END)
{
if (GetGuild())
return 100 * GetGuild()->GetSkillLevel(dwVnum) / 7 / 7;
else
return 0;
}if (bLevel)
{
//SKILL_POWER_BY_LEVEL
return GetSkillPowerByLevel(bLevel, true);
//END_SKILL_POWER_BY_LEVEL;
}if (dwVnum >= SKILL_MAX_NUM)
{
sys_err("%s skill vnum overflow %u", GetName(), dwVnum);
return 0;
}//SKILL_POWER_BY_LEVEL
return GetSkillPowerByLevel(GetSkillLevel(dwVnum));
//SKILL_POWER_BY_LEVEL
}int CHARACTER::GetSkillLevel(DWORD dwVnum) const
{
if (dwVnum >= SKILL_MAX_NUM)
{
sys_err("%s skill vnum overflow %u", GetName(), dwVnum);
sys_log(0, "%s skill vnum overflow %u", GetName(), dwVnum);
return 0;
}return MIN(SKILL_MAX_LEVEL, m_pSkillLevels ? m_pSkillLevels[dwVnum].bLevel : 0);
}EVENTFUNC(skill_muyoung_event)
{
char_event_info* info = dynamic_cast<char_event_info*>( event->info );if ( info == NULL )
{
sys_err( "skill_muyoung_event> <Factor> Null pointer" );
return 0;
}LPCHARACTER ch = info->ch;
if (ch == NULL) { // <Factor>
return 0;
}if (!ch->IsAffectFlag(AFF_MUYEONG))
{
ch->StopMuyeongEvent();
return 0;
}// 1. Find Victim
FFindNearVictim f(ch, ch);
if (ch->GetSectree())
{
ch->GetSectree()->ForEachAround(f);
// 2. Shoot!
if (f.GetVictim())
{
ch->CreateFly(FLY_SKILL_MUYEONG, f.GetVictim());
ch->ComputeSkill(SKILL_MUYEONG, f.GetVictim());
}
}return PASSES_PER_SEC(3);
}void CHARACTER::StartMuyeongEvent()
{
if (m_pkMuyeongEvent)
return;char_event_info* info = AllocEventInfo<char_event_info>();
info->ch = this;
m_pkMuyeongEvent = event_create(skill_muyoung_event, info, PASSES_PER_SEC(1));
}void CHARACTER::StopMuyeongEvent()
{
event_cancel(&m_pkMuyeongEvent);
}void CHARACTER::SkillLearnWaitMoreTimeMessage(DWORD ms)
{
//const char* str = "";
//
if (ms < 3 * 60)
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("몸 속이 뜨겁군. 하지만 아주 편안해. 이대로 기를 안정시키자."));
else if (ms < 5 * 60)
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("그래, 천천히. 좀더 천천히, 그러나 막힘 없이 빠르게!"));
else if (ms < 10 * 60) // 10분
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("그래, 이 느낌이야. 체내에 기가 아주 충만해."));
else if (ms < 30 * 60) // 30분
{
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("다 읽었다! 이제 비급에 적혀있는 대로 전신에 기를 돌리기만 하면,"));
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("그것으로 수련은 끝난 거야!"));
}
else if (ms < 1 * 3600) // 1시간
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("이제 책의 마지막 장이야! 수련의 끝이 눈에 보이고 있어!"));
else if (ms < 2 * 3600) // 2시간
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("얼마 안 남았어! 조금만 더!"));
else if (ms < 3 * 3600)
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("좋았어! 조금만 더 읽으면 끝이다!"));
else if (ms < 6 * 3600)
{
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("책장도 이제 얼마 남지 않았군."));
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("뭔가 몸 안에 힘이 생기는 기분인 걸."));
}
else if (ms < 12 * 3600)
{
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("이제 좀 슬슬 가닥이 잡히는 것 같은데."));
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("좋아, 이 기세로 계속 나간다!"));
}
else if (ms < 18 * 3600)
{
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("아니 어떻게 된 게 종일 읽어도 머리에 안 들어오냐."));
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("공부하기 싫어지네."));
}
else //if (ms < 2 * 86400)
{
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("생각만큼 읽기가 쉽지가 않군. 이해도 어렵고 내용도 난해해."));
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("이래서야 공부가 안된다구."));
}
/*
str = "30%";
else if (ms < 3 * 86400)
str = "10%";
else if (ms < 4 * 86400)
str = "5%";
else
str = "0%";*///ChatPacket(CHAT_TYPE_TALKING, "%s", str);
}void CHARACTER::DisableCooltime()
{
m_bDisableCooltime = true;
}bool CHARACTER::HasMobSkill() const
{
return CountMobSkill() > 0;
}size_t CHARACTER::CountMobSkill() const
{
if (!m_pkMobData)
return 0;size_t c = 0;
for (size_t i = 0; i < MOB_SKILL_MAX_NUM; ++i)
if (m_pkMobData->m_table.Skills.dwVnum)
++c;return c;
}const TMobSkillInfo* CHARACTER::GetMobSkill(unsigned int idx) const
{
if (idx >= MOB_SKILL_MAX_NUM)
return NULL;if (!m_pkMobData)
return NULL;if (0 == m_pkMobData->m_table.Skills[idx].dwVnum)
return NULL;return &m_pkMobData->m_mobSkillInfo[idx];
}bool CHARACTER::CanUseMobSkill(unsigned int idx) const
{
const TMobSkillInfo* pInfo = GetMobSkill(idx);if (!pInfo)
return false;if (m_adwMobSkillCooltime[idx] > get_dword_time())
return false;if (number(0, 1))
return false;return true;
}EVENTINFO(mob_skill_event_info)
{
DynamicCharacterPtr ch;
PIXEL_POSITION pos;
DWORD vnum;
int index;
BYTE level;mob_skill_event_info()
: ch()
, pos()
, vnum(0)
, index(0)
, level(0)
{
}
};EVENTFUNC(mob_skill_hit_event)
{
mob_skill_event_info * info = dynamic_cast<mob_skill_event_info *>( event->info );if ( info == NULL )
{
sys_err( "mob_skill_event_info> <Factor> Null pointer" );
return 0;
}// <Factor>
LPCHARACTER ch = info->ch;
if (ch == NULL) {
return 0;
}ch->ComputeSkillAtPosition(info->vnum, info->pos, info->level);
ch->m_mapMobSkillEvent.erase(info->index);return 0;
}bool CHARACTER::UseMobSkill(unsigned int idx)
{
if (IsPC())
return false;const TMobSkillInfo* pInfo = GetMobSkill(idx);
if (!pInfo)
return false;DWORD dwVnum = pInfo->dwSkillVnum;
CSkillProto * pkSk = CSkillManager::instance().Get(dwVnum);if (!pkSk)
return false;const float k = 1.0 * GetSkillPower(pkSk->dwVnum, pInfo->bSkillLevel) * pkSk->bMaxLevel / 100;
pkSk->kCooldownPoly.SetVar("k", k);
int iCooltime = (int) (pkSk->kCooldownPoly.Eval() * 1000);m_adwMobSkillCooltime[idx] = get_dword_time() + iCooltime;
sys_log(0, "USE_MOB_SKILL: %s idx %d vnum %u cooltime %d", GetName(), idx, dwVnum, iCooltime);
if (m_pkMobData->m_mobSkillInfo[idx].vecSplashAttack.empty())
{
sys_err("No skill hit data for mob %s index %d", GetName(), idx);
return false;
}for (size_t i = 0; i < m_pkMobData->m_mobSkillInfo[idx].vecSplashAttack.size(); i++)
{
PIXEL_POSITION pos = GetXYZ();
const TMobSplashAttackInfo& rInfo = m_pkMobData->m_mobSkillInfo[idx].vecSplashAttack;if (rInfo.dwHitDistance)
{
float fx, fy;
GetDeltaByDegree(GetRotation(), rInfo.dwHitDistance, &fx, &fy);
pos.x += (long) fx;
pos.y += (long) fy;
}if (rInfo.dwTiming)
{
if (test_server)
sys_log(0, " timing %ums", rInfo.dwTiming);mob_skill_event_info* info = AllocEventInfo<mob_skill_event_info>();
info->ch = this;
info->pos = pos;
info->level = pInfo->bSkillLevel;
info->vnum = dwVnum;
info->index = i;// <Factor> Cancel existing event first
itertype(m_mapMobSkillEvent) it = m_mapMobSkillEvent.find(i);
if (it != m_mapMobSkillEvent.end()) {
LPEVENT existing = it->second;
event_cancel(&existing);
m_mapMobSkillEvent.erase(it);
}m_mapMobSkillEvent.insert(std::make_pair(i, event_create(mob_skill_hit_event, info, PASSES_PER_SEC(rInfo.dwTiming) / 1000)));
}
else
{
ComputeSkillAtPosition(dwVnum, pos, pInfo->bSkillLevel);
}
}return true;
}void CHARACTER::ResetMobSkillCooltime()
{
memset(m_adwMobSkillCooltime, 0, sizeof(m_adwMobSkillCooltime));
}bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
{
DWORD selfJobGroup = (GetJob() + 1) * 10 + GetSkillGroup();const DWORD SKILL_NUM = 176;
static DWORD s_anSkill2JobGroup[SKILL_NUM] = {
0, // common_skill 0
11, // job_skill 1
11, // job_skill 2
11, // job_skill 3
11, // job_skill 4
11, // job_skill 5
11, // job_skill 6
0, // common_skill 7
0, // common_skill 8
0, // common_skill 9
0, // common_skill 10
0, // common_skill 11
0, // common_skill 12
0, // common_skill 13
0, // common_skill 14
0, // common_skill 15
12, // job_skill 16
12, // job_skill 17
12, // job_skill 18
12, // job_skill 19
12, // job_skill 20
12, // job_skill 21
0, // common_skill 22
0, // common_skill 23
0, // common_skill 24
0, // common_skill 25
0, // common_skill 26
0, // common_skill 27
0, // common_skill 28
0, // common_skill 29
0, // common_skill 30
21, // job_skill 31
21, // job_skill 32
21, // job_skill 33
21, // job_skill 34
21, // job_skill 35
21, // job_skill 36
0, // common_skill 37
0, // common_skill 38
0, // common_skill 39
0, // common_skill 40
0, // common_skill 41
0, // common_skill 42
0, // common_skill 43
0, // common_skill 44
0, // common_skill 45
22, // job_skill 46
22, // job_skill 47
22, // job_skill 48
22, // job_skill 49
22, // job_skill 50
22, // job_skill 51
0, // common_skill 52
0, // common_skill 53
0, // common_skill 54
0, // common_skill 55
0, // common_skill 56
0, // common_skill 57
0, // common_skill 58
0, // common_skill 59
0, // common_skill 60
31, // job_skill 61
31, // job_skill 62
31, // job_skill 63
31, // job_skill 64
31, // job_skill 65
31, // job_skill 66
0, // common_skill 67
0, // common_skill 68
0, // common_skill 69
0, // common_skill 70
0, // common_skill 71
0, // common_skill 72
0, // common_skill 73
0, // common_skill 74
0, // common_skill 75
32, // job_skill 76
32, // job_skill 77
32, // job_skill 78
32, // job_skill 79
32, // job_skill 80
32, // job_skill 81
0, // common_skill 82
0, // common_skill 83
0, // common_skill 84
0, // common_skill 85
0, // common_skill 86
0, // common_skill 87
0, // common_skill 88
0, // common_skill 89
0, // common_skill 90
41, // job_skill 91
41, // job_skill 92
41, // job_skill 93
41, // job_skill 94
41, // job_skill 95
41, // job_skill 96
0, // common_skill 97
0, // common_skill 98
0, // common_skill 99
0, // common_skill 100
0, // common_skill 101
0, // common_skill 102
0, // common_skill 103
0, // common_skill 104
0, // common_skill 105
42, // job_skill 106
42, // job_skill 107
42, // job_skill 108
42, // job_skill 109
42, // job_skill 110
42, // job_skill 111
0, // common_skill 112
0, // common_skill 113
0, // common_skill 114
0, // common_skill 115
0, // common_skill 116
0, // common_skill 117
0, // common_skill 118
0, // common_skill 119
0, // common_skill 120
0, // common_skill 121
0, // common_skill 122
0, // common_skill 123
0, // common_skill 124
0, // common_skill 125
0, // common_skill 126
0, // common_skill 127
0, // common_skill 128
0, // common_skill 129
0, // common_skill 130
0, // common_skill 131
0, // common_skill 132
0, // common_skill 133
0, // common_skill 134
0, // common_skill 135
0, // common_skill 136
0, // job_skill 137
0, // job_skill 138
0, // job_skill 139
0, // job_skill 140
0, // common_skill 141
0, // common_skill 142
0, // common_skill 143
0, // common_skill 144
0, // common_skill 145
0, // common_skill 146
0, // common_skill 147
0, // common_skill 148
0, // common_skill 149
0, // common_skill 150
0, // common_skill 151
0, // job_skill 152
0, // job_skill 153
0, // job_skill 154
0, // job_skill 155
0, // job_skill 156
0, // job_skill 157
0, // empty(reserved) 158
0, // empty(reserved) 159
0, // empty(reserved) 160
0, // empty(reserved) 161
0, // empty(reserved) 162
0, // empty(reserved) 163
0, // empty(reserved) 164
0, // empty(reserved) 165
0, // empty(reserved) 166
0, // empty(reserved) 167
0, // empty(reserved) 168
0, // empty(reserved) 169
51, // job_skill(WOLFMAN SKILL) 170
51, // job_skill(WOLFMAN SKILL) 171
51, // job_skill(WOLFMAN SKILL) 172
51, // job_skill(WOLFMAN SKILL) 173
51, // job_skill(WOLFMAN SKILL) 174
51, // job_skill(WOLFMAN SKILL) 175
};const DWORD MOTION_MAX_NUM = 124;
const DWORD SKILL_LIST_MAX_COUNT = 6;static DWORD s_anMotion2SkillVnumList[MOTION_MAX_NUM][SKILL_LIST_MAX_COUNT] =
{
{ 0, 0, 0, 0, 0 }, // 0
{ 5, 1, 31, 61, 91, 170, }, // 1
{ 5, 2, 32, 62, 92, 171, }, // 2
{ 5, 3, 33, 63, 93, 172, }, // 3
{ 5, 4, 34, 64, 94, 173, }, // 4
{ 5, 5, 35, 65, 95, 174, }, // 5
{ 5, 6, 36, 66, 96, 175, }, // 6
{ 0, 0, 0, 0, 0, }, // 7
{ 0, 0, 0, 0, 0, }, // 8
{ 0, 0, 0, 0, 0, }, // 9
{ 0, 0, 0, 0, 0, }, // 10
{ 0, 0, 0, 0, 0, }, // 11
{ 0, 0, 0, 0, 0, }, // 12
{ 0, 0, 0, 0, 0, }, // 13
{ 0, 0, 0, 0, 0, }, // 14
{ 0, 0, 0, 0, 0, }, // 15
{ 4, 16, 46, 76, 106, }, // 16
{ 4, 17, 47, 77, 107, }, // 17
{ 4, 18, 48, 78, 108, }, // 18
{ 4, 19, 49, 79, 109, }, // 19
{ 4, 20, 50, 80, 110, }, // 20
{ 4, 21, 51, 81, 111, }, // 21
{ 0, 0, 0, 0, 0, }, // 22
{ 0, 0, 0, 0, 0, }, // 23
{ 0, 0, 0, 0, 0, }, // 24
{ 0, 0, 0, 0, 0, }, // 25
{ 5, 1, 31, 61, 91, 170, }, // 26
{ 5, 2, 32, 62, 92, 171, }, // 27
{ 5, 3, 33, 63, 93, 172, }, // 28
{ 5, 4, 34, 64, 94, 173, }, // 29
{ 5, 5, 35, 65, 95, 174, }, // 30
{ 5, 6, 36, 66, 96, 175, }, // 31
{ 0, 0, 0, 0, 0, }, // 32
{ 0, 0, 0, 0, 0, }, // 33
{ 0, 0, 0, 0, 0, }, // 34
{ 0, 0, 0, 0, 0, }, // 35
{ 0, 0, 0, 0, 0, }, // 36
{ 0, 0, 0, 0, 0, }, // 37
{ 0, 0, 0, 0, 0, }, // 38
{ 0, 0, 0, 0, 0, }, // 39
{ 0, 0, 0, 0, 0, }, // 40
{ 4, 16, 46, 76, 106, }, // 41
{ 4, 17, 47, 77, 107, }, // 42
{ 4, 18, 48, 78, 108, }, // 43
{ 4, 19, 49, 79, 109, }, // 44
{ 4, 20, 50, 80, 110, }, // 45
{ 4, 21, 51, 81, 111, }, // 46
{ 0, 0, 0, 0, 0, }, // 47
{ 0, 0, 0, 0, 0, }, // 48
{ 0, 0, 0, 0, 0 }, // 49
{ 0, 0, 0, 0, 0 }, // 50
{ 5, 1, 31, 61, 91, 170, }, // 51
{ 5, 2, 32, 62, 92, 171, }, // 52
{ 5, 3, 33, 63, 93, 172, }, // 53
{ 5, 4, 34, 64, 94, 173, }, // 54
{ 5, 5, 35, 65, 95, 174, }, // 55
{ 5, 6, 36, 66, 96, 175, }, // 56
{ 0, 0, 0, 0, 0, }, // 57
{ 0, 0, 0, 0, 0, }, // 58
{ 0, 0, 0, 0, 0, }, // 59
{ 0, 0, 0, 0, 0, }, // 60
{ 0, 0, 0, 0, 0, }, // 61
{ 0, 0, 0, 0, 0, }, // 62
{ 0, 0, 0, 0, 0, }, // 63
{ 0, 0, 0, 0, 0, }, // 64
{ 0, 0, 0, 0, 0, }, // 65
{ 4, 16, 46, 76, 106, }, // 66
{ 4, 17, 47, 77, 107, }, // 67
{ 4, 18, 48, 78, 108, }, // 68
{ 4, 19, 49, 79, 109, }, // 69
{ 4, 20, 50, 80, 110, }, // 70
{ 4, 21, 51, 81, 111, }, // 71
{ 0, 0, 0, 0, 0, }, // 72
{ 0, 0, 0, 0, 0, }, // 73
{ 0, 0, 0, 0, 0, }, // 74
{ 0, 0, 0, 0, 0, }, // 75
{ 5, 1, 31, 61, 91, 170, }, // 76
{ 5, 2, 32, 62, 92, 171, }, // 77
{ 5, 3, 33, 63, 93, 172, }, // 78
{ 5, 4, 34, 64, 94, 173, }, // 79
{ 5, 5, 35, 65, 95, 174, }, // 80
{ 5, 6, 36, 66, 96, 175, }, // 81
{ 0, 0, 0, 0, 0, }, // 82
{ 0, 0, 0, 0, 0, }, // 83
{ 0, 0, 0, 0, 0, }, // 84
{ 0, 0, 0, 0, 0, }, // 85
{ 0, 0, 0, 0, 0, }, // 86
{ 0, 0, 0, 0, 0, }, // 87
{ 0, 0, 0, 0, 0, }, // 88
{ 0, 0, 0, 0, 0, }, // 89
{ 0, 0, 0, 0, 0, }, // 90
{ 4, 16, 46, 76, 106, }, // 91
{ 4, 17, 47, 77, 107, }, // 92
{ 4, 18, 48, 78, 108, }, // 93
{ 4, 19, 49, 79, 109, }, // 94
{ 4, 20, 50, 80, 110, }, // 95
{ 4, 21, 51, 81, 111, }, // 96
{ 0, 0, 0, 0, 0, }, // 97
{ 0, 0, 0, 0, 0, }, // 98
{ 0, 0, 0, 0, 0, }, // 99
{ 0, 0, 0, 0, 0, }, // 100
{ 1, 152, 0, 0, 0, }, // 101
{ 1, 153, 0, 0, 0, }, // 102
{ 1, 154, 0, 0, 0, }, // 103
{ 1, 155, 0, 0, 0, }, // 104
{ 1, 156, 0, 0, 0, }, // 105
{ 1, 157, 0, 0, 0, }, // 106
{ 0, 0, 0, 0, 0, }, // 107
{ 0, 0, 0, 0, 0, }, // 108
{ 0, 0, 0, 0, 0, }, // 109
{ 0, 0, 0, 0, 0, }, // 110
{ 0, 0, 0, 0, 0, }, // 111
{ 0, 0, 0, 0, 0, }, // 112
{ 0, 0, 0, 0, 0, }, // 113
{ 0, 0, 0, 0, 0, }, // 114
{ 0, 0, 0, 0, 0, }, // 115
{ 0, 0, 0, 0, 0, }, // 116
{ 0, 0, 0, 0, 0, }, // 117
{ 0, 0, 0, 0, 0, }, // 118
{ 0, 0, 0, 0, 0, }, // 119
{ 0, 0, 0, 0, 0, }, // 120
{ 2, 137, 140, 0, 0, }, // 121
{ 1, 138, 0, 0, 0, }, // 122
{ 1, 139, 0, 0, 0, }, // 123
};if (dwMotionIndex >= MOTION_MAX_NUM)
{
sys_err("OUT_OF_MOTION_VNUM: name=%s, motion=%d/%d", GetName(), dwMotionIndex, MOTION_MAX_NUM);
return false;
}DWORD* skillVNums = s_anMotion2SkillVnumList[dwMotionIndex];
DWORD skillCount = *skillVNums++;
if (skillCount >= SKILL_LIST_MAX_COUNT)
{
sys_err("OUT_OF_SKILL_LIST: name=%s, count=%d/%d", GetName(), skillCount, SKILL_LIST_MAX_COUNT);
return false;
}for (DWORD skillIndex = 0; skillIndex != skillCount; ++skillIndex)
{
if (skillIndex >= SKILL_MAX_NUM)
{
sys_err("OUT_OF_SKILL_VNUM: name=%s, skill=%d/%d", GetName(), skillIndex, SKILL_MAX_NUM);
return false;
}DWORD eachSkillVNum = skillVNums[skillIndex];
if ( eachSkillVNum != 0 )
{
DWORD eachJobGroup = s_anSkill2JobGroup[eachSkillVNum];
if (0 == eachJobGroup || eachJobGroup == selfJobGroup)
{
DWORD eachSkillLevel = 0;
if (eachSkillVNum >= GUILD_SKILL_START && eachSkillVNum <= GUILD_SKILL_END)
{
if (GetGuild())
eachSkillLevel = GetGuild()->GetSkillLevel(eachSkillVNum);
else
eachSkillLevel = 0;
}
else
{
eachSkillLevel = GetSkillLevel(eachSkillVNum);
}if (eachSkillLevel > 0)
{
return true;
}
}
}
}return false;
}void CHARACTER::ClearSkill()
{
PointChange(POINT_SKILL, 4 + (GetLevel() - 5) - GetPoint(POINT_SKILL));ResetSkill();
}void CHARACTER::ClearSubSkill()
{
PointChange(POINT_SUB_SKILL, GetLevel() < 10 ? 0 : (GetLevel() - 9) - GetPoint(POINT_SUB_SKILL));if (m_pSkillLevels == NULL)
{
sys_err("m_pSkillLevels nil (name: %s)", GetName());
return;
}TPlayerSkill CleanSkill;
memset(&CleanSkill, 0, sizeof(TPlayerSkill));size_t count = sizeof(s_adwSubSkillVnums) / sizeof(s_adwSubSkillVnums[0]);
for (size_t i = 0; i < count; ++i)
{
if (s_adwSubSkillVnums >= SKILL_MAX_NUM)
continue;m_pSkillLevels[s_adwSubSkillVnums] = CleanSkill;
}ComputePoints();
SkillLevelPacket();
}bool CHARACTER::ResetOneSkill(DWORD dwVnum)
{
if (NULL == m_pSkillLevels)
{
sys_err("m_pSkillLevels nil (name %s, vnum %u)", GetName(), dwVnum);
return false;
}if (dwVnum >= SKILL_MAX_NUM)
{
sys_err("vnum overflow (name %s, vnum %u)", GetName(), dwVnum);
return false;
}BYTE level = m_pSkillLevels[dwVnum].bLevel;
m_pSkillLevels[dwVnum].bLevel = 0;
m_pSkillLevels[dwVnum].bMasterType = 0;
m_pSkillLevels[dwVnum].tNextRead = 0;if (level > 17)
level = 17;PointChange(POINT_SKILL, level);
LogManager::instance().CharLog(this, dwVnum, "ONE_SKILL_RESET_BY_SCROLL", "");
ComputePoints();
SkillLevelPacket();return true;
}bool CHARACTER::CanUseSkill(DWORD dwSkillVnum) const
{
if (0 == dwSkillVnum) return false;if (0 < GetSkillGroup())
{
const int SKILL_COUNT = 6;
static const DWORD SkillList[JOB_MAX_NUM][SKILL_GROUP_MAX_NUM][SKILL_COUNT] =
{
{{1, 2, 3, 4, 5, 6}, {16, 17, 18, 19, 20, 21}},
{{31, 32, 33, 34, 35, 36}, {46, 47, 48, 49, 50, 51}},
{{61, 62, 63, 64, 65, 66}, {76, 77, 78, 79, 80, 81}},
{{91, 92, 93, 94, 95, 96}, {106, 107, 108, 109, 110, 111}},
{{170, 171, 172, 173, 174, 175},},
};const DWORD* pSkill = SkillList[ GetJob() ][ GetSkillGroup()-1 ];
for (int i=0 ; i < SKILL_COUNT ; ++i)
{
if (pSkill == dwSkillVnum) return true;
}
}if (true == IsRiding())
{
if(GetMountVnum())
{
if( !((GetMountVnum() >= 20209 && GetMountVnum() <= 20212) ||
GetMountVnum() == 20215 || GetMountVnum() == 20218 || GetMountVnum() == 20225 ) )
return false;
}switch(dwSkillVnum)
{
case SKILL_HORSE_WILDATTACK:
case SKILL_HORSE_CHARGE:
case SKILL_HORSE_ESCAPE:
case SKILL_HORSE_WILDATTACK_RANGE:
return true;
}
}switch( dwSkillVnum )
{
case 121: case 122: case 124: case 126: case 127: case 128: case 129: case 130:
case 131:
case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159:
return true;
}return false;
}bool CHARACTER::CheckSkillHitCount(const BYTE SkillID, const VID TargetVID)
{
std::map<int, TSkillUseInfo>::iterator iter = m_SkillUseInfo.find(SkillID);if (iter == m_SkillUseInfo.end())
{
sys_log(0, "SkillHack: Skill(%u) is not in container", SkillID);
return false;
}TSkillUseInfo& rSkillUseInfo = iter->second;
if (false == rSkillUseInfo.bUsed)
{
sys_log(0, "SkillHack: not used skill(%u)", SkillID);
return false;
}switch (SkillID)
{
case SKILL_YONGKWON:
case SKILL_HWAYEOMPOK:
case SKILL_DAEJINGAK:
case SKILL_PAERYONG:
sys_log(0, "SkillHack: cannot use attack packet for skill(%u)", SkillID);
return false;
}boost::unordered_map<VID, size_t>::iterator iterTargetMap = rSkillUseInfo.TargetVIDMap.find(TargetVID);
if (rSkillUseInfo.TargetVIDMap.end() != iterTargetMap)
{
size_t MaxAttackCountPerTarget = 1;switch (SkillID)
{
case SKILL_SAMYEON:
case SKILL_CHARYUN:
case SKILL_CHAYEOL:
case SKILL_PASWAE:
MaxAttackCountPerTarget = 3;
break;case SKILL_HORSE_WILDATTACK_RANGE:
MaxAttackCountPerTarget = 5;
break;case SKILL_YEONSA:
MaxAttackCountPerTarget = 7;
break;case SKILL_HORSE_ESCAPE:
MaxAttackCountPerTarget = 10;
break;
}if (iterTargetMap->second >= MaxAttackCountPerTarget)
{
sys_log(0, "SkillHack: Too Many Hit count from SkillID(%u) count(%u)", SkillID, iterTargetMap->second);
return false;
}iterTargetMap->second++;
}
else
{
rSkillUseInfo.TargetVIDMap.insert( std::make_pair(TargetVID, 1) );
}return true;
}
-
any ideas to fix it?
-
-
download link is down please update it
-
Hello metin2dev,
i have a problem about my mysql when i am rebooting the server the new tables getting crash and i cant open them
the problem starts when i deleted these files:https://metin2.download/picture/r3F9504x09DVmF8K988YXgTtGTP6KMUj/.gif
now the syserr of root601841.kms4.cc.err
Spoiler180118 18:20:23 mysqld_safe mysqld from pid file /var/db/mysql/root601841.kms4.cc.pid ended
180118 18:21:10 mysqld_safe Logging to '/var/db/mysql/root601841.kms4.cc.err'.
180118 18:21:10 mysqld_safe Starting mysqld daemon with databases from /var/db/mysql
2018-01-18 18:21:12 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2018-01-18 18:21:12 0 [Note] /usr/local/libexec/mysqld (mysqld 5.6.38) starting as process 684 ...
2018-01-18 18:21:12 684 [Note] Plugin 'FEDERATED' is disabled.
/usr/local/libexec/mysqld: Table 'mysql.plugin' doesn't exist
2018-01-18 18:21:12 684 [ERROR] Can't open the mysql.plugin table. Please run mysql_upgrade to create it.
2018-01-18 18:21:12 684 [Note] InnoDB: Using atomics to ref count buffer pool pages
2018-01-18 18:21:12 684 [Note] InnoDB: The InnoDB memory heap is disabled
2018-01-18 18:21:12 684 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
2018-01-18 18:21:12 684 [Note] InnoDB: Memory barrier is not used
2018-01-18 18:21:12 684 [Note] InnoDB: Compressed tables use zlib 1.2.8
2018-01-18 18:21:12 684 [Note] InnoDB: Using CPU crc32 instructions
2018-01-18 18:21:12 684 [Note] InnoDB: Initializing buffer pool, size = 128.0M
2018-01-18 18:21:12 684 [Note] InnoDB: Completed initialization of buffer pool
2018-01-18 18:21:12 684 [Note] InnoDB: The first specified data file ./ibdata1 did not exist: a new database to be created!
2018-01-18 18:21:12 684 [Note] InnoDB: Setting file ./ibdata1 size to 12 MB
2018-01-18 18:21:12 684 [Note] InnoDB: Database physically writes the file full: wait...
2018-01-18 18:21:12 684 [Note] InnoDB: Setting log file ./ib_logfile101 size to 48 MB
2018-01-18 18:21:13 684 [Note] InnoDB: Setting log file ./ib_logfile1 size to 48 MB
2018-01-18 18:21:13 684 [Note] InnoDB: Renaming log file ./ib_logfile101 to ./ib_logfile0
2018-01-18 18:21:13 684 [Warning] InnoDB: New log files created, LSN=45781
2018-01-18 18:21:13 684 [Note] InnoDB: Doublewrite buffer not found: creating new
2018-01-18 18:21:13 684 [Note] InnoDB: Doublewrite buffer created
2018-01-18 18:21:13 684 [Note] InnoDB: 128 rollback segment(s) are active.
2018-01-18 18:21:13 684 [Warning] InnoDB: Creating foreign key constraint system tables.
2018-01-18 18:21:13 684 [Note] InnoDB: Foreign key constraint system tables created
2018-01-18 18:21:13 684 [Note] InnoDB: Creating tablespace and datafile system tables.
2018-01-18 18:21:13 684 [Note] InnoDB: Tablespace and datafile system tables created.
2018-01-18 18:21:13 684 [Note] InnoDB: Waiting for purge to start
2018-01-18 18:21:13 684 [Note] InnoDB: 5.6.38 started; log sequence number 0
2018-01-18 18:21:13 684 [Note] RSA private key file not found: /var/db/mysql//private_key.pem. Some authentication plugins will not work.
2018-01-18 18:21:13 684 [Note] RSA public key file not found: /var/db/mysql//public_key.pem. Some authentication plugins will not work.
2018-01-18 18:21:13 684 [Note] Server hostname (bind-address): '*'; port: 3306
2018-01-18 18:21:13 684 [Note] IPv6 is available.
2018-01-18 18:21:13 684 [Note] - '::' resolves to '::';
2018-01-18 18:21:13 684 [Note] Server socket created on IP: '::'.
2018-01-18 18:21:13 684 [ERROR] Missing system table mysql.proxies_priv; please run mysql_upgrade to create it
2018-01-18 18:21:13 684 [ERROR] Can't open and lock privilege tables: Table 'mysql.servers' doesn't exist
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'cond_instances' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_waits_current' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_waits_history' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_waits_history_long' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_waits_summary_by_host_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_waits_summary_by_instance' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_waits_summary_by_thread_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_waits_summary_by_user_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_waits_summary_by_account_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_waits_summary_global_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'file_instances' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'file_summary_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'file_summary_by_instance' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'host_cache' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'mutex_instances' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'objects_summary_global_by_type' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'performance_timers' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'rwlock_instances' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'setup_actors' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'setup_consumers' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'setup_instruments' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'setup_objects' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'setup_timers' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'table_io_waits_summary_by_index_usage' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'table_io_waits_summary_by_table' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'table_lock_waits_summary_by_table' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'threads' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_stages_current' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_stages_history' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_stages_history_long' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_stages_summary_by_thread_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_stages_summary_by_account_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_stages_summary_by_user_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_stages_summary_by_host_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_stages_summary_global_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_statements_current' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_statements_history' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_statements_history_long' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_statements_summary_by_thread_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_statements_summary_by_account_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_statements_summary_by_user_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_statements_summary_by_host_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_statements_summary_global_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'events_statements_summary_by_digest' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'users' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'accounts' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'hosts' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'socket_instances' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'socket_summary_by_instance' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'socket_summary_by_event_name' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'session_connect_attrs' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Native table 'performance_schema'.'session_account_connect_attrs' has the wrong structure
2018-01-18 18:21:13 684 [ERROR] Column count of mysql.db is wrong. Expected 22, found 20. The table is probably corrupted
2018-01-18 18:21:13 684 [ERROR] Cannot open mysql.event
2018-01-18 18:21:13 684 [ERROR] Event Scheduler: An error occurred when initializing system tables. Disabling the Event Scheduler.
2018-01-18 18:21:13 684 [Note] /usr/local/libexec/mysqld: ready for connections.
Version: '5.6.38' socket: '/tmp/mysql.sock' port: 3306 Source distribution
2018-01-18 18:21:41 684 [Warning] InnoDB: Cannot open table anyshop/categories from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2018-01-18 18:21:41 684 [Warning] InnoDB: Cannot open table anyshop/categories from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2018-01-18 18:21:45 684 [Warning] InnoDB: Cannot open table homepage/ban_log from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2018-01-18 18:21:45 684 [Warning] InnoDB: Cannot open table homepage/ban_log from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2018-01-18 18:21:47 684 [Warning] InnoDB: Cannot open table homepage/psc_log from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2018-01-18 18:21:47 684 [Warning] InnoDB: Cannot open table homepage/psc_log from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2018-01-18 18:23:32 684 [Warning] InnoDB: Cannot open table homepage/psc_log from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2018-01-18 18:26:01 684 [Warning] InnoDB: Cannot open table anyshop/categories from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2018-01-18 18:26:01 684 [Warning] InnoDB: Cannot open table anyshop/categories from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2018-01-18 18:26:04 684 [Warning] InnoDB: Cannot open table anyshop/shopitems from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2018-01-18 18:26:04 684 [Warning] InnoDB: Cannot open table anyshop/shopitems from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
2018-01-18 18:27:12 829f77c00 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:27:22 829f77c00 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:27:22 829f77c00 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:27:22 829f77c00 InnoDB: Error: Fetch of persistent statistics requested for table "homepage"."server_settings" but the required system tables mysql.innodb_table_stats and mysql.innodb_index_stats are not present or have unexpected structure. Using transient stats instead.
2018-01-18 18:27:32 80380b000 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:27:32 80380b000 InnoDB: Recalculation of persistent statistics requested for table "homepage"."server_settings" but the required persistent statistics storage is not present or is corrupted. Using transient stats instead.
2018-01-18 18:27:44 829f77c00 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:27:53 829f77c00 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:28:12 829f77c00 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:28:20 829f77c00 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:28:48 829f76000 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:28:48 829f76000 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:28:48 829f76000 InnoDB: Error: Fetch of persistent statistics requested for table "anyshop"."categories" but the required system tables mysql.innodb_table_stats and mysql.innodb_index_stats are not present or have unexpected structure. Using transient stats instead.
2018-01-18 18:28:56 829f76000 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:28:56 829f76000 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:28:56 829f76000 InnoDB: Error: Fetch of persistent statistics requested for table "anyshop"."shopitems" but the required system tables mysql.innodb_table_stats and mysql.innodb_index_stats are not present or have unexpected structure. Using transient stats instead.
2018-01-18 18:29:03 829f76000 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:29:03 829f76000 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:29:03 829f76000 InnoDB: Error: Fetch of persistent statistics requested for table "anyshop"."shops" but the required system tables mysql.innodb_table_stats and mysql.innodb_index_stats are not present or have unexpected structure. Using transient stats instead.
2018-01-18 18:29:06 80380b000 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:29:06 80380b000 InnoDB: Recalculation of persistent statistics requested for table "anyshop"."shopitems" but the required persistent statistics storage is not present or is corrupted. Using transient stats instead.
2018-01-18 18:29:16 80380b000 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:29:16 80380b000 InnoDB: Recalculation of persistent statistics requested for table "anyshop"."categories" but the required persistent statistics storage is not present or is corrupted. Using transient stats instead.
2018-01-18 18:32:14 829f76000 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:32:14 829f76000 InnoDB: Error: Fetch of persistent statistics requested for table "anyshop"."shopitems" but the required system tables mysql.innodb_table_stats and mysql.innodb_index_stats are not present or have unexpected structure. Using transient stats instead.
2018-01-18 18:32:14 829f76000 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:32:14 829f76000 InnoDB: Error: Fetch of persistent statistics requested for table "anyshop"."shops" but the required system tables mysql.innodb_table_stats and mysql.innodb_index_stats are not present or have unexpected structure. Using transient stats instead.
2018-01-18 18:32:14 829f76000 InnoDB: Error: Table "mysql"."innodb_table_stats" not found.
2018-01-18 18:32:14 829f76000 InnoDB: Error: Fetch of persistent statistics requested for table "anyshop"."categories" but the required system tables mysql.innodb_table_stats and mysql.innodb_index_stats are not present or have unexpected structure. Using transient stats instead.
can you please tell me what can i do to fix it?(sorry for my english hope you unterstand my problem)
-
Hello guys i am searching ingame itemshop script unbugged and without any problem!
i would like something like that:
send me private message!
-
-
Hello guys so can you please help me to find a solution on my problem?
so my problem:
i put the mysql table config etc..
but i have the following error:
ingame is the same problem.
Metin2 SlotActive-Deactive bug
in Community Support - Questions & Answers
Posted
Video
any ideas to fix it?
i already checked the following archives:
ui.py, uiinventory.py, uitastbar.py, uicharacter.py