Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "stdafx.h"
- #include "utils.h"
- #include "config.h"
- #include "desc.h"
- #include "desc_manager.h"
- #include "char_manager.h"
- #include "item.h"
- #include "item_manager.h"
- #include "mob_manager.h"
- #include "battle.h"
- #include "pvp.h"
- #include "skill.h"
- #include "start_position.h"
- #include "profiler.h"
- #include "cmd.h"
- #include "dungeon.h"
- #include "log.h"
- #include "unique_item.h"
- #include "priv_manager.h"
- #include "db.h"
- #include "vector.h"
- #include "marriage.h"
- #include "arena.h"
- #include "regen.h"
- #include "monarch.h"
- #include "exchange.h"
- #include "shop_manager.h"
- #include "castle.h"
- #include "dev_log.h"
- #include "ani.h"
- #include "BattleArena.h"
- #include "packet.h"
- #include "party.h"
- #include "affect.h"
- #include "guild.h"
- #include "guild_manager.h"
- #include "questmanager.h"
- #include "questlua.h"
- #include "threeway_war.h"
- #include "BlueDragon.h"
- #include "DragonLair.h"
- #define ENABLE_EFFECT_PENETRATE
- static DWORD __GetPartyExpNP(const DWORD level)
- {
- if (!level || level > PLAYER_EXP_TABLE_MAX)
- return 14000;
- return party_exp_distribute_table[level];
- }
- static int __GetExpLossPerc(const DWORD level)
- {
- if (!level || level > PLAYER_EXP_TABLE_MAX)
- return 1;
- return aiExpLossPercents[level];
- }
- DWORD AdjustExpByLevel(const LPCHARACTER ch, const DWORD exp)
- {
- if (PLAYER_MAX_LEVEL_CONST < ch->GetLevel())
- {
- double ret = 0.95;
- double factor = 0.1;
- for (ssize_t i=0 ; i < ch->GetLevel()-100 ; ++i)
- {
- if ( (i%10) == 0)
- factor /= 2.0;
- ret *= 1.0 - factor;
- }
- ret = ret * static_cast<double>(exp);
- if (ret < 1.0)
- return 1;
- return static_cast<DWORD>(ret);
- }
- return exp;
- }
- bool CHARACTER::CanBeginFight() const
- {
- if (!CanMove())
- return false;
- return m_pointsInstant.position == POS_STANDING && !IsDead() && !IsStun();
- }
- void CHARACTER::BeginFight(LPCHARACTER pkVictim)
- {
- SetVictim(pkVictim);
- SetPosition(POS_FIGHTING);
- SetNextStatePulse(1);
- }
- bool CHARACTER::CanFight() const
- {
- return m_pointsInstant.position >= POS_FIGHTING ? true : false;
- }
- void CHARACTER::CreateFly(BYTE bType, LPCHARACTER pkVictim)
- {
- TPacketGCCreateFly packFly;
- packFly.bHeader = HEADER_GC_CREATE_FLY;
- packFly.bType = bType;
- packFly.dwStartVID = GetVID();
- packFly.dwEndVID = pkVictim->GetVID();
- PacketAround(&packFly, sizeof(TPacketGCCreateFly));
- }
- void CHARACTER::DistributeSP(LPCHARACTER pkKiller, int iMethod)
- {
- if (pkKiller->GetSP() >= pkKiller->GetMaxSP())
- return;
- bool bAttacking = (get_dword_time() - GetLastAttackTime()) < 3000;
- bool bMoving = (get_dword_time() - GetLastMoveTime()) < 3000;
- if (iMethod == 1)
- {
- int num = number(0, 3);
- if (!num)
- {
- int iLvDelta = GetLevel() - pkKiller->GetLevel();
- int iAmount = 0;
- if (iLvDelta >= 5)
- iAmount = 10;
- else if (iLvDelta >= 0)
- iAmount = 6;
- else if (iLvDelta >= -3)
- iAmount = 2;
- if (iAmount != 0)
- {
- iAmount += (iAmount * pkKiller->GetPoint(POINT_SP_REGEN)) / 100;
- if (iAmount >= 11)
- CreateFly(FLY_SP_BIG, pkKiller);
- else if (iAmount >= 7)
- CreateFly(FLY_SP_MEDIUM, pkKiller);
- else
- CreateFly(FLY_SP_SMALL, pkKiller);
- pkKiller->PointChange(POINT_SP, iAmount);
- }
- }
- }
- else
- {
- if (pkKiller->GetJob() == JOB_SHAMAN || (pkKiller->GetJob() == JOB_SURA && pkKiller->GetSkillGroup() == 2))
- {
- int iAmount;
- if (bAttacking)
- iAmount = 2 + GetMaxSP() / 100;
- else if (bMoving)
- iAmount = 3 + GetMaxSP() * 2 / 100;
- else
- iAmount = 10 + GetMaxSP() * 3 / 100; // Ćň»ó˝Ă
- iAmount += (iAmount * pkKiller->GetPoint(POINT_SP_REGEN)) / 100;
- pkKiller->PointChange(POINT_SP, iAmount);
- }
- else
- {
- int iAmount;
- if (bAttacking)
- iAmount = 2 + pkKiller->GetMaxSP() / 200;
- else if (bMoving)
- iAmount = 2 + pkKiller->GetMaxSP() / 100;
- else
- {
- // Ćň»ó˝Ă
- if (pkKiller->GetHP() < pkKiller->GetMaxHP())
- iAmount = 2 + (pkKiller->GetMaxSP() / 100); // ÇÇ ´Ů ľČáŔ»¶§
- else
- iAmount = 9 + (pkKiller->GetMaxSP() / 100); // ±âş»
- }
- iAmount += (iAmount * pkKiller->GetPoint(POINT_SP_REGEN)) / 100;
- pkKiller->PointChange(POINT_SP, iAmount);
- }
- }
- }
- bool CHARACTER::Attack(LPCHARACTER pkVictim, BYTE bType)
- {
- if (test_server)
- sys_log(0, "[TEST_SERVER] Attack : %s type %d, MobBattleType %d", GetName(), bType, !GetMobBattleType() ? 0 : GetMobAttackRange());
- //PROF_UNIT puAttack("Attack");
- if (!CanMove())
- return false;
- // CASTLE
- if (IS_CASTLE_MAP(GetMapIndex()) && false == castle_can_attack(this, pkVictim))
- return false;
- // CASTLE
- // @fixme131
- if (!battle_is_attackable(this, pkVictim))
- return false;
- DWORD dwCurrentTime = get_dword_time();
- if (IsPC())
- {
- if (IS_SPEED_HACK(this, pkVictim, dwCurrentTime))
- return false;
- if (bType == 0 && dwCurrentTime < GetSkipComboAttackByTime())
- return false;
- }
- else
- {
- MonsterChat(MONSTER_CHAT_ATTACK);
- }
- pkVictim->SetSyncOwner(this);
- if (pkVictim->CanBeginFight())
- pkVictim->BeginFight(this);
- int iRet;
- if (bType == 0)
- {
- //
- // ŔĎąÝ °ř°Ý
- //
- switch (GetMobBattleType())
- {
- case BATTLE_TYPE_MELEE:
- case BATTLE_TYPE_POWER:
- case BATTLE_TYPE_TANKER:
- case BATTLE_TYPE_SUPER_POWER:
- case BATTLE_TYPE_SUPER_TANKER:
- iRet = battle_melee_attack(this, pkVictim);
- break;
- case BATTLE_TYPE_RANGE:
- FlyTarget(pkVictim->GetVID(), pkVictim->GetX(), pkVictim->GetY(), HEADER_CG_FLY_TARGETING);
- iRet = Shoot(0) ? BATTLE_DAMAGE : BATTLE_NONE;
- break;
- case BATTLE_TYPE_MAGIC:
- FlyTarget(pkVictim->GetVID(), pkVictim->GetX(), pkVictim->GetY(), HEADER_CG_FLY_TARGETING);
- iRet = Shoot(1) ? BATTLE_DAMAGE : BATTLE_NONE;
- break;
- default:
- sys_err("Unhandled battle type %d", GetMobBattleType());
- iRet = BATTLE_NONE;
- break;
- }
- }
- else
- {
- if (IsPC() == true)
- {
- if (dwCurrentTime - m_dwLastSkillTime > 1500)
- {
- sys_log(1, "HACK: Too long skill using term. Name(%s) PID(%u) delta(%u)",
- GetName(), GetPlayerID(), (dwCurrentTime - m_dwLastSkillTime));
- return false;
- }
- }
- sys_log(1, "Attack call ComputeSkill %d %s", bType, pkVictim?pkVictim->GetName():"");
- iRet = ComputeSkill(bType, pkVictim);
- }
- //if (test_server && IsPC())
- // sys_log(0, "%s Attack %s type %u ret %d", GetName(), pkVictim->GetName(), bType, iRet);
- if (iRet == BATTLE_DAMAGE || iRet == BATTLE_DEAD)
- {
- OnMove(true);
- pkVictim->OnMove();
- // only pc sets victim null. For npc, state machine will reset this.
- if (BATTLE_DEAD == iRet && IsPC())
- SetVictim(NULL);
- return true;
- }
- return false;
- }
- void CHARACTER::DeathPenalty(BYTE bTown)
- {
- sys_log(1, "DEATH_PERNALY_CHECK(%s) town(%d)", GetName(), bTown);
- Cube_close(this);
- #ifdef __SASH_SYSTEM__
- CloseSash();
- #endif
- if (CBattleArena::instance().IsBattleArenaMap(GetMapIndex()) == true)
- {
- return;
- }
- if (GetLevel() < 10)
- {
- sys_log(0, "NO_DEATH_PENALTY_LESS_LV10(%s)", GetName());
- ChatPacket(CHAT_TYPE_INFO, LC_TEXT("żë˝ĹŔÇ °ˇČŁ·Î °ćÇčġ°ˇ ¶łľîÁöÁö ľĘľŇ˝Ŕ´Ď´Ů."));
- return;
- }
- if (number(0, 2))
- {
- sys_log(0, "NO_DEATH_PENALTY_LUCK(%s)", GetName());
- ChatPacket(CHAT_TYPE_INFO, LC_TEXT("żë˝ĹŔÇ °ˇČŁ·Î °ćÇčġ°ˇ ¶łľîÁöÁö ľĘľŇ˝Ŕ´Ď´Ů."));
- return;
- }
- if (IS_SET(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY))
- {
- REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
- // NO_DEATH_PENALTY_BUG_FIX
- if (!bTown) // ±ąÁ¦ ąöŔüżˇĽ´Â Á¦ŔÚ¸® şÎČ°˝Ă¸¸ żë˝ĹŔÇ °ˇČŁ¸¦ »çżëÇŃ´Ů. (¸¶Ŕ» şą±Í˝Ă´Â °ćÇčġ ĆĐłÎĆĽ ľřŔ˝)
- {
- if (FindAffect(AFFECT_NO_DEATH_PENALTY))
- {
- sys_log(0, "NO_DEATH_PENALTY_AFFECT(%s)", GetName());
- ChatPacket(CHAT_TYPE_INFO, LC_TEXT("żë˝ĹŔÇ °ˇČŁ·Î °ćÇčġ°ˇ ¶łľîÁöÁö ľĘľŇ˝Ŕ´Ď´Ů."));
- RemoveAffect(AFFECT_NO_DEATH_PENALTY);
- return;
- }
- }
- // END_OF_NO_DEATH_PENALTY_BUG_FIX
- int iLoss = ((GetNextExp() * __GetExpLossPerc(GetLevel())) / 100);
- iLoss = MIN(800000, iLoss);
- if (bTown)
- iLoss = 0;
- if (IsEquipUniqueItem(UNIQUE_ITEM_TEARDROP_OF_GODNESS))
- iLoss /= 2;
- sys_log(0, "DEATH_PENALTY(%s) EXP_LOSS: %d percent %d%%", GetName(), iLoss, __GetExpLossPerc(GetLevel()));
- PointChange(POINT_EXP, -iLoss, true);
- }
- }
- bool CHARACTER::IsStun() const
- {
- if (IS_SET(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN))
- return true;
- return false;
- }
- EVENTFUNC(StunEvent)
- {
- char_event_info* info = dynamic_cast<char_event_info*>( event->info );
- if ( info == NULL )
- {
- sys_err( "StunEvent> <Factor> Null pointer" );
- return 0;
- }
- LPCHARACTER ch = info->ch;
- if (ch == NULL) { // <Factor>
- return 0;
- }
- ch->m_pkStunEvent = NULL;
- ch->Dead();
- return 0;
- }
- void CHARACTER::Stun()
- {
- if (IsStun())
- return;
- if (IsDead())
- return;
- if (!IsPC() && m_pkParty)
- {
- m_pkParty->SendMessage(this, PM_ATTACKED_BY, 0, 0);
- }
- sys_log(1, "%s: Stun %p", GetName(), this);
- PointChange(POINT_HP_RECOVERY, -GetPoint(POINT_HP_RECOVERY));
- PointChange(POINT_SP_RECOVERY, -GetPoint(POINT_SP_RECOVERY));
- CloseMyShop();
- event_cancel(&m_pkRecoveryEvent); // ȸşą ŔĚşĄĆ®¸¦ Á×ŔδŮ.
- TPacketGCStun pack;
- pack.header = HEADER_GC_STUN;
- pack.vid = m_vid;
- PacketAround(&pack, sizeof(pack));
- SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN);
- if (m_pkStunEvent)
- return;
- char_event_info* info = AllocEventInfo<char_event_info>();
- info->ch = this;
- m_pkStunEvent = event_create(StunEvent, info, PASSES_PER_SEC(3));
- }
- EVENTINFO(SCharDeadEventInfo)
- {
- bool isPC;
- uint32_t dwID;
- SCharDeadEventInfo()
- : isPC(0)
- , dwID(0)
- {
- }
- };
- EVENTFUNC(dead_event)
- {
- const SCharDeadEventInfo* info = dynamic_cast<SCharDeadEventInfo*>(event->info);
- if ( info == NULL )
- {
- sys_err( "dead_event> <Factor> Null pointer" );
- return 0;
- }
- LPCHARACTER ch = NULL;
- if (true == info->isPC)
- {
- ch = CHARACTER_MANAGER::instance().FindByPID( info->dwID );
- }
- else
- {
- ch = CHARACTER_MANAGER::instance().Find( info->dwID );
- }
- if (NULL == ch)
- {
- sys_err("DEAD_EVENT: cannot find char pointer with %s id(%d)", info->isPC ? "PC" : "MOB", info->dwID );
- return 0;
- }
- ch->m_pkDeadEvent = NULL;
- if (ch->GetDesc())
- {
- ch->GetDesc()->SetPhase(PHASE_GAME);
- ch->SetPosition(POS_STANDING);
- PIXEL_POSITION pos;
- if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(ch->GetMapIndex(), ch->GetEmpire(), pos))
- ch->WarpSet(pos.x, pos.y);
- else
- {
- sys_err("cannot find spawn position (name %s)", ch->GetName());
- ch->WarpSet(EMPIRE_START_X(ch->GetEmpire()), EMPIRE_START_Y(ch->GetEmpire()));
- }
- ch->PointChange(POINT_HP, (ch->GetMaxHP() / 2) - ch->GetHP(), true);
- ch->DeathPenalty(0);
- ch->StartRecoveryEvent();
- ch->ChatPacket(CHAT_TYPE_COMMAND, "CloseRestartWindow");
- }
- else
- {
- if (ch->IsMonster() == true)
- {
- if (ch->IsRevive() == false && ch->HasReviverInParty() == true)
- {
- ch->SetPosition(POS_STANDING);
- ch->SetHP(ch->GetMaxHP());
- ch->ViewReencode();
- ch->SetAggressive();
- ch->SetRevive(true);
- return 0;
- }
- }
- M2_DESTROY_CHARACTER(ch);
- }
- return 0;
- }
- bool CHARACTER::IsDead() const
- {
- if (m_pointsInstant.position == POS_DEAD)
- return true;
- return false;
- }
- #define GetGoldMultipler() (distribution_test_server ? 3 : 1)
- void CHARACTER::RewardGold(LPCHARACTER pkAttacker)
- {
- // ADD_PREMIUM
- bool isAutoLoot =
- (pkAttacker->GetPremiumRemainSeconds(PREMIUM_AUTOLOOT) > 0 ||
- pkAttacker->IsEquipUniqueGroup(UNIQUE_GROUP_AUTOLOOT))
- ? true : false; // Á¦3ŔÇ ĽŐ
- // END_OF_ADD_PREMIUM
- PIXEL_POSITION pos;
- if (!isAutoLoot)
- if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), GetX(), GetY(), pos))
- return;
- int iTotalGold = 0;
- //
- // --------- µ· µĺ·Ó Č®·ü °č»ę ----------
- //
- int iGoldPercent = MobRankStats[GetMobRank()].iGoldPercent;
- if (pkAttacker->IsPC())
- iGoldPercent = iGoldPercent * (100 + CPrivManager::instance().GetPriv(pkAttacker, PRIV_GOLD_DROP)) / 100;
- if (pkAttacker->GetPoint(POINT_MALL_GOLDBONUS))
- iGoldPercent += (iGoldPercent * pkAttacker->GetPoint(POINT_MALL_GOLDBONUS) / 100);
- iGoldPercent = iGoldPercent * CHARACTER_MANAGER::instance().GetMobGoldDropRate(pkAttacker) / 100;
- // ADD_PREMIUM
- if (pkAttacker->GetPremiumRemainSeconds(PREMIUM_GOLD) > 0 ||
- pkAttacker->IsEquipUniqueGroup(UNIQUE_GROUP_LUCKY_GOLD))
- iGoldPercent += iGoldPercent;
- // END_OF_ADD_PREMIUM
- if (iGoldPercent > 100)
- iGoldPercent = 100;
- int iPercent;
- if (GetMobRank() >= MOB_RANK_BOSS)
- iPercent = ((iGoldPercent * PERCENT_LVDELTA_BOSS(pkAttacker->GetLevel(), GetLevel())) / 100);
- else
- iPercent = ((iGoldPercent * PERCENT_LVDELTA(pkAttacker->GetLevel(), GetLevel())) / 100);
- //int iPercent = CALCULATE_VALUE_LVDELTA(pkAttacker->GetLevel(), GetLevel(), iGoldPercent);
- if (number(1, 100) > iPercent)
- return;
- int iGoldMultipler = GetGoldMultipler();
- if (1 == number(1, 50000)) // 1/50000 Č®·ü·Î µ·ŔĚ 10ąč
- iGoldMultipler *= 10;
- else if (1 == number(1, 10000)) // 1/10000 Č®·ü·Î µ·ŔĚ 5ąč
- iGoldMultipler *= 5;
- // °łŔÎ Ŕűżë
- if (pkAttacker->GetPoint(POINT_GOLD_DOUBLE_BONUS))
- if (number(1, 100) <= pkAttacker->GetPoint(POINT_GOLD_DOUBLE_BONUS))
- iGoldMultipler *= 2;
- //
- // --------- µ· µĺ·Ó ąčĽö °áÁ¤ ----------
- //
- if (test_server)
- pkAttacker->ChatPacket(CHAT_TYPE_PARTY, "gold_mul %d rate %d", iGoldMultipler, CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker));
- //
- // --------- ˝ÇÁ¦ µĺ·Ó Ăł¸® -------------
- //
- LPITEM item;
- int iGold10DropPct = 100;
- iGold10DropPct = (iGold10DropPct * 100) / (100 + CPrivManager::instance().GetPriv(pkAttacker, PRIV_GOLD10_DROP));
- // MOB_RANK°ˇ BOSSş¸´Ů łôŔ¸¸é ą«Á¶°Ç µ·ĆřĹş
- if (GetMobRank() >= MOB_RANK_BOSS && !IsStone() && GetMobTable().dwGoldMax != 0)
- {
- if (1 == number(1, iGold10DropPct))
- iGoldMultipler *= 10; // 1% Č®·ü·Î µ· 10ąč
- int iSplitCount = number(25, 35);
- for (int i = 0; i < iSplitCount; ++i)
- {
- int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax) / iSplitCount;
- if (test_server)
- sys_log(0, "iGold %d", iGold);
- iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker) / 100;
- iGold *= iGoldMultipler;
- if (iGold == 0)
- {
- continue ;
- }
- if (test_server)
- {
- sys_log(0, "Drop Moeny MobGoldAmountRate %d %d", CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker), iGoldMultipler);
- sys_log(0, "Drop Money gold %d GoldMin %d GoldMax %d", iGold, GetMobTable().dwGoldMax, GetMobTable().dwGoldMax);
- }
- // NOTE: µ· ĆřĹşŔş Á¦ 3ŔÇ ĽŐ Ăł¸®¸¦ ÇĎÁö ľĘŔ˝
- if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold)))
- {
- pos.x = GetX() + ((number(-14, 14) + number(-14, 14)) * 23);
- pos.y = GetY() + ((number(-14, 14) + number(-14, 14)) * 23);
- item->AddToGround(GetMapIndex(), pos);
- item->StartDestroyEvent();
- iTotalGold += iGold; // Total gold
- }
- }
- }
- // 1% Č®·ü·Î µ·Ŕ» 10°ł ¶łľî ¶ß¸°´Ů. (10ąč µĺ·ÓŔÓ)
- else if (1 == number(1, iGold10DropPct))
- {
- //
- // µ· ĆřĹş˝Ä µĺ·Ó
- //
- for (int i = 0; i < 10; ++i)
- {
- int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
- iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker) / 100;
- iGold *= iGoldMultipler;
- if (iGold == 0)
- {
- continue;
- }
- // NOTE: µ· ĆřĹşŔş Á¦ 3ŔÇ ĽŐ Ăł¸®¸¦ ÇĎÁö ľĘŔ˝
- if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold)))
- {
- pos.x = GetX() + (number(-7, 7) * 20);
- pos.y = GetY() + (number(-7, 7) * 20);
- item->AddToGround(GetMapIndex(), pos);
- item->StartDestroyEvent();
- iTotalGold += iGold; // Total gold
- }
- }
- }
- else
- {
- //
- // ŔĎąÝŔűŔÎ ąć˝ÄŔÇ µ· µĺ·Ó
- //
- int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
- iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker) / 100;
- iGold *= iGoldMultipler;
- int iSplitCount;
- if (iGold >= 3)
- iSplitCount = number(1, 3);
- else if (GetMobRank() >= MOB_RANK_BOSS)
- {
- iSplitCount = number(3, 10);
- if ((iGold / iSplitCount) == 0)
- iSplitCount = 1;
- }
- else
- iSplitCount = 1;
- if (iGold != 0)
- {
- iTotalGold += iGold; // Total gold
- for (int i = 0; i < iSplitCount; ++i)
- {
- if (isAutoLoot)
- {
- pkAttacker->GiveGold(iGold / iSplitCount);
- }
- else if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold / iSplitCount)))
- {
- pos.x = GetX() + (number(-7, 7) * 20);
- pos.y = GetY() + (number(-7, 7) * 20);
- item->AddToGround(GetMapIndex(), pos);
- item->StartDestroyEvent();
- }
- }
- }
- }
- DBManager::instance().SendMoneyLog(MONEY_LOG_MONSTER, GetRaceNum(), iTotalGold);
- }
- void CHARACTER::Reward(bool bItemDrop)
- {
- if (GetRaceNum() == 5001) // żÖ±¸´Â µ·Ŕ» ą«Á¶°Ç µĺ·Ó
- {
- PIXEL_POSITION pos;
- if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), GetX(), GetY(), pos))
- return;
- LPITEM item;
- int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
- iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(NULL) / 100;
- iGold *= GetGoldMultipler();
- int iSplitCount = number(25, 35);
- sys_log(0, "WAEGU Dead gold %d split %d", iGold, iSplitCount);
- for (int i = 1; i <= iSplitCount; ++i)
- {
- if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold / iSplitCount)))
- {
- if (i != 0)
- {
- pos.x = number(-7, 7) * 20;
- pos.y = number(-7, 7) * 20;
- pos.x += GetX();
- pos.y += GetY();
- }
- item->AddToGround(GetMapIndex(), pos);
- item->StartDestroyEvent();
- }
- }
- return;
- }
- //PROF_UNIT puReward("Reward");
- LPCHARACTER pkAttacker = DistributeExp();
- if (!pkAttacker)
- return;
- //PROF_UNIT pu1("r1");
- if (pkAttacker->IsPC())
- {
- if ((GetLevel() - pkAttacker->GetLevel()) >= -10)
- {
- if (pkAttacker->GetRealAlignment() < 0)
- {
- if (pkAttacker->IsEquipUniqueItem(UNIQUE_ITEM_FASTER_ALIGNMENT_UP_BY_KILL))
- pkAttacker->UpdateAlignment(14);
- else
- pkAttacker->UpdateAlignment(7);
- }
- else
- pkAttacker->UpdateAlignment(2);
- }
- pkAttacker->SetQuestNPCID(GetVID());
- quest::CQuestManager::instance().Kill(pkAttacker->GetPlayerID(), GetRaceNum());
- CHARACTER_MANAGER::instance().KillLog(GetRaceNum());
- if (!number(0, 9))
- {
- if (pkAttacker->GetPoint(POINT_KILL_HP_RECOVERY))
- {
- int iHP = pkAttacker->GetMaxHP() * pkAttacker->GetPoint(POINT_KILL_HP_RECOVERY) / 100;
- pkAttacker->PointChange(POINT_HP, iHP);
- CreateFly(FLY_HP_SMALL, pkAttacker);
- }
- if (pkAttacker->GetPoint(POINT_KILL_SP_RECOVER))
- {
- int iSP = pkAttacker->GetMaxSP() * pkAttacker->GetPoint(POINT_KILL_SP_RECOVER) / 100;
- pkAttacker->PointChange(POINT_SP, iSP);
- CreateFly(FLY_SP_SMALL, pkAttacker);
- }
- }
- }
- //pu1.Pop();
- if (!bItemDrop)
- return;
- PIXEL_POSITION pos = GetXYZ();
- if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), pos.x, pos.y, pos))
- return;
- //
- // µ· µĺ·Ó
- //
- //PROF_UNIT pu2("r2");
- if (test_server)
- sys_log(0, "Drop money : Attacker %s", pkAttacker->GetName());
- RewardGold(pkAttacker);
- //pu2.Pop();
- //
- // ľĆŔĚĹŰ µĺ·Ó
- //
- //PROF_UNIT pu3("r3");
- LPITEM item;
- static std::vector<LPITEM> s_vec_item;
- s_vec_item.clear();
- if (ITEM_MANAGER::instance().CreateDropItem(this, pkAttacker, s_vec_item))
- {
- if (s_vec_item.size() == 0);
- else if (s_vec_item.size() == 1)
- {
- item = s_vec_item[0];
- item->AddToGround(GetMapIndex(), pos);
- if (CBattleArena::instance().IsBattleArenaMap(pkAttacker->GetMapIndex()) == false)
- {
- #ifdef ENABLE_DICE_SYSTEM
- if (pkAttacker->GetParty())
- {
- FPartyDropDiceRoll f(item, pkAttacker);
- f.Process(this);
- }
- else
- item->SetOwnership(pkAttacker);
- #else
- item->SetOwnership(pkAttacker);
- #endif
- }
- item->StartDestroyEvent();
- pos.x = number(-7, 7) * 20;
- pos.y = number(-7, 7) * 20;
- pos.x += GetX();
- pos.y += GetY();
- sys_log(0, "DROP_ITEM: %s %d %d from %s", item->GetName(), pos.x, pos.y, GetName());
- }
- else
- {
- int iItemIdx = s_vec_item.size() - 1;
- std::priority_queue<std::pair<int, LPCHARACTER> > pq;
- int total_dam = 0;
- for (TDamageMap::iterator it = m_map_kDamage.begin(); it != m_map_kDamage.end(); ++it)
- {
- int iDamage = it->second.iTotalDamage;
- if (iDamage > 0)
- {
- LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(it->first);
- if (ch)
- {
- pq.push(std::make_pair(iDamage, ch));
- total_dam += iDamage;
- }
- }
- }
- std::vector<LPCHARACTER> v;
- while (!pq.empty() && pq.top().first * 10 >= total_dam)
- {
- v.push_back(pq.top().second);
- pq.pop();
- }
- if (v.empty())
- {
- // µĄąĚÁö¸¦ ĆŻş°Č÷ ¸ąŔĚ ÁŘ »ç¶÷ŔĚ ľřŔ¸´Ď ĽŇŔŻ±Ç ľřŔ˝
- while (iItemIdx >= 0)
- {
- item = s_vec_item[iItemIdx--];
- if (!item)
- {
- sys_err("item null in vector idx %d", iItemIdx + 1);
- continue;
- }
- item->AddToGround(GetMapIndex(), pos);
- // 10% ŔĚÇĎ µĄąĚÁö ÁŘ »ç¶÷ł˘¸®´Â ĽŇŔŻ±ÇľřŔ˝
- //item->SetOwnership(pkAttacker);
- item->StartDestroyEvent();
- pos.x = number(-7, 7) * 20;
- pos.y = number(-7, 7) * 20;
- pos.x += GetX();
- pos.y += GetY();
- sys_log(0, "DROP_ITEM: %s %d %d by %s", item->GetName(), pos.x, pos.y, GetName());
- }
- }
- else
- {
- // µĄąĚÁö ¸ąŔĚ ÁŘ »ç¶÷µé ł˘¸®¸¸ ĽŇŔŻ±Ç łŞ´˛°ˇÁü
- std::vector<LPCHARACTER>::iterator it = v.begin();
- while (iItemIdx >= 0)
- {
- item = s_vec_item[iItemIdx--];
- if (!item)
- {
- sys_err("item null in vector idx %d", iItemIdx + 1);
- continue;
- }
- item->AddToGround(GetMapIndex(), pos);
- LPCHARACTER ch = *it;
- if (ch->GetParty())
- ch = ch->GetParty()->GetNextOwnership(ch, GetX(), GetY());
- ++it;
- if (it == v.end())
- it = v.begin();
- if (CBattleArena::instance().IsBattleArenaMap(ch->GetMapIndex()) == false)
- {
- #ifdef ENABLE_DICE_SYSTEM
- if (ch->GetParty())
- {
- FPartyDropDiceRoll f(item, ch);
- f.Process(this);
- }
- else
- item->SetOwnership(ch);
- #else
- item->SetOwnership(ch);
- #endif
- }
- item->StartDestroyEvent();
- pos.x = number(-7, 7) * 20;
- pos.y = number(-7, 7) * 20;
- pos.x += GetX();
- pos.y += GetY();
- sys_log(0, "DROP_ITEM: %s %d %d by %s", item->GetName(), pos.x, pos.y, GetName());
- }
- }
- }
- }
- m_map_kDamage.clear();
- }
- struct TItemDropPenalty
- {
- int iInventoryPct; // Range: 1 ~ 1000
- int iInventoryQty; // Range: --
- int iEquipmentPct; // Range: 1 ~ 100
- int iEquipmentQty; // Range: --
- };
- TItemDropPenalty aItemDropPenalty_kor[9] =
- {
- { 0, 0, 0, 0 }, // Ľ±żŐ
- { 0, 0, 0, 0 }, // żµżő
- { 0, 0, 0, 0 }, // ĽşŔÚ
- { 0, 0, 0, 0 }, // ÁöŔÎ
- { 0, 0, 0, 0 }, // ľçąÎ
- { 25, 1, 5, 1 }, // ł¶ŔÎ
- { 50, 2, 10, 1 }, // ľÇŔÎ
- { 75, 4, 15, 1 }, // ¸¶µÎ
- { 100, 8, 20, 1 }, // ĆĐżŐ
- };
- void CHARACTER::ItemDropPenalty(LPCHARACTER pkKiller)
- {
- // °łŔλóÁˇŔ» ż¬ »óĹÂżˇĽ´Â ľĆŔĚĹŰŔ» µĺ·ÓÇĎÁö ľĘ´Â´Ů.
- if (GetMyShop())
- return;
- if (GetLevel() < 50)
- return;
- if (CBattleArena::instance().IsBattleArenaMap(GetMapIndex()) == true)
- {
- return;
- }
- struct TItemDropPenalty * table = &aItemDropPenalty_kor[0];
- if (GetLevel() < 10)
- return;
- int iAlignIndex;
- if (GetRealAlignment() >= 120000)
- iAlignIndex = 0;
- else if (GetRealAlignment() >= 80000)
- iAlignIndex = 1;
- else if (GetRealAlignment() >= 40000)
- iAlignIndex = 2;
- else if (GetRealAlignment() >= 10000)
- iAlignIndex = 3;
- else if (GetRealAlignment() >= 0)
- iAlignIndex = 4;
- else if (GetRealAlignment() > -40000)
- iAlignIndex = 5;
- else if (GetRealAlignment() > -80000)
- iAlignIndex = 6;
- else if (GetRealAlignment() > -120000)
- iAlignIndex = 7;
- else
- iAlignIndex = 8;
- std::vector<std::pair<LPITEM, int> > vec_item;
- LPITEM pkItem;
- int i;
- bool isDropAllEquipments = false;
- TItemDropPenalty & r = table[iAlignIndex];
- sys_log(0, "%s align %d inven_pct %d equip_pct %d", GetName(), iAlignIndex, r.iInventoryPct, r.iEquipmentPct);
- bool bDropInventory = r.iInventoryPct >= number(1, 1000);
- bool bDropEquipment = r.iEquipmentPct >= number(1, 100);
- bool bDropAntiDropUniqueItem = false;
- if ((bDropInventory || bDropEquipment) && IsEquipUniqueItem(UNIQUE_ITEM_SKIP_ITEM_DROP_PENALTY))
- {
- bDropInventory = false;
- bDropEquipment = false;
- bDropAntiDropUniqueItem = true;
- }
- if (bDropInventory) // Drop Inventory
- {
- std::vector<BYTE> vec_bSlots;
- for (i = 0; i < INVENTORY_MAX_NUM; ++i)
- if (GetInventoryItem(i))
- vec_bSlots.push_back(i);
- if (!vec_bSlots.empty())
- {
- random_shuffle(vec_bSlots.begin(), vec_bSlots.end());
- int iQty = MIN(vec_bSlots.size(), r.iInventoryQty);
- if (iQty)
- iQty = number(1, iQty);
- for (i = 0; i < iQty; ++i)
- {
- pkItem = GetInventoryItem(vec_bSlots[i]);
- if (IS_SET(pkItem->GetAntiFlag(), ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_PKDROP))
- continue;
- SyncQuickslot(QUICKSLOT_TYPE_ITEM, vec_bSlots[i], 255);
- vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), INVENTORY));
- }
- }
- else if (iAlignIndex == 8)
- isDropAllEquipments = true;
- }
- if (bDropEquipment) // Drop Equipment
- {
- std::vector<BYTE> vec_bSlots;
- for (i = 0; i < WEAR_MAX_NUM; ++i)
- if (GetWear(i))
- vec_bSlots.push_back(i);
- if (!vec_bSlots.empty())
- {
- random_shuffle(vec_bSlots.begin(), vec_bSlots.end());
- int iQty;
- if (isDropAllEquipments)
- iQty = vec_bSlots.size();
- else
- iQty = MIN(vec_bSlots.size(), number(1, r.iEquipmentQty));
- if (iQty)
- iQty = number(1, iQty);
- for (i = 0; i < iQty; ++i)
- {
- pkItem = GetWear(vec_bSlots[i]);
- if (IS_SET(pkItem->GetAntiFlag(), ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_PKDROP))
- continue;
- SyncQuickslot(QUICKSLOT_TYPE_ITEM, vec_bSlots[i], 255);
- vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), EQUIPMENT));
- }
- }
- }
- if (bDropAntiDropUniqueItem)
- {
- LPITEM pkItem;
- pkItem = GetWear(WEAR_UNIQUE1);
- if (pkItem && pkItem->GetVnum() == UNIQUE_ITEM_SKIP_ITEM_DROP_PENALTY)
- {
- SyncQuickslot(QUICKSLOT_TYPE_ITEM, WEAR_UNIQUE1, 255);
- vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), EQUIPMENT));
- }
- pkItem = GetWear(WEAR_UNIQUE2);
- if (pkItem && pkItem->GetVnum() == UNIQUE_ITEM_SKIP_ITEM_DROP_PENALTY)
- {
- SyncQuickslot(QUICKSLOT_TYPE_ITEM, WEAR_UNIQUE2, 255);
- vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), EQUIPMENT));
- }
- }
- {
- PIXEL_POSITION pos;
- pos.x = GetX();
- pos.y = GetY();
- unsigned int i;
- for (i = 0; i < vec_item.size(); ++i)
- {
- LPITEM item = vec_item[i].first;
- int window = vec_item[i].second;
- item->AddToGround(GetMapIndex(), pos);
- item->StartDestroyEvent();
- sys_log(0, "DROP_ITEM_PK: %s %d %d from %s", item->GetName(), pos.x, pos.y, GetName());
- LogManager::instance().ItemLog(this, item, "DEAD_DROP", (window == INVENTORY) ? "INVENTORY" : ((window == EQUIPMENT) ? "EQUIPMENT" : ""));
- pos.x = GetX() + number(-7, 7) * 20;
- pos.y = GetY() + number(-7, 7) * 20;
- }
- }
- }
- class FPartyAlignmentCompute
- {
- public:
- FPartyAlignmentCompute(int iAmount, int x, int y)
- {
- m_iAmount = iAmount;
- m_iCount = 0;
- m_iStep = 0;
- m_iKillerX = x;
- m_iKillerY = y;
- }
- void operator () (LPCHARACTER pkChr)
- {
- if (DISTANCE_APPROX(pkChr->GetX() - m_iKillerX, pkChr->GetY() - m_iKillerY) < PARTY_DEFAULT_RANGE)
- {
- if (m_iStep == 0)
- {
- ++m_iCount;
- }
- else
- {
- pkChr->UpdateAlignment(m_iAmount / m_iCount);
- }
- }
- }
- int m_iAmount;
- int m_iCount;
- int m_iStep;
- int m_iKillerX;
- int m_iKillerY;
- };
- void CHARACTER::Dead(LPCHARACTER pkKiller, bool bImmediateDead)
- {
- if (IsDead())
- return;
- {
- if (IsHorseRiding())
- {
- StopRiding();
- }
- else if (GetMountVnum())
- {
- RemoveAffect(AFFECT_MOUNT_BONUS);
- m_dwMountVnum = 0;
- UnEquipSpecialRideUniqueItem();
- UpdatePacket();
- }
- }
- if (!pkKiller && m_dwKillerPID)
- pkKiller = CHARACTER_MANAGER::instance().FindByPID(m_dwKillerPID);
- m_dwKillerPID = 0; // ąÝµĺ˝Ă ĂʱâČ ÇŘľßÇÔ DO NOT DELETE THIS LINE UNLESS YOU ARE 1000000% SURE
- bool isAgreedPVP = false;
- bool isUnderGuildWar = false;
- bool isDuel = false;
- bool isForked = false;
- if (pkKiller && pkKiller->IsPC())
- {
- if (pkKiller->m_pkChrTarget == this)
- pkKiller->SetTarget(NULL);
- if (!IsPC() && pkKiller->GetDungeon())
- pkKiller->GetDungeon()->IncKillCount(pkKiller, this);
- isAgreedPVP = CPVPManager::instance().Dead(this, pkKiller->GetPlayerID());
- isDuel = CArenaManager::instance().OnDead(pkKiller, this);
- if (IsPC())
- {
- CGuild * g1 = GetGuild();
- CGuild * g2 = pkKiller->GetGuild();
- if (g1 && g2)
- if (g1->UnderWar(g2->GetID()))
- isUnderGuildWar = true;
- pkKiller->SetQuestNPCID(GetVID());
- quest::CQuestManager::instance().Kill(pkKiller->GetPlayerID(), quest::QUEST_NO_NPC);
- CGuildManager::instance().Kill(pkKiller, this);
- }
- }
- #ifdef ENABLE_QUEST_DIE_EVENT
- if (IsPC())
- {
- if (pkKiller)
- SetQuestNPCID(pkKiller->GetVID());
- // quest::CQuestManager::instance().Die(GetPlayerID(), quest::QUEST_NO_NPC);
- quest::CQuestManager::instance().Die(GetPlayerID(), (pkKiller)?pkKiller->GetRaceNum():quest::QUEST_NO_NPC);
- }
- #endif
- //CHECK_FORKEDROAD_WAR
- if (IsPC())
- {
- if (CThreeWayWar::instance().IsThreeWayWarMapIndex(GetMapIndex()))
- isForked = true;
- }
- //END_CHECK_FORKEDROAD_WAR
- if (pkKiller &&
- !isAgreedPVP &&
- !isUnderGuildWar &&
- IsPC() &&
- !isDuel &&
- !isForked &&
- !IS_CASTLE_MAP(GetMapIndex()))
- {
- if (GetGMLevel() == GM_PLAYER || test_server)
- {
- ItemDropPenalty(pkKiller);
- }
- }
- // CASTLE_SIEGE
- if (IS_CASTLE_MAP(GetMapIndex()))
- {
- if (CASTLE_FROG_VNUM == GetRaceNum())
- castle_frog_die(this, pkKiller);
- else if (castle_is_guard_vnum(GetRaceNum()))
- castle_guard_die(this, pkKiller);
- else if (castle_is_tower_vnum(GetRaceNum()))
- castle_tower_die(this, pkKiller);
- }
- // CASTLE_SIEGE
- if (true == isForked)
- {
- CThreeWayWar::instance().onDead( this, pkKiller );
- }
- SetPosition(POS_DEAD);
- ClearAffect(true);
- if (pkKiller && IsPC())
- {
- if (!pkKiller->IsPC())
- {
- if (!isForked)
- {
- sys_log(1, "DEAD: %s %p WITH PENALTY", GetName(), this);
- SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
- LogManager::instance().CharLog(this, pkKiller->GetRaceNum(), "DEAD_BY_NPC", pkKiller->GetName());
- }
- }
- else
- {
- sys_log(1, "DEAD_BY_PC: %s %p KILLER %s %p", GetName(), this, pkKiller->GetName(), get_pointer(pkKiller));
- REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
- if (GetEmpire() != pkKiller->GetEmpire())
- {
- int iEP = MIN(GetPoint(POINT_EMPIRE_POINT), pkKiller->GetPoint(POINT_EMPIRE_POINT));
- PointChange(POINT_EMPIRE_POINT, -(iEP / 10));
- pkKiller->PointChange(POINT_EMPIRE_POINT, iEP / 5);
- if (GetPoint(POINT_EMPIRE_POINT) < 10)
- {
- // TODO : ŔÔ±¸·Î łŻ¸®´Â Äڵ带 łÖľîľß ÇŃ´Ů.
- }
- char buf[256];
- snprintf(buf, sizeof(buf),
- "%d %d %d %s %d %d %d %s",
- GetEmpire(), GetAlignment(), GetPKMode(), GetName(),
- pkKiller->GetEmpire(), pkKiller->GetAlignment(), pkKiller->GetPKMode(), pkKiller->GetName());
- LogManager::instance().CharLog(this, pkKiller->GetPlayerID(), "DEAD_BY_PC", buf);
- }
- else
- {
- if (!isAgreedPVP && !isUnderGuildWar && !IsKillerMode() && GetAlignment() >= 0 && !isDuel && !isForked)
- {
- int iNoPenaltyProb = 0;
- if (pkKiller->GetAlignment() >= 0) // 1/3 percent down
- iNoPenaltyProb = 33;
- else // 4/5 percent down
- iNoPenaltyProb = 20;
- if (number(1, 100) < iNoPenaltyProb)
- pkKiller->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("żë˝ĹŔÇ ş¸ČŁ·Î ľĆŔĚĹŰŔĚ ¶łľîÁöÁö ľĘľŇ˝Ŕ´Ď´Ů."));
- else
- {
- if (pkKiller->GetParty())
- {
- FPartyAlignmentCompute f(-20000, pkKiller->GetX(), pkKiller->GetY());
- pkKiller->GetParty()->ForEachOnlineMember(f);
- if (f.m_iCount == 0)
- pkKiller->UpdateAlignment(-20000);
- else
- {
- sys_log(0, "ALIGNMENT PARTY count %d amount %d", f.m_iCount, f.m_iAmount);
- f.m_iStep = 1;
- pkKiller->GetParty()->ForEachOnlineMember(f);
- }
- }
- else
- pkKiller->UpdateAlignment(-20000);
- }
- }
- char buf[256];
- snprintf(buf, sizeof(buf),
- "%d %d %d %s %d %d %d %s",
- GetEmpire(), GetAlignment(), GetPKMode(), GetName(),
- pkKiller->GetEmpire(), pkKiller->GetAlignment(), pkKiller->GetPKMode(), pkKiller->GetName());
- LogManager::instance().CharLog(this, pkKiller->GetPlayerID(), "DEAD_BY_PC", buf);
- }
- }
- }
- else
- {
- sys_log(1, "DEAD: %s %p", GetName(), this);
- REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
- }
- ClearSync();
- //sys_log(1, "stun cancel %s[%d]", GetName(), (DWORD)GetVID());
- event_cancel(&m_pkStunEvent); // ±âŔý ŔĚşĄĆ®´Â Á×ŔδŮ.
- if (IsPC())
- {
- m_dwLastDeadTime = get_dword_time();
- SetKillerMode(false);
- GetDesc()->SetPhase(PHASE_DEAD);
- }
- else
- {
- // °ˇµĺżˇ°Ô °ř°ÝąŢŔş ¸ó˝şĹÍ´Â ş¸»óŔĚ ľřľîľß ÇŃ´Ů.
- if (!IS_SET(m_pointsInstant.instant_flag, INSTANT_FLAG_NO_REWARD))
- {
- if (!(pkKiller && pkKiller->IsPC() && pkKiller->GetGuild() && pkKiller->GetGuild()->UnderAnyWar(GUILD_WAR_TYPE_FIELD)))
- {
- // şÎČ°ÇĎ´Â ¸ó˝şĹÍ´Â ş¸»óŔ» ÁÖÁö ľĘ´Â´Ů.
- if (GetMobTable().dwResurrectionVnum)
- {
- // DUNGEON_MONSTER_REBIRTH_BUG_FIX
- LPCHARACTER chResurrect = CHARACTER_MANAGER::instance().SpawnMob(GetMobTable().dwResurrectionVnum, GetMapIndex(), GetX(), GetY(), GetZ(), true, (int) GetRotation());
- if (GetDungeon() && chResurrect)
- {
- chResurrect->SetDungeon(GetDungeon());
- }
- // END_OF_DUNGEON_MONSTER_REBIRTH_BUG_FIX
- Reward(false);
- }
- else if (IsRevive() == true)
- {
- Reward(false);
- }
- else
- {
- Reward(true); // Drops gold, item, etc..
- }
- }
- else
- {
- if (pkKiller->m_dwUnderGuildWarInfoMessageTime < get_dword_time())
- {
- pkKiller->m_dwUnderGuildWarInfoMessageTime = get_dword_time() + 60000;
- pkKiller->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<±ćµĺ> ±ćµĺŔüÁßżˇ´Â »çłÉżˇ µű¸Ą ŔĚŔÍŔĚ ľř˝Ŕ´Ď´Ů."));
- }
- }
- }
- }
- // BOSS_KILL_LOG
- if (GetMobRank() >= MOB_RANK_BOSS && pkKiller && pkKiller->IsPC())
- {
- char buf[51];
- snprintf(buf, sizeof(buf), "%d %ld", g_bChannel, pkKiller->GetMapIndex());
- if (IsStone())
- LogManager::instance().CharLog(pkKiller, GetRaceNum(), "STONE_KILL", buf);
- else
- LogManager::instance().CharLog(pkKiller, GetRaceNum(), "BOSS_KILL", buf);
- }
- // END_OF_BOSS_KILL_LOG
- TPacketGCDead pack;
- pack.header = HEADER_GC_DEAD;
- pack.vid = m_vid;
- PacketAround(&pack, sizeof(pack));
- REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN);
- // ÇĂ·ąŔĚľî Äł¸ŻĹÍŔ̸é
- if (GetDesc() != NULL) {
- //
- // Ŭ¶óŔĚľđĆ®żˇ żˇĆĺĆ® ĆĐŶŔ» ´Ů˝Ă ş¸ł˝´Ů.
- //
- itertype(m_list_pkAffect) it = m_list_pkAffect.begin();
- while (it != m_list_pkAffect.end())
- SendAffectAddPacket(GetDesc(), *it++);
- }
- //
- // Dead ŔĚşĄĆ® »ýĽş,
- //
- // Dead ŔĚşĄĆ®żˇĽ´Â ¸ó˝şĹÍŔÇ °ćżě ¸îĂĘ ČÄżˇ Destroy µÇµµ·Ď ÇŘÁÖ¸ç,
- // PCŔÇ °ćżě 3şĐ ŔÖ´Ů°ˇ ¸¶Ŕ»żˇĽ łŞżŔµµ·Ď ÇŘ ÁŘ´Ů. 3şĐ ł»żˇ´Â ŔŻŔú·ÎşÎĹÍ
- // ¸¶Ŕ»żˇĽ ˝ĂŔŰÇŇ °ÇÁö, ż©±âĽ ˝ĂŔŰÇŇ °ÇÁö °áÁ¤Ŕ» ąŢ´Â´Ů.
- if (isDuel == false)
- {
- if (m_pkDeadEvent)
- {
- sys_log(1, "DEAD_EVENT_CANCEL: %s %p %p", GetName(), this, get_pointer(m_pkDeadEvent));
- event_cancel(&m_pkDeadEvent);
- }
- if (IsStone())
- ClearStone();
- if (GetDungeon())
- {
- GetDungeon()->DeadCharacter(this);
- }
- SCharDeadEventInfo* pEventInfo = AllocEventInfo<SCharDeadEventInfo>();
- if (IsPC())
- {
- pEventInfo->isPC = true;
- pEventInfo->dwID = this->GetPlayerID();
- m_pkDeadEvent = event_create(dead_event, pEventInfo, PASSES_PER_SEC(180));
- }
- else
- {
- pEventInfo->isPC = false;
- pEventInfo->dwID = this->GetVID();
- if (IsRevive() == false && HasReviverInParty() == true)
- {
- m_pkDeadEvent = event_create(dead_event, pEventInfo, bImmediateDead ? 1 : PASSES_PER_SEC(3));
- }
- else
- {
- m_pkDeadEvent = event_create(dead_event, pEventInfo, bImmediateDead ? 1 : PASSES_PER_SEC(10));
- }
- }
- sys_log(1, "DEAD_EVENT_CREATE: %s %p %p", GetName(), this, get_pointer(m_pkDeadEvent));
- }
- if (m_pkExchange != NULL)
- {
- m_pkExchange->Cancel();
- }
- if (IsCubeOpen() == true)
- {
- Cube_close(this);
- }
- #ifdef __SASH_SYSTEM__
- if (IsPC())
- CloseSash();
- #endif
- CShopManager::instance().StopShopping(this);
- CloseMyShop();
- CloseSafebox();
- if (true == IsMonster() && 2493 == GetMobTable().dwVnum)
- {
- if (NULL != pkKiller && NULL != pkKiller->GetGuild())
- {
- CDragonLairManager::instance().OnDragonDead( this, pkKiller->GetGuild()->GetID() );
- }
- else
- {
- sys_err("DragonLair: Dragon killed by nobody");
- }
- }
- }
- struct FuncSetLastAttacked
- {
- FuncSetLastAttacked(DWORD dwTime) : m_dwTime(dwTime)
- {
- }
- void operator () (LPCHARACTER ch)
- {
- ch->SetLastAttacked(m_dwTime);
- }
- DWORD m_dwTime;
- };
- void CHARACTER::SetLastAttacked(DWORD dwTime)
- {
- assert(m_pkMobInst != NULL);
- m_pkMobInst->m_dwLastAttackedTime = dwTime;
- m_pkMobInst->m_posLastAttacked = GetXYZ();
- }
- void CHARACTER::SendDamagePacket(LPCHARACTER pAttacker, int Damage, BYTE DamageFlag)
- {
- if (IsPC() == true || (pAttacker->IsPC() == true && pAttacker->GetTarget() == this))
- {
- TPacketGCDamageInfo damageInfo;
- memset(&damageInfo, 0, sizeof(TPacketGCDamageInfo));
- damageInfo.header = HEADER_GC_DAMAGE_INFO;
- damageInfo.dwVID = (DWORD)GetVID();
- damageInfo.flag = DamageFlag;
- damageInfo.damage = Damage;
- if (GetDesc() != NULL)
- {
- GetDesc()->Packet(&damageInfo, sizeof(TPacketGCDamageInfo));
- }
- if (pAttacker->GetDesc() != NULL)
- {
- pAttacker->GetDesc()->Packet(&damageInfo, sizeof(TPacketGCDamageInfo));
- }
- /*
- if (GetArenaObserverMode() == false && GetArena() != NULL)
- {
- GetArena()->SendPacketToObserver(&damageInfo, sizeof(TPacketGCDamageInfo));
- }
- */
- }
- }
- //
- // CHARACTER::Damage ¸ŢĽŇµĺ´Â this°ˇ µĄąĚÁö¸¦ ŔÔ°Ô ÇŃ´Ů.
- //
- // Arguments
- // pAttacker : °ř°ÝŔÚ
- // dam : µĄąĚÁö
- // EDamageType : ľî¶˛ Çü˝ÄŔÇ °ř°ÝŔΰˇ?
- //
- // Return value
- // true : dead
- // false : not dead yet
- //
- bool CHARACTER::Damage(LPCHARACTER pAttacker, int dam, EDamageType type) // returns true if dead
- {
- #ifdef ENABLE_NEWSTUFF
- if (pAttacker && IsStone() && pAttacker->IsPC())
- {
- if (GetEmpire() && GetEmpire() == pAttacker->GetEmpire())
- {
- SendDamagePacket(pAttacker, 0, DAMAGE_BLOCK);
- return false;
- }
- }
- #endif
- if (DAMAGE_TYPE_MAGIC == type)
- {
- dam = (int)((float)dam * (100 + (pAttacker->GetPoint(POINT_MAGIC_ATT_BONUS_PER) + pAttacker->GetPoint(POINT_MELEE_MAGIC_ATT_BONUS_PER))) / 100.f + 0.5f);
- }
- if (GetRaceNum() == 5001)
- {
- bool bDropMoney = false;
- int iPercent = 0; // @fixme136
- if (GetMaxHP() >= 0)
- iPercent = (GetHP() * 100) / GetMaxHP();
- if (iPercent <= 10 && GetMaxSP() < 5)
- {
- SetMaxSP(5);
- bDropMoney = true;
- }
- else if (iPercent <= 20 && GetMaxSP() < 4)
- {
- SetMaxSP(4);
- bDropMoney = true;
- }
- else if (iPercent <= 40 && GetMaxSP() < 3)
- {
- SetMaxSP(3);
- bDropMoney = true;
- }
- else if (iPercent <= 60 && GetMaxSP() < 2)
- {
- SetMaxSP(2);
- bDropMoney = true;
- }
- else if (iPercent <= 80 && GetMaxSP() < 1)
- {
- SetMaxSP(1);
- bDropMoney = true;
- }
- if (bDropMoney)
- {
- DWORD dwGold = 1000;
- int iSplitCount = number(10, 13);
- sys_log(0, "WAEGU DropGoldOnHit %d times", GetMaxSP());
- for (int i = 1; i <= iSplitCount; ++i)
- {
- PIXEL_POSITION pos;
- LPITEM item;
- if ((item = ITEM_MANAGER::instance().CreateItem(1, dwGold / iSplitCount)))
- {
- if (i != 0)
- {
- pos.x = (number(-14, 14) + number(-14, 14)) * 20;
- pos.y = (number(-14, 14) + number(-14, 14)) * 20;
- pos.x += GetX();
- pos.y += GetY();
- }
- item->AddToGround(GetMapIndex(), pos);
- item->StartDestroyEvent();
- }
- }
- }
- }
- // ĆňŸ°ˇ ľĆ´Ň ¶§´Â °řĆ÷ Ăł¸®
- if (type != DAMAGE_TYPE_NORMAL && type != DAMAGE_TYPE_NORMAL_RANGE)
- {
- if (IsAffectFlag(AFF_TERROR))
- {
- int pct = GetSkillPower(SKILL_TERROR) / 400;
- if (number(1, 100) <= pct)
- return false;
- }
- }
- int iCurHP = GetHP();
- int iCurSP = GetSP();
- bool IsCritical = false;
- bool IsPenetrate = false;
- bool IsDeathBlow = false;
- //PROF_UNIT puAttr("Attr");
- //
- // ¸¶ąýÇü ˝şĹł°ú, ·ąŔÎÁöÇü ˝şĹłŔş(±ĂŔÚ°´) Ĺ©¸®ĆĽÄĂ°ú, °üĹë°ř°Ý °č»ęŔ» ÇŃ´Ů.
- // żř·ˇ´Â ÇĎÁö ľĘľĆľß ÇϴµĄ Nerf(´Ůżîąë·±˝ş)ĆĐġ¸¦ ÇŇ Ľö ľřľîĽ Ĺ©¸®ĆĽÄĂ°ú
- // °üĹë°ř°ÝŔÇ żř·ˇ °ŞŔ» ľ˛Áö ľĘ°í, /2 ŔĚ»óÇĎż© ŔűżëÇŃ´Ů.
- //
- // ą«»ç Ŕ̾߱Ⱑ ¸ąľĆĽ ąĐ¸® ˝şĹłµµ Ăß°ˇ
- //
- // 20091109 : ą«»ç°ˇ °á°úŔűŔ¸·Î ľöĂ»łŞ°Ô °ÇŘÁř °ÍŔ¸·Î °á·Đł˛, µ¶ŔĎ ±âÁŘ ą«»ç şńŔ˛ 70% Ŕ°ąÚ
- //
- if (type == DAMAGE_TYPE_MELEE || type == DAMAGE_TYPE_RANGE || type == DAMAGE_TYPE_MAGIC)
- {
- if (pAttacker)
- {
- // Ĺ©¸®ĆĽÄĂ
- int iCriticalPct = pAttacker->GetPoint(POINT_CRITICAL_PCT);
- if (!IsPC())
- iCriticalPct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_CRITICAL_BONUS);
- if (iCriticalPct)
- {
- if (iCriticalPct >= 10) // 10ş¸´Ů Ĺ©¸é 5% + (4¸¶´Ů 1%ľż Áő°ˇ), µű¶óĽ Ľöġ°ˇ 50Ŕ̸é 20%
- iCriticalPct = 5 + (iCriticalPct - 10) / 4;
- else // 10ş¸´Ů ŔŰŔ¸¸é ´ÜĽřČ÷ ąÝŔ¸·Î ±đŔ˝, 10 = 5%
- iCriticalPct /= 2;
- //Ĺ©¸®ĆĽÄĂ ŔúÇ× °Ş Ŕűżë.
- iCriticalPct -= GetPoint(POINT_RESIST_CRITICAL);
- if (number(1, 100) <= iCriticalPct)
- {
- IsCritical = true;
- dam *= 2;
- EffectPacket(SE_CRITICAL);
- if (IsAffectFlag(AFF_MANASHIELD))
- {
- RemoveAffect(AFF_MANASHIELD);
- }
- }
- }
- // °üĹë°ř°Ý
- int iPenetratePct = pAttacker->GetPoint(POINT_PENETRATE_PCT);
- if (!IsPC())
- iPenetratePct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_PENETRATE_BONUS);
- if (iPenetratePct)
- {
- {
- CSkillProto* pkSk = CSkillManager::instance().Get(SKILL_RESIST_PENETRATE);
- if (NULL != pkSk)
- {
- pkSk->SetPointVar("k", 1.0f * GetSkillPower(SKILL_RESIST_PENETRATE) / 100.0f);
- iPenetratePct -= static_cast<int>(pkSk->kPointPoly.Eval());
- }
- }
- if (iPenetratePct >= 10)
- {
- // 10ş¸´Ů Ĺ©¸é 5% + (4¸¶´Ů 1%ľż Áő°ˇ), µű¶óĽ Ľöġ°ˇ 50Ŕ̸é 20%
- iPenetratePct = 5 + (iPenetratePct - 10) / 4;
- }
- else
- {
- // 10ş¸´Ů ŔŰŔ¸¸é ´ÜĽřČ÷ ąÝŔ¸·Î ±đŔ˝, 10 = 5%
- iPenetratePct /= 2;
- }
- //°üĹëŸ°Ý ŔúÇ× °Ş Ŕűżë.
- iPenetratePct -= GetPoint(POINT_RESIST_PENETRATE);
- if (number(1, 100) <= iPenetratePct)
- {
- IsPenetrate = true;
- if (test_server)
- ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°üĹë Ăß°ˇ µĄąĚÁö %d"), GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100);
- dam += GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100;
- if (IsAffectFlag(AFF_MANASHIELD))
- {
- RemoveAffect(AFF_MANASHIELD);
- }
- #ifdef ENABLE_EFFECT_PENETRATE
- EffectPacket(SE_PENETRATE);
- #endif
- }
- }
- }
- }
- //
- // ÄŢş¸ °ř°Ý, Č° °ř°Ý, Áď ĆňŸ ŔĎ ¶§¸¸ ĽÓĽş°ŞµéŔ» °č»ęŔ» ÇŃ´Ů.
- //
- else if (type == DAMAGE_TYPE_NORMAL || type == DAMAGE_TYPE_NORMAL_RANGE)
- {
- if (type == DAMAGE_TYPE_NORMAL)
- {
- // ±ŮÁ˘ ĆňŸŔĎ °ćżě ¸·Ŕ» Ľö ŔÖŔ˝
- if (GetPoint(POINT_BLOCK) && number(1, 100) <= GetPoint(POINT_BLOCK))
- {
- if (test_server)
- {
- pAttacker->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s şí·°! (%d%%)"), GetName(), GetPoint(POINT_BLOCK));
- ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s şí·°! (%d%%)"), GetName(), GetPoint(POINT_BLOCK));
- }
- SendDamagePacket(pAttacker, 0, DAMAGE_BLOCK);
- return false;
- }
- }
- else if (type == DAMAGE_TYPE_NORMAL_RANGE)
- {
- // żř°Ĺ¸® ĆňŸŔÇ °ćżě ÇÇÇŇ Ľö ŔÖŔ˝
- if (GetPoint(POINT_DODGE) && number(1, 100) <= GetPoint(POINT_DODGE))
- {
- if (test_server)
- {
- pAttacker->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s ȸÇÇ! (%d%%)"), GetName(), GetPoint(POINT_DODGE));
- ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s ȸÇÇ! (%d%%)"), GetName(), GetPoint(POINT_DODGE));
- }
- SendDamagePacket(pAttacker, 0, DAMAGE_DODGE);
- return false;
- }
- }
- if (IsAffectFlag(AFF_JEONGWIHON))
- dam = (int) (dam * (100 + GetSkillPower(SKILL_JEONGWI) * 25 / 100) / 100);
- if (IsAffectFlag(AFF_TERROR))
- dam = (int) (dam * (95 - GetSkillPower(SKILL_TERROR) / 5) / 100);
- if (IsAffectFlag(AFF_HOSIN))
- dam = dam * (100 - GetPoint(POINT_RESIST_NORMAL_DAMAGE)) / 100;
- //
- // °ř°ÝŔÚ ĽÓĽş Ŕűżë
- //
- if (pAttacker)
- {
- if (type == DAMAGE_TYPE_NORMAL)
- {
- // ąÝ»ç
- if (GetPoint(POINT_REFLECT_MELEE))
- {
- int reflectDamage = dam * GetPoint(POINT_REFLECT_MELEE) / 100;
- // NOTE: °ř°ÝŔÚ°ˇ IMMUNE_REFLECT ĽÓĽşŔ» °®°íŔÖ´Ů¸é ąÝ»ç¸¦ ľČ ÇĎ´Â °Ô
- // ľĆ´Ď¶ó 1/3 µĄąĚÁö·Î °íÁ¤ÇŘĽ µéľî°ˇµµ·Ď ±âČążˇĽ żäĂ».
- if (pAttacker->IsImmune(IMMUNE_REFLECT))
- reflectDamage = int(reflectDamage / 3.0f + 0.5f);
- pAttacker->Damage(this, reflectDamage, DAMAGE_TYPE_SPECIAL);
- }
- }
- // Ĺ©¸®ĆĽÄĂ
- int iCriticalPct = pAttacker->GetPoint(POINT_CRITICAL_PCT);
- if (!IsPC())
- iCriticalPct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_CRITICAL_BONUS);
- if (iCriticalPct)
- {
- //Ĺ©¸®ĆĽÄĂ ŔúÇ× °Ş Ŕűżë.
- iCriticalPct -= GetPoint(POINT_RESIST_CRITICAL);
- if (number(1, 100) <= iCriticalPct)
- {
- IsCritical = true;
- dam *= 2;
- EffectPacket(SE_CRITICAL);
- }
- }
- // °üĹë°ř°Ý
- int iPenetratePct = pAttacker->GetPoint(POINT_PENETRATE_PCT);
- if (!IsPC())
- iPenetratePct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_PENETRATE_BONUS);
- {
- CSkillProto* pkSk = CSkillManager::instance().Get(SKILL_RESIST_PENETRATE);
- if (NULL != pkSk)
- {
- pkSk->SetPointVar("k", 1.0f * GetSkillPower(SKILL_RESIST_PENETRATE) / 100.0f);
- iPenetratePct -= static_cast<int>(pkSk->kPointPoly.Eval());
- }
- }
- if (iPenetratePct)
- {
- //°üĹëŸ°Ý ŔúÇ× °Ş Ŕűżë.
- iPenetratePct -= GetPoint(POINT_RESIST_PENETRATE);
- if (number(1, 100) <= iPenetratePct)
- {
- IsPenetrate = true;
- if (test_server)
- ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°üĹë Ăß°ˇ µĄąĚÁö %d"), GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100);
- dam += GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100;
- #ifdef ENABLE_EFFECT_PENETRATE
- EffectPacket(SE_PENETRATE);
- #endif
- }
- }
- // HP ˝şĆż
- if (pAttacker->GetPoint(POINT_STEAL_HP))
- {
- int pct = 1;
- if (number(1, 10) <= pct)
- {
- int iHP = MIN(dam, MAX(0, iCurHP)) * pAttacker->GetPoint(POINT_STEAL_HP) / 100;
- if (iHP > 0 && GetHP() >= iHP)
- {
- CreateFly(FLY_HP_SMALL, pAttacker);
- pAttacker->PointChange(POINT_HP, iHP);
- PointChange(POINT_HP, -iHP);
- }
- }
- }
- // SP ˝şĆż
- if (pAttacker->GetPoint(POINT_STEAL_SP))
- {
- int pct = 1;
- if (number(1, 10) <= pct)
- {
- int iCur;
- if (IsPC())
- iCur = iCurSP;
- else
- iCur = iCurHP;
- int iSP = MIN(dam, MAX(0, iCur)) * pAttacker->GetPoint(POINT_STEAL_SP) / 100;
- if (iSP > 0 && iCur >= iSP)
- {
- CreateFly(FLY_SP_SMALL, pAttacker);
- pAttacker->PointChange(POINT_SP, iSP);
- if (IsPC())
- PointChange(POINT_SP, -iSP);
- }
- }
- }
- // µ· ˝şĆż
- if (pAttacker->GetPoint(POINT_STEAL_GOLD))
- {
- if (number(1, 100) <= pAttacker->GetPoint(POINT_STEAL_GOLD))
- {
- int iAmount = number(1, GetLevel());
- pAttacker->PointChange(POINT_GOLD, iAmount);
- DBManager::instance().SendMoneyLog(MONEY_LOG_MISC, 1, iAmount);
- }
- }
- // ÄĄ ¶§¸¶´Ů HPȸşą
- if (pAttacker->GetPoint(POINT_HIT_HP_RECOVERY) && number(0, 4) > 0) // 80% Č®·ü
- {
- int i = ((iCurHP>=0)?MIN(dam, iCurHP):dam) * pAttacker->GetPoint(POINT_HIT_HP_RECOVERY) / 100; //@fixme107
- if (i)
- {
- CreateFly(FLY_HP_SMALL, pAttacker);
- pAttacker->PointChange(POINT_HP, i);
- }
- }
- // ÄĄ ¶§¸¶´Ů SPȸşą
- if (pAttacker->GetPoint(POINT_HIT_SP_RECOVERY) && number(0, 4) > 0) // 80% Č®·ü
- {
- int i = ((iCurHP>=0)?MIN(dam, iCurHP):dam) * pAttacker->GetPoint(POINT_HIT_SP_RECOVERY) / 100; //@fixme107
- if (i)
- {
- CreateFly(FLY_SP_SMALL, pAttacker);
- pAttacker->PointChange(POINT_SP, i);
- }
- }
- // »ó´ëąćŔÇ ¸¶łŞ¸¦ ľřľŘ´Ů.
- if (pAttacker->GetPoint(POINT_MANA_BURN_PCT))
- {
- if (number(1, 100) <= pAttacker->GetPoint(POINT_MANA_BURN_PCT))
- PointChange(POINT_SP, -50);
- }
- }
- }
- //
- // ĆňŸ ¶Ç´Â ˝şĹł·Î ŔÎÇŃ ş¸łĘ˝ş ÇÇÇŘ/ąćľî °č»ę
- //
- switch (type)
- {
- case DAMAGE_TYPE_NORMAL:
- case DAMAGE_TYPE_NORMAL_RANGE:
- if (pAttacker)
- if (pAttacker->GetPoint(POINT_NORMAL_HIT_DAMAGE_BONUS))
- dam = dam * (100 + pAttacker->GetPoint(POINT_NORMAL_HIT_DAMAGE_BONUS)) / 100;
- dam = dam * (100 - MIN(99, GetPoint(POINT_NORMAL_HIT_DEFEND_BONUS))) / 100;
- break;
- case DAMAGE_TYPE_MELEE:
- case DAMAGE_TYPE_RANGE:
- case DAMAGE_TYPE_FIRE:
- case DAMAGE_TYPE_ICE:
- case DAMAGE_TYPE_ELEC:
- case DAMAGE_TYPE_MAGIC:
- if (pAttacker)
- if (pAttacker->GetPoint(POINT_SKILL_DAMAGE_BONUS))
- dam = dam * (100 + pAttacker->GetPoint(POINT_SKILL_DAMAGE_BONUS)) / 100;
- dam = dam * (100 - MIN(99, GetPoint(POINT_SKILL_DEFEND_BONUS))) / 100;
- break;
- default:
- break;
- }
- //
- // ¸¶łŞ˝Żµĺ(Čć˝ĹĽöČŁ)
- //
- if (IsAffectFlag(AFF_MANASHIELD))
- {
- // POINT_MANASHIELD ´Â ŔŰľĆÁúĽö·Ď ÁÁ´Ů
- int iDamageSPPart = dam / 3;
- int iDamageToSP = iDamageSPPart * GetPoint(POINT_MANASHIELD) / 100;
- int iSP = GetSP();
- // SP°ˇ ŔÖŔ¸¸é ą«Á¶°Ç µĄąĚÁö ŔýąÝ °¨ĽŇ
- if (iDamageToSP <= iSP)
- {
- PointChange(POINT_SP, -iDamageToSP);
- dam -= iDamageSPPart;
- }
- else
- {
- // Á¤˝Ĺ·ÂŔĚ ¸đŔÚ¶óĽ ÇÇ°ˇ ´ő ±ďż©ľßÇŇ‹š
- PointChange(POINT_SP, -GetSP());
- dam -= iSP * 100 / MAX(GetPoint(POINT_MANASHIELD), 1);
- }
- }
- //
- // ŔüĂĽ ąćľî·Â »ó˝Â (¸ô ľĆŔĚĹŰ)
- //
- if (GetPoint(POINT_MALL_DEFBONUS) > 0)
- {
- int dec_dam = MIN(200, dam * GetPoint(POINT_MALL_DEFBONUS) / 100);
- dam -= dec_dam;
- }
- if (pAttacker)
- {
- //
- // ŔüĂĽ °ř°Ý·Â »ó˝Â (¸ô ľĆŔĚĹŰ)
- //
- if (pAttacker->GetPoint(POINT_MALL_ATTBONUS) > 0)
- {
- int add_dam = MIN(300, dam * pAttacker->GetLimitPoint(POINT_MALL_ATTBONUS) / 100);
- dam += add_dam;
- }
- if (pAttacker->IsPC())
- {
- int iEmpire = pAttacker->GetEmpire();
- long lMapIndex = pAttacker->GetMapIndex();
- int iMapEmpire = SECTREE_MANAGER::instance().GetEmpireFromMapIndex(lMapIndex);
- // ´Ů¸Ą Á¦±ą »ç¶÷ŔÎ °ćżě µĄąĚÁö 10% °¨ĽŇ
- if (iEmpire && iMapEmpire && iEmpire != iMapEmpire)
- {
- dam = dam * 9 / 10;
- }
- if (!IsPC() && GetMonsterDrainSPPoint())
- {
- int iDrain = GetMonsterDrainSPPoint();
- if (iDrain <= pAttacker->GetSP())
- pAttacker->PointChange(POINT_SP, -iDrain);
- else
- {
- int iSP = pAttacker->GetSP();
- pAttacker->PointChange(POINT_SP, -iSP);
- }
- }
- }
- else if (pAttacker->IsGuardNPC())
- {
- SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_NO_REWARD);
- Stun();
- return true;
- }
- //
- // ±şÁÖŔÇ ±Ý°±Ç & »çŔÚČÄ
- //
- if (pAttacker->IsPC() && CMonarch::instance().IsPowerUp(pAttacker->GetEmpire()))
- {
- // 10% ÇÇÇŘ Áő°ˇ
- dam += dam / 10;
- }
- if (IsPC() && CMonarch::instance().IsDefenceUp(GetEmpire()))
- {
- // 10% ÇÇÇŘ °¨ĽŇ
- dam -= dam / 10;
- }
- }
- //puAttr.Pop();
- if (!GetSectree() || GetSectree()->IsAttr(GetX(), GetY(), ATTR_BANPK))
- return false;
- if (!IsPC())
- {
- if (m_pkParty && m_pkParty->GetLeader())
- m_pkParty->GetLeader()->SetLastAttacked(get_dword_time());
- else
- SetLastAttacked(get_dword_time());
- // ¸ó˝şĹÍ ´ë»ç : ¸ÂŔ» ¶§
- MonsterChat(MONSTER_CHAT_ATTACKED);
- }
- if (IsStun())
- {
- Dead(pAttacker);
- return true;
- }
- if (IsDead())
- return true;
- // µ¶ °ř°ÝŔ¸·Î Á×Áö ľĘµµ·Ď ÇÔ.
- if (type == DAMAGE_TYPE_POISON)
- {
- if (GetHP() - dam <= 0)
- {
- dam = GetHP() - 1;
- }
- }
- #ifdef ENABLE_WOLFMAN_CHARACTER
- else if (type == DAMAGE_TYPE_BLEEDING)
- {
- if (GetHP() - dam <= 0)
- {
- dam = GetHP();
- }
- }
- #endif
- // ------------------------
- // µ¶ŔĎ ÇÁ¸®ąĚľö ¸đµĺ
- // -----------------------
- if (pAttacker && pAttacker->IsPC())
- {
- int iDmgPct = CHARACTER_MANAGER::instance().GetUserDamageRate(pAttacker);
- dam = dam * iDmgPct / 100;
- }
- // STONE SKIN : ÇÇÇŘ ąÝŔ¸·Î °¨ĽŇ
- if (IsMonster() && IsStoneSkinner())
- {
- if (GetHPPct() < GetMobTable().bStoneSkinPoint)
- dam /= 2;
- }
- //PROF_UNIT puRest1("Rest1");
- if (pAttacker)
- {
- // DEATH BLOW : Č®·ü ŔűŔ¸·Î 4ąč ÇÇÇŘ (!? ÇöŔç ŔĚşĄĆ®łŞ °řĽşŔüżë ¸ó˝şĹ͸¸ »çżëÇÔ)
- if (pAttacker->IsMonster() && pAttacker->IsDeathBlower())
- {
- if (pAttacker->IsDeathBlow())
- {
- if (number(1, 4) == GetJob())
- {
- IsDeathBlow = true;
- dam = dam * 4;
- }
- }
- }
- dam = BlueDragon_Damage(this, pAttacker, dam);
- BYTE damageFlag = 0;
- if (type == DAMAGE_TYPE_POISON)
- damageFlag = DAMAGE_POISON;
- #if defined(ENABLE_WOLFMAN_CHARACTER) && !defined(USE_MOB_BLEEDING_AS_POISON)
- else if (type == DAMAGE_TYPE_BLEEDING)
- damageFlag = DAMAGE_BLEEDING;
- #elif defined(ENABLE_WOLFMAN_CHARACTER) && defined(USE_MOB_BLEEDING_AS_POISON)
- else if (type == DAMAGE_TYPE_BLEEDING)
- damageFlag = DAMAGE_POISON;
- #endif
- else
- damageFlag = DAMAGE_NORMAL;
- if (IsCritical == true)
- damageFlag |= DAMAGE_CRITICAL;
- if (IsPenetrate == true)
- damageFlag |= DAMAGE_PENETRATE;
- //ĂÖÁľ µĄąĚÁö ş¸Á¤
- float damMul = this->GetDamMul();
- float tempDam = dam;
- dam = tempDam * damMul + 0.5f;
- if (pAttacker)
- SendDamagePacket(pAttacker, dam, damageFlag);
- if (test_server)
- {
- int iTmpPercent = 0; // @fixme136
- if (GetMaxHP() >= 0)
- iTmpPercent = (GetHP() * 100) / GetMaxHP();
- if(pAttacker)
- {
- pAttacker->ChatPacket(CHAT_TYPE_INFO, "-> %s, DAM %d HP %d(%d%%) %s%s",
- GetName(),
- dam,
- GetHP(),
- iTmpPercent,
- IsCritical ? "crit " : "",
- IsPenetrate ? "pene " : "",
- IsDeathBlow ? "deathblow " : "");
- }
- ChatPacket(CHAT_TYPE_PARTY, "<- %s, DAM %d HP %d(%d%%) %s%s",
- pAttacker ? pAttacker->GetName() : 0,
- dam,
- GetHP(),
- iTmpPercent,
- IsCritical ? "crit " : "",
- IsPenetrate ? "pene " : "",
- IsDeathBlow ? "deathblow " : "");
- }
- if (m_bDetailLog)
- {
- ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s[%d]°ˇ °ř°Ý Ŕ§Äˇ: %d %d"), pAttacker->GetName(), (DWORD) pAttacker->GetVID(), pAttacker->GetX(), pAttacker->GetY());
- }
- }
- //
- // !!!!!!!!! ˝ÇÁ¦ HP¸¦ ÁŮŔĚ´Â şÎşĐ !!!!!!!!!
- //
- if (!cannot_dead)
- {
- if (GetHP() - dam <= 0) // @fixme137
- dam = GetHP();
- PointChange(POINT_HP, -dam, false);
- }
- //puRest1.Pop();
- //PROF_UNIT puRest2("Rest2");
- if (pAttacker && dam > 0 && IsNPC())
- {
- //PROF_UNIT puRest20("Rest20");
- TDamageMap::iterator it = m_map_kDamage.find(pAttacker->GetVID());
- if (it == m_map_kDamage.end())
- {
- m_map_kDamage.insert(TDamageMap::value_type(pAttacker->GetVID(), TBattleInfo(dam, 0)));
- it = m_map_kDamage.find(pAttacker->GetVID());
- }
- else
- {
- it->second.iTotalDamage += dam;
- }
- //puRest20.Pop();
- //PROF_UNIT puRest21("Rest21");
- StartRecoveryEvent(); // ¸ó˝şĹÍ´Â µĄąĚÁö¸¦ ŔÔŔ¸¸é ȸşąŔ» ˝ĂŔŰÇŃ´Ů.
- //puRest21.Pop();
- //PROF_UNIT puRest22("Rest22");
- UpdateAggrPointEx(pAttacker, type, dam, it->second);
- //puRest22.Pop();
- }
- //puRest2.Pop();
- //PROF_UNIT puRest3("Rest3");
- if (GetHP() <= 0)
- {
- Stun();
- if (pAttacker && !pAttacker->IsNPC())
- m_dwKillerPID = pAttacker->GetPlayerID();
- else
- m_dwKillerPID = 0;
- }
- return false;
- }
- void CHARACTER::DistributeHP(LPCHARACTER pkKiller)
- {
- if (pkKiller->GetDungeon()) // ´řÁŻł»żˇĽ± ¸¸µÎ°ˇłŞżŔÁöľĘ´Â´Ů
- return;
- }
- #define ENABLE_NEWEXP_CALCULATION
- #ifdef ENABLE_NEWEXP_CALCULATION
- #define NEW_GET_LVDELTA(me, victim) aiPercentByDeltaLev[MINMAX(0, (victim + 15) - me, MAX_EXP_DELTA_OF_LEV - 1)]
- typedef long double rate_t;
- static void GiveExp(LPCHARACTER from, LPCHARACTER to, int iExp)
- {
- if (test_server && iExp < 0)
- {
- to->ChatPacket(CHAT_TYPE_INFO, "exp(%d) overflow", iExp);
- return;
- }
- // decrease/increase exp based on player<>mob level
- rate_t lvFactor = static_cast<rate_t>(NEW_GET_LVDELTA(to->GetLevel(), from->GetLevel())) / 100.0L;
- iExp *= lvFactor;
- // start calculating rate exp bonus
- int iBaseExp = iExp;
- rate_t rateFactor = 100;
- if (distribution_test_server)
- rateFactor *= 3;
- rateFactor += CPrivManager::instance().GetPriv(to, PRIV_EXP_PCT);
- if (to->IsEquipUniqueItem(UNIQUE_ITEM_LARBOR_MEDAL))
- rateFactor += 20;
- if (to->GetMapIndex() >= 660000 && to->GetMapIndex() < 670000)
- rateFactor += 20;
- if (to->GetPoint(POINT_EXP_DOUBLE_BONUS))
- if (number(1, 100) <= to->GetPoint(POINT_EXP_DOUBLE_BONUS))
- rateFactor += 30;
- if (to->IsEquipUniqueItem(UNIQUE_ITEM_DOUBLE_EXP))
- rateFactor += 50;
- switch (to->GetMountVnum())
- {
- case 20110:
- case 20111:
- case 20112:
- case 20113:
- if (to->IsEquipUniqueItem(71115) || to->IsEquipUniqueItem(71117) || to->IsEquipUniqueItem(71119) ||
- to->IsEquipUniqueItem(71121) )
- {
- rateFactor += 10;
- }
- break;
- case 20114:
- case 20120:
- case 20121:
- case 20122:
- case 20123:
- case 20124:
- case 20125:
- rateFactor += 30;
- break;
- }
- if (to->GetPremiumRemainSeconds(PREMIUM_EXP) > 0)
- rateFactor += 50;
- if (to->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_EXP))
- rateFactor += 50;
- if (to->GetPoint(POINT_PC_BANG_EXP_BONUS) > 0)
- {
- if (to->IsPCBang())
- rateFactor += to->GetPoint(POINT_PC_BANG_EXP_BONUS);
- }
- rateFactor += to->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_EXP_BONUS);
- rateFactor += to->GetPoint(POINT_RAMADAN_CANDY_BONUS_EXP);
- rateFactor += to->GetPoint(POINT_MALL_EXPBONUS);
- rateFactor += to->GetPoint(POINT_EXP);
- // useless (never used except for china intoxication) = always 100
- rateFactor = rateFactor * static_cast<rate_t>(CHARACTER_MANAGER::instance().GetMobExpRate(to))/100.0L;
- // apply calculated rate bonus
- iExp *= (rateFactor/100.0L);
- if (test_server)
- to->ChatPacket(CHAT_TYPE_INFO, "base_exp(%d) * rate(%Lf) = exp(%d)", iBaseExp, rateFactor/100.0L, iExp);
- // you can get at maximum only 10% of the total required exp at once (so, you need to kill at least 10 mobs to level up) (useless)
- iExp = MIN(to->GetNextExp() / 10, iExp);
- // it recalculate the given exp if the player level is greater than the exp_table size (useless)
- iExp = AdjustExpByLevel(to, iExp);
- if (test_server)
- to->ChatPacket(CHAT_TYPE_INFO, "exp+minGNE+adjust(%d)", iExp);
- // set
- to->PointChange(POINT_EXP, iExp, true);
- from->CreateFly(FLY_EXP, to);
- // marriage
- {
- LPCHARACTER you = to->GetMarryPartner();
- if (you)
- {
- // sometimes, this overflows
- DWORD dwUpdatePoint = (2000.0L/to->GetLevel()/to->GetLevel()/3)*iExp;
- if (to->GetPremiumRemainSeconds(PREMIUM_MARRIAGE_FAST) > 0 ||
- you->GetPremiumRemainSeconds(PREMIUM_MARRIAGE_FAST) > 0)
- dwUpdatePoint *= 3;
- marriage::TMarriage* pMarriage = marriage::CManager::instance().Get(to->GetPlayerID());
- // DIVORCE_NULL_BUG_FIX
- if (pMarriage && pMarriage->IsNear())
- pMarriage->Update(dwUpdatePoint);
- // END_OF_DIVORCE_NULL_BUG_FIX
- }
- }
- }
- #else
- static void GiveExp(LPCHARACTER from, LPCHARACTER to, int iExp)
- {
- // ·ąş§Â÷ °ćÇčġ °ˇ°¨şńŔ˛
- iExp = CALCULATE_VALUE_LVDELTA(to->GetLevel(), from->GetLevel(), iExp);
- // żÜşÎ Ĺ×˝şĆ® Ľąö °ćÇčġ 3ąč ş¸łĘ˝ş
- if (distribution_test_server)
- iExp *= 3;
- int iBaseExp = iExp;
- // ÁˇĽú, ȸ»ç °ćÇčġ ŔĚşĄĆ® Ŕűżë
- iExp = iExp * (100 + CPrivManager::instance().GetPriv(to, PRIV_EXP_PCT)) / 100;
- // °ÔŔÓł» ±âş» Á¦°řµÇ´Â °ćÇčġ ş¸łĘ˝ş
- {
- // łëµżŔý ¸Ţ´Ţ
- if (to->IsEquipUniqueItem(UNIQUE_ITEM_LARBOR_MEDAL))
- iExp += iExp * 20 /100;
- // »ç±ÍŸżö °ćÇčġ ş¸łĘ˝ş
- if (to->GetMapIndex() >= 660000 && to->GetMapIndex() < 670000)
- iExp += iExp * 20 / 100; // 1.2ąč (20%)
- // ľĆŔĚĹŰ °ćÇčġ µÎąč ĽÓĽş
- if (to->GetPoint(POINT_EXP_DOUBLE_BONUS))
- if (number(1, 100) <= to->GetPoint(POINT_EXP_DOUBLE_BONUS))
- iExp += iExp * 30 / 100; // 1.3ąč (30%)
- // °ćÇčŔÇ ąÝÁö (2˝Ă°ŁÂĄ¸®)
- if (to->IsEquipUniqueItem(UNIQUE_ITEM_DOUBLE_EXP))
- iExp += iExp * 50 / 100;
- switch (to->GetMountVnum())
- {
- case 20110:
- case 20111:
- case 20112:
- case 20113:
- if (to->IsEquipUniqueItem(71115) || to->IsEquipUniqueItem(71117) || to->IsEquipUniqueItem(71119) ||
- to->IsEquipUniqueItem(71121) )
- {
- iExp += iExp * 10 / 100;
- }
- break;
- case 20114:
- case 20120:
- case 20121:
- case 20122:
- case 20123:
- case 20124:
- case 20125:
- // ąé»çŔÚ °ćÇčġ ş¸łĘ˝ş
- iExp += iExp * 30 / 100;
- break;
- }
- }
- // ľĆŔĚĹŰ ¸ô ĆǸŠ°ćÇčġ ş¸łĘ˝ş
- {
- // ľĆŔĚĹŰ ¸ô: °ćÇčġ °áÁ¦
- if (to->GetPremiumRemainSeconds(PREMIUM_EXP) > 0)
- {
- iExp += (iExp * 50 / 100);
- }
- if (to->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_EXP) == true)
- {
- iExp += (iExp * 50 / 100);
- }
- // PCąć ľĆĹŰ °ćġ ş¸łĘ˝ş
- if (to->GetPoint(POINT_PC_BANG_EXP_BONUS) > 0)
- {
- if (to->IsPCBang() == true)
- iExp += (iExp * to->GetPoint(POINT_PC_BANG_EXP_BONUS)/100);
- }
- // °áČĄ ş¸łĘ˝ş
- iExp += iExp * to->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_EXP_BONUS) / 100;
- }
- iExp += (iExp * to->GetPoint(POINT_RAMADAN_CANDY_BONUS_EXP)/100);
- iExp += (iExp * to->GetPoint(POINT_MALL_EXPBONUS)/100);
- iExp += (iExp * to->GetPoint(POINT_EXP)/100);
- /* if (speed_server)
- {
- iExp += iExp * CSpeedServerManager::ExpBonus();
- }
- */
- if (test_server)
- {
- sys_log(0, "Bonus Exp : Ramadan Candy: %d MallExp: %d PointExp: %d",
- to->GetPoint(POINT_RAMADAN_CANDY_BONUS_EXP),
- to->GetPoint(POINT_MALL_EXPBONUS),
- to->GetPoint(POINT_EXP)
- );
- }
- // ±âČąĂř Á¶Á¤°Ş 2005.04.21 ÇöŔç 85%
- iExp = iExp * CHARACTER_MANAGER::instance().GetMobExpRate(to) / 100;
- // °ćÇčġ ÇŃąř Čąµć·® Á¦ÇŃ
- iExp = MIN(to->GetNextExp() / 10, iExp);
- if (test_server)
- {
- if (quest::CQuestManager::instance().GetEventFlag("exp_bonus_log") && iBaseExp>0)
- to->ChatPacket(CHAT_TYPE_INFO, "exp bonus %d%%", (iExp-iBaseExp)*100/iBaseExp);
- to->ChatPacket(CHAT_TYPE_INFO, "exp(%d) base_exp(%d)", iExp, iBaseExp);
- }
- iExp = AdjustExpByLevel(to, iExp);
- to->PointChange(POINT_EXP, iExp, true);
- from->CreateFly(FLY_EXP, to);
- {
- LPCHARACTER you = to->GetMarryPartner();
- // şÎşÎ°ˇ Ľ·Î ĆÄĆĽÁßŔĚ¸é ±Ý˝˝ŔĚ żŔ¸Ą´Ů
- if (you)
- {
- // 1ľďŔĚ 100%
- DWORD dwUpdatePoint = 2000*iExp/to->GetLevel()/to->GetLevel()/3;
- if (to->GetPremiumRemainSeconds(PREMIUM_MARRIAGE_FAST) > 0 ||
- you->GetPremiumRemainSeconds(PREMIUM_MARRIAGE_FAST) > 0)
- dwUpdatePoint = (DWORD)(dwUpdatePoint * 3);
- marriage::TMarriage* pMarriage = marriage::CManager::instance().Get(to->GetPlayerID());
- // DIVORCE_NULL_BUG_FIX
- if (pMarriage && pMarriage->IsNear())
- pMarriage->Update(dwUpdatePoint);
- // END_OF_DIVORCE_NULL_BUG_FIX
- }
- }
- }
- #endif
- namespace NPartyExpDistribute
- {
- struct FPartyTotaler
- {
- int total;
- int member_count;
- int x, y;
- FPartyTotaler(LPCHARACTER center)
- : total(0), member_count(0), x(center->GetX()), y(center->GetY())
- {};
- void operator () (LPCHARACTER ch)
- {
- if (DISTANCE_APPROX(ch->GetX() - x, ch->GetY() - y) <= PARTY_DEFAULT_RANGE)
- {
- total += __GetPartyExpNP(ch->GetLevel());
- ++member_count;
- }
- }
- };
- struct FPartyDistributor
- {
- int total;
- LPCHARACTER c;
- int x, y;
- DWORD _iExp;
- int m_iMode;
- int m_iMemberCount;
- FPartyDistributor(LPCHARACTER center, int member_count, int total, DWORD iExp, int iMode)
- : total(total), c(center), x(center->GetX()), y(center->GetY()), _iExp(iExp), m_iMode(iMode), m_iMemberCount(member_count)
- {
- if (m_iMemberCount == 0)
- m_iMemberCount = 1;
- };
- void operator () (LPCHARACTER ch)
- {
- if (DISTANCE_APPROX(ch->GetX() - x, ch->GetY() - y) <= PARTY_DEFAULT_RANGE)
- {
- DWORD iExp2 = 0;
- switch (m_iMode)
- {
- case PARTY_EXP_DISTRIBUTION_NON_PARITY:
- iExp2 = (DWORD) (_iExp * (float) __GetPartyExpNP(ch->GetLevel()) / total);
- break;
- case PARTY_EXP_DISTRIBUTION_PARITY:
- iExp2 = _iExp / m_iMemberCount;
- break;
- default:
- sys_err("Unknown party exp distribution mode %d", m_iMode);
- return;
- }
- GiveExp(c, ch, iExp2);
- }
- }
- };
- }
- typedef struct SDamageInfo
- {
- int iDam;
- LPCHARACTER pAttacker;
- LPPARTY pParty;
- void Clear()
- {
- pAttacker = NULL;
- pParty = NULL;
- }
- inline void Distribute(LPCHARACTER ch, int iExp)
- {
- if (pAttacker)
- GiveExp(ch, pAttacker, iExp);
- else if (pParty)
- {
- NPartyExpDistribute::FPartyTotaler f(ch);
- pParty->ForEachOnlineMember(f);
- if (pParty->IsPositionNearLeader(ch))
- iExp = iExp * (100 + pParty->GetExpBonusPercent()) / 100;
- if (test_server)
- {
- if (quest::CQuestManager::instance().GetEventFlag("exp_bonus_log") && pParty->GetExpBonusPercent())
- pParty->ChatPacketToAllMember(CHAT_TYPE_INFO, "exp party bonus %d%%", pParty->GetExpBonusPercent());
- }
- // °ćÇčġ ¸ôľĆÁÖ±â (ĆÄĆĽ°ˇ ČąµćÇŃ °ćÇčġ¸¦ 5% »©Ľ ¸ŐŔú ÁÜ)
- if (pParty->GetExpCentralizeCharacter())
- {
- LPCHARACTER tch = pParty->GetExpCentralizeCharacter();
- if (DISTANCE_APPROX(ch->GetX() - tch->GetX(), ch->GetY() - tch->GetY()) <= PARTY_DEFAULT_RANGE)
- {
- int iExpCenteralize = (int) (iExp * 0.05f);
- iExp -= iExpCenteralize;
- GiveExp(ch, pParty->GetExpCentralizeCharacter(), iExpCenteralize);
- }
- }
- NPartyExpDistribute::FPartyDistributor fDist(ch, f.member_count, f.total, iExp, pParty->GetExpDistributionMode());
- pParty->ForEachOnlineMember(fDist);
- }
- }
- } TDamageInfo;
- LPCHARACTER CHARACTER::DistributeExp()
- {
- int iExpToDistribute = GetExp();
- if (iExpToDistribute <= 0)
- return NULL;
- int iTotalDam = 0;
- LPCHARACTER pkChrMostAttacked = NULL;
- int iMostDam = 0;
- typedef std::vector<TDamageInfo> TDamageInfoTable;
- TDamageInfoTable damage_info_table;
- std::map<LPPARTY, TDamageInfo> map_party_damage;
- damage_info_table.reserve(m_map_kDamage.size());
- TDamageMap::iterator it = m_map_kDamage.begin();
- // ŔĎ´Ü ÁÖŔ§żˇ ľř´Â »ç¶÷Ŕ» °É·Ż ł˝´Ů. (50m)
- while (it != m_map_kDamage.end())
- {
- const VID & c_VID = it->first;
- int iDam = it->second.iTotalDamage;
- ++it;
- LPCHARACTER pAttacker = CHARACTER_MANAGER::instance().Find(c_VID);
- // NPC°ˇ ¶§¸®±âµµ ÇĎłŞ? -.-;
- if (!pAttacker || pAttacker->IsNPC() || DISTANCE_APPROX(GetX()-pAttacker->GetX(), GetY()-pAttacker->GetY())>5000)
- continue;
- iTotalDam += iDam;
- if (!pkChrMostAttacked || iDam > iMostDam)
- {
- pkChrMostAttacked = pAttacker;
- iMostDam = iDam;
- }
- if (pAttacker->GetParty())
- {
- std::map<LPPARTY, TDamageInfo>::iterator it = map_party_damage.find(pAttacker->GetParty());
- if (it == map_party_damage.end())
- {
- TDamageInfo di;
- di.iDam = iDam;
- di.pAttacker = NULL;
- di.pParty = pAttacker->GetParty();
- map_party_damage.insert(std::make_pair(di.pParty, di));
- }
- else
- {
- it->second.iDam += iDam;
- }
- }
- else
- {
- TDamageInfo di;
- di.iDam = iDam;
- di.pAttacker = pAttacker;
- di.pParty = NULL;
- //sys_log(0, "__ pq_damage %s %d", pAttacker->GetName(), iDam);
- //pq_damage.push(di);
- damage_info_table.push_back(di);
- }
- }
- for (std::map<LPPARTY, TDamageInfo>::iterator it = map_party_damage.begin(); it != map_party_damage.end(); ++it)
- {
- damage_info_table.push_back(it->second);
- //sys_log(0, "__ pq_damage_party [%u] %d", it->second.pParty->GetLeaderPID(), it->second.iDam);
- }
- SetExp(0);
- //m_map_kDamage.clear();
- if (iTotalDam == 0) // µĄąĚÁö ÁŘ°Ô 0ŔĚ¸é ¸®ĹĎ
- return NULL;
- if (m_pkChrStone) // µąŔĚ ŔÖŔ» °ćżě °ćÇčġŔÇ ąÝŔ» µążˇ°Ô łŃ±ä´Ů.
- {
- //sys_log(0, "__ Give half to Stone : %d", iExpToDistribute>>1);
- int iExp = iExpToDistribute >> 1;
- m_pkChrStone->SetExp(m_pkChrStone->GetExp() + iExp);
- iExpToDistribute -= iExp;
- }
- sys_log(1, "%s total exp: %d, damage_info_table.size() == %d, TotalDam %d",
- GetName(), iExpToDistribute, damage_info_table.size(), iTotalDam);
- //sys_log(1, "%s total exp: %d, pq_damage.size() == %d, TotalDam %d",
- //GetName(), iExpToDistribute, pq_damage.size(), iTotalDam);
- if (damage_info_table.empty())
- return NULL;
- // Á¦ŔĎ µĄąĚÁö¸¦ ¸ąŔĚ ÁŘ »ç¶÷ŔĚ HP ȸşąŔ» ÇŃ´Ů.
- DistributeHP(pkChrMostAttacked); // ¸¸µÎ ˝Ă˝şĹŰ
- {
- // Á¦ŔĎ µĄąĚÁö¸¦ ¸ąŔĚ ÁŘ »ç¶÷ŔĚłŞ ĆÄĆĽ°ˇ ĂŃ °ćÇčġŔÇ 20% + ŔڱⰡ ¶§¸°¸¸ĹŔÇ °ćÇčġ¸¦ ¸Ô´Â´Ů.
- TDamageInfoTable::iterator di = damage_info_table.begin();
- {
- TDamageInfoTable::iterator it;
- for (it = damage_info_table.begin(); it != damage_info_table.end();++it)
- {
- if (it->iDam > di->iDam)
- di = it;
- }
- }
- int iExp = iExpToDistribute / 5;
- iExpToDistribute -= iExp;
- float fPercent = (float) di->iDam / iTotalDam;
- if (fPercent > 1.0f)
- {
- sys_err("DistributeExp percent over 1.0 (fPercent %f name %s)", fPercent, di->pAttacker->GetName());
- fPercent = 1.0f;
- }
- iExp += (int) (iExpToDistribute * fPercent);
- //sys_log(0, "%s given exp percent %.1f + 20 dam %d", GetName(), fPercent * 100.0f, di.iDam);
- di->Distribute(this, iExp);
- // 100% ´Ů ¸ÔľúŔ¸¸é ¸®ĹĎÇŃ´Ů.
- if (fPercent == 1.0f)
- return pkChrMostAttacked;
- di->Clear();
- }
- {
- // ł˛Ŕş 80%ŔÇ °ćÇčġ¸¦ şĐąčÇŃ´Ů.
- TDamageInfoTable::iterator it;
- for (it = damage_info_table.begin(); it != damage_info_table.end(); ++it)
- {
- TDamageInfo & di = *it;
- float fPercent = (float) di.iDam / iTotalDam;
- if (fPercent > 1.0f)
- {
- sys_err("DistributeExp percent over 1.0 (fPercent %f name %s)", fPercent, di.pAttacker->GetName());
- fPercent = 1.0f;
- }
- //sys_log(0, "%s given exp percent %.1f dam %d", GetName(), fPercent * 100.0f, di.iDam);
- di.Distribute(this, (int) (iExpToDistribute * fPercent));
- }
- }
- return pkChrMostAttacked;
- }
- // Č»ě °łĽö¸¦ ¸®ĹĎÇŘ ÁÜ
- int CHARACTER::GetArrowAndBow(LPITEM * ppkBow, LPITEM * ppkArrow, int iArrowCount/* = 1 */)
- {
- LPITEM pkBow;
- if (!(pkBow = GetWear(WEAR_WEAPON)) || pkBow->GetProto()->bSubType != WEAPON_BOW)
- {
- return 0;
- }
- LPITEM pkArrow;
- if (!(pkArrow = GetWear(WEAR_ARROW)) || pkArrow->GetType() != ITEM_WEAPON ||
- pkArrow->GetProto()->bSubType != WEAPON_ARROW)
- {
- return 0;
- }
- iArrowCount = MIN(iArrowCount, pkArrow->GetCount());
- *ppkBow = pkBow;
- *ppkArrow = pkArrow;
- return iArrowCount;
- }
- void CHARACTER::UseArrow(LPITEM pkArrow, DWORD dwArrowCount)
- {
- int iCount = pkArrow->GetCount();
- DWORD dwVnum = pkArrow->GetVnum();
- iCount = iCount - MIN(iCount, dwArrowCount);
- pkArrow->SetCount(iCount);
- if (iCount == 0)
- {
- LPITEM pkNewArrow = FindSpecifyItem(dwVnum);
- sys_log(0, "UseArrow : FindSpecifyItem %u %p", dwVnum, get_pointer(pkNewArrow));
- if (pkNewArrow)
- EquipItem(pkNewArrow);
- }
- }
- class CFuncShoot
- {
- public:
- LPCHARACTER m_me;
- BYTE m_bType;
- bool m_bSucceed;
- CFuncShoot(LPCHARACTER ch, BYTE bType) : m_me(ch), m_bType(bType), m_bSucceed(FALSE)
- {
- }
- void operator () (DWORD dwTargetVID)
- {
- if (m_bType > 1)
- {
- if (g_bSkillDisable)
- return;
- m_me->m_SkillUseInfo[m_bType].SetMainTargetVID(dwTargetVID);
- /*if (m_bType == SKILL_BIPABU || m_bType == SKILL_KWANKYEOK)
- m_me->m_SkillUseInfo[m_bType].ResetHitCount();*/
- }
- LPCHARACTER pkVictim = CHARACTER_MANAGER::instance().Find(dwTargetVID);
- if (!pkVictim)
- return;
- // °ř°Ý şŇ°ˇ
- if (!battle_is_attackable(m_me, pkVictim))
- return;
- if (m_me->IsNPC())
- {
- if (DISTANCE_APPROX(m_me->GetX() - pkVictim->GetX(), m_me->GetY() - pkVictim->GetY()) > 5000)
- return;
- }
- LPITEM pkBow, pkArrow;
- switch (m_bType)
- {
- case 0: // ŔĎąÝČ°
- {
- int iDam = 0;
- if (m_me->IsPC())
- {
- if (m_me->GetJob() != JOB_ASSASSIN)
- return;
- if (0 == m_me->GetArrowAndBow(&pkBow, &pkArrow))
- return;
- if (m_me->GetSkillGroup() != 0)
- if (!m_me->IsNPC() && m_me->GetSkillGroup() != 2)
- {
- if (m_me->GetSP() < 5)
- return;
- m_me->PointChange(POINT_SP, -5);
- }
- iDam = CalcArrowDamage(m_me, pkVictim, pkBow, pkArrow);
- m_me->UseArrow(pkArrow, 1);
- // check speed hack
- DWORD dwCurrentTime = get_dword_time();
- if (IS_SPEED_HACK(m_me, pkVictim, dwCurrentTime))
- iDam = 0;
- }
- else
- iDam = CalcMeleeDamage(m_me, pkVictim);
- NormalAttackAffect(m_me, pkVictim);
- // µĄąĚÁö °č»ę
- iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_BOW)) / 100;
- //sys_log(0, "%s arrow %s dam %d", m_me->GetName(), pkVictim->GetName(), iDam);
- m_me->OnMove(true);
- pkVictim->OnMove();
- if (pkVictim->CanBeginFight())
- pkVictim->BeginFight(m_me);
- pkVictim->Damage(m_me, iDam, DAMAGE_TYPE_NORMAL_RANGE);
- // Ÿ°Ýġ °č»ęşÎ łˇ
- }
- break;
- case 1: // ŔĎąÝ ¸¶ąý
- {
- int iDam;
- if (m_me->IsPC())
- return;
- iDam = CalcMagicDamage(m_me, pkVictim);
- NormalAttackAffect(m_me, pkVictim);
- // µĄąĚÁö °č»ę
- #ifdef ENABLE_MAGIC_REDUCTION_SYSTEM
- const int resist_magic = MINMAX(0, pkVictim->GetPoint(POINT_RESIST_MAGIC), 100);
- const int resist_magic_reduction = MINMAX(0, (m_me->GetJob()==JOB_SURA) ? m_me->GetPoint(POINT_RESIST_MAGIC_REDUCTION)/2 : m_me->GetPoint(POINT_RESIST_MAGIC_REDUCTION), 50);
- const int total_res_magic = MINMAX(0, resist_magic - resist_magic_reduction, 100);
- iDam = iDam * (100 - total_res_magic) / 100;
- #else
- iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_MAGIC)) / 100;
- #endif
- //sys_log(0, "%s arrow %s dam %d", m_me->GetName(), pkVictim->GetName(), iDam);
- m_me->OnMove(true);
- pkVictim->OnMove();
- if (pkVictim->CanBeginFight())
- pkVictim->BeginFight(m_me);
- pkVictim->Damage(m_me, iDam, DAMAGE_TYPE_MAGIC);
- // Ÿ°Ýġ °č»ęşÎ łˇ
- }
- break;
- case SKILL_YEONSA: // ż¬»ç
- {
- //int iUseArrow = 2 + (m_me->GetSkillPower(SKILL_YEONSA) *6/100);
- int iUseArrow = 1;
- // ĹäĹ»¸¸ °č»ęÇϴ°ćżě
- {
- if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
- {
- m_me->OnMove(true);
- pkVictim->OnMove();
- if (pkVictim->CanBeginFight())
- pkVictim->BeginFight(m_me);
- m_me->ComputeSkill(m_bType, pkVictim);
- m_me->UseArrow(pkArrow, iUseArrow);
- if (pkVictim->IsDead())
- break;
- }
- else
- break;
- }
- }
- break;
- case SKILL_KWANKYEOK:
- {
- int iUseArrow = 1;
- if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
- {
- m_me->OnMove(true);
- pkVictim->OnMove();
- if (pkVictim->CanBeginFight())
- pkVictim->BeginFight(m_me);
- sys_log(0, "%s kwankeyok %s", m_me->GetName(), pkVictim->GetName());
- m_me->ComputeSkill(m_bType, pkVictim);
- m_me->UseArrow(pkArrow, iUseArrow);
- }
- }
- break;
- case SKILL_GIGUNG:
- {
- int iUseArrow = 1;
- if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
- {
- m_me->OnMove(true);
- pkVictim->OnMove();
- if (pkVictim->CanBeginFight())
- pkVictim->BeginFight(m_me);
- sys_log(0, "%s gigung %s", m_me->GetName(), pkVictim->GetName());
- m_me->ComputeSkill(m_bType, pkVictim);
- m_me->UseArrow(pkArrow, iUseArrow);
- }
- }
- break;
- case SKILL_HWAJO:
- {
- int iUseArrow = 1;
- if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
- {
- m_me->OnMove(true);
- pkVictim->OnMove();
- if (pkVictim->CanBeginFight())
- pkVictim->BeginFight(m_me);
- sys_log(0, "%s hwajo %s", m_me->GetName(), pkVictim->GetName());
- m_me->ComputeSkill(m_bType, pkVictim);
- m_me->UseArrow(pkArrow, iUseArrow);
- }
- }
- break;
- case SKILL_HORSE_WILDATTACK_RANGE:
- {
- int iUseArrow = 1;
- if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
- {
- m_me->OnMove(true);
- pkVictim->OnMove();
- if (pkVictim->CanBeginFight())
- pkVictim->BeginFight(m_me);
- sys_log(0, "%s horse_wildattack %s", m_me->GetName(), pkVictim->GetName());
- m_me->ComputeSkill(m_bType, pkVictim);
- m_me->UseArrow(pkArrow, iUseArrow);
- }
- }
- break;
- case SKILL_MARYUNG:
- //case SKILL_GUMHWAN:
- case SKILL_TUSOK:
- case SKILL_BIPABU:
- case SKILL_NOEJEON:
- case SKILL_GEOMPUNG:
- case SKILL_SANGONG:
- case SKILL_MAHWAN:
- case SKILL_PABEOB:
- //case SKILL_CURSE:
- {
- m_me->OnMove(true);
- pkVictim->OnMove();
- if (pkVictim->CanBeginFight())
- pkVictim->BeginFight(m_me);
- sys_log(0, "%s - Skill %d -> %s", m_me->GetName(), m_bType, pkVictim->GetName());
- m_me->ComputeSkill(m_bType, pkVictim);
- }
- break;
- case SKILL_CHAIN:
- {
- m_me->OnMove(true);
- pkVictim->OnMove();
- if (pkVictim->CanBeginFight())
- pkVictim->BeginFight(m_me);
- sys_log(0, "%s - Skill %d -> %s", m_me->GetName(), m_bType, pkVictim->GetName());
- m_me->ComputeSkill(m_bType, pkVictim);
- // TODO ż©·Ż¸íżˇ°Ô ˝µ ˝µ ˝µ Çϱâ
- }
- break;
- case SKILL_YONGBI:
- {
- m_me->OnMove(true);
- }
- break;
- /*case SKILL_BUDONG:
- {
- m_me->OnMove(true);
- pkVictim->OnMove();
- DWORD * pdw;
- DWORD dwEI = AllocEventInfo(sizeof(DWORD) * 2, &pdw);
- pdw[0] = m_me->GetVID();
- pdw[1] = pkVictim->GetVID();
- event_create(budong_event_func, dwEI, PASSES_PER_SEC(1));
- }
- break;*/
- default:
- sys_err("CFuncShoot: I don't know this type [%d] of range attack.", (int) m_bType);
- break;
- }
- m_bSucceed = TRUE;
- }
- };
- bool CHARACTER::Shoot(BYTE bType)
- {
- sys_log(1, "Shoot %s type %u flyTargets.size %zu", GetName(), bType, m_vec_dwFlyTargets.size());
- if (!CanMove())
- {
- return false;
- }
- CFuncShoot f(this, bType);
- if (m_dwFlyTargetID != 0)
- {
- f(m_dwFlyTargetID);
- m_dwFlyTargetID = 0;
- }
- f = std::for_each(m_vec_dwFlyTargets.begin(), m_vec_dwFlyTargets.end(), f);
- m_vec_dwFlyTargets.clear();
- return f.m_bSucceed;
- }
- void CHARACTER::FlyTarget(DWORD dwTargetVID, long x, long y, BYTE bHeader)
- {
- LPCHARACTER pkVictim = CHARACTER_MANAGER::instance().Find(dwTargetVID);
- TPacketGCFlyTargeting pack;
- //pack.bHeader = HEADER_GC_FLY_TARGETING;
- pack.bHeader = (bHeader == HEADER_CG_FLY_TARGETING) ? HEADER_GC_FLY_TARGETING : HEADER_GC_ADD_FLY_TARGETING;
- pack.dwShooterVID = GetVID();
- if (pkVictim)
- {
- pack.dwTargetVID = pkVictim->GetVID();
- pack.x = pkVictim->GetX();
- pack.y = pkVictim->GetY();
- if (bHeader == HEADER_CG_FLY_TARGETING)
- m_dwFlyTargetID = dwTargetVID;
- else
- m_vec_dwFlyTargets.push_back(dwTargetVID);
- }
- else
- {
- pack.dwTargetVID = 0;
- pack.x = x;
- pack.y = y;
- }
- sys_log(1, "FlyTarget %s vid %d x %d y %d", GetName(), pack.dwTargetVID, pack.x, pack.y);
- PacketAround(&pack, sizeof(pack), this);
- }
- LPCHARACTER CHARACTER::GetNearestVictim(LPCHARACTER pkChr)
- {
- if (NULL == pkChr)
- pkChr = this;
- float fMinDist = 99999.0f;
- LPCHARACTER pkVictim = NULL;
- TDamageMap::iterator it = m_map_kDamage.begin();
- // ŔĎ´Ü ÁÖŔ§żˇ ľř´Â »ç¶÷Ŕ» °É·Ż ł˝´Ů.
- while (it != m_map_kDamage.end())
- {
- const VID & c_VID = it->first;
- ++it;
- LPCHARACTER pAttacker = CHARACTER_MANAGER::instance().Find(c_VID);
- if (!pAttacker)
- continue;
- if (pAttacker->IsAffectFlag(AFF_EUNHYUNG) ||
- pAttacker->IsAffectFlag(AFF_INVISIBILITY) ||
- pAttacker->IsAffectFlag(AFF_REVIVE_INVISIBLE))
- continue;
- float fDist = DISTANCE_APPROX(pAttacker->GetX() - pkChr->GetX(), pAttacker->GetY() - pkChr->GetY());
- if (fDist < fMinDist)
- {
- pkVictim = pAttacker;
- fMinDist = fDist;
- }
- }
- return pkVictim;
- }
- void CHARACTER::SetVictim(LPCHARACTER pkVictim)
- {
- if (!pkVictim)
- {
- if (0 != (DWORD)m_kVIDVictim)
- MonsterLog("°ř°Ý ´ë»óŔ» ÇŘÁ¦");
- m_kVIDVictim.Reset();
- battle_end(this);
- }
- else
- {
- if (m_kVIDVictim != pkVictim->GetVID())
- MonsterLog("°ř°Ý ´ë»óŔ» ĽłÁ¤: %s", pkVictim->GetName());
- m_kVIDVictim = pkVictim->GetVID();
- m_dwLastVictimSetTime = get_dword_time();
- }
- }
- LPCHARACTER CHARACTER::GetVictim() const
- {
- return CHARACTER_MANAGER::instance().Find(m_kVIDVictim);
- }
- LPCHARACTER CHARACTER::GetProtege() const // ş¸ČŁÇŘľß ÇŇ ´ë»óŔ» ¸®ĹĎ
- {
- if (m_pkChrStone)
- return m_pkChrStone;
- if (m_pkParty)
- return m_pkParty->GetLeader();
- return NULL;
- }
- int CHARACTER::GetAlignment() const
- {
- return m_iAlignment;
- }
- int CHARACTER::GetRealAlignment() const
- {
- return m_iRealAlignment;
- }
- void CHARACTER::ShowAlignment(bool bShow)
- {
- if (bShow)
- {
- if (m_iAlignment != m_iRealAlignment)
- {
- m_iAlignment = m_iRealAlignment;
- UpdatePacket();
- }
- }
- else
- {
- if (m_iAlignment != 0)
- {
- m_iAlignment = 0;
- UpdatePacket();
- }
- }
- }
- void CHARACTER::UpdateAlignment(int iAmount)
- {
- bool bShow = false;
- if (m_iAlignment == m_iRealAlignment)
- bShow = true;
- int i = m_iAlignment / 10;
- m_iRealAlignment = MINMAX(-200000, m_iRealAlignment + iAmount, 200000);
- if (bShow)
- {
- m_iAlignment = m_iRealAlignment;
- if (i != m_iAlignment / 10)
- UpdatePacket();
- }
- }
- void CHARACTER::SetKillerMode(bool isOn)
- {
- if ((isOn ? ADD_CHARACTER_STATE_KILLER : 0) == IS_SET(m_bAddChrState, ADD_CHARACTER_STATE_KILLER))
- return;
- if (isOn)
- SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_KILLER);
- else
- REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_KILLER);
- m_iKillerModePulse = thecore_pulse();
- UpdatePacket();
- sys_log(0, "SetKillerMode Update %s[%d]", GetName(), GetPlayerID());
- }
- bool CHARACTER::IsKillerMode() const
- {
- return IS_SET(m_bAddChrState, ADD_CHARACTER_STATE_KILLER);
- }
- void CHARACTER::UpdateKillerMode()
- {
- if (!IsKillerMode())
- return;
- if (thecore_pulse() - m_iKillerModePulse >= PASSES_PER_SEC(30))
- SetKillerMode(false);
- }
- void CHARACTER::SetPKMode(BYTE bPKMode)
- {
- if (bPKMode >= PK_MODE_MAX_NUM)
- return;
- if (m_bPKMode == bPKMode)
- return;
- if (bPKMode == PK_MODE_GUILD && !GetGuild())
- bPKMode = PK_MODE_FREE;
- m_bPKMode = bPKMode;
- UpdatePacket();
- sys_log(0, "PK_MODE: %s %d", GetName(), m_bPKMode);
- }
- BYTE CHARACTER::GetPKMode() const
- {
- return m_bPKMode;
- }
- struct FuncForgetMyAttacker
- {
- LPCHARACTER m_ch;
- FuncForgetMyAttacker(LPCHARACTER ch)
- {
- m_ch = ch;
- }
- void operator()(LPENTITY ent)
- {
- if (ent->IsType(ENTITY_CHARACTER))
- {
- LPCHARACTER ch = (LPCHARACTER) ent;
- if (ch->IsPC())
- return;
- if (ch->m_kVIDVictim == m_ch->GetVID())
- ch->SetVictim(NULL);
- }
- }
- };
- struct FuncAggregateMonster
- {
- LPCHARACTER m_ch;
- FuncAggregateMonster(LPCHARACTER ch)
- {
- m_ch = ch;
- }
- void operator()(LPENTITY ent)
- {
- if (ent->IsType(ENTITY_CHARACTER))
- {
- LPCHARACTER ch = (LPCHARACTER) ent;
- if (ch->IsPC())
- return;
- if (!ch->IsMonster())
- return;
- if (ch->GetVictim())
- return;
- if (number(1, 100) <= 50) // Ŕӽ÷Π50% Č®·ü·Î ŔűŔ» ˛řľîżÂ´Ů
- if (DISTANCE_APPROX(ch->GetX() - m_ch->GetX(), ch->GetY() - m_ch->GetY()) < 5000)
- if (ch->CanBeginFight())
- ch->BeginFight(m_ch);
- }
- }
- };
- struct FuncAttractRanger
- {
- LPCHARACTER m_ch;
- FuncAttractRanger(LPCHARACTER ch)
- {
- m_ch = ch;
- }
- void operator()(LPENTITY ent)
- {
- if (ent->IsType(ENTITY_CHARACTER))
- {
- LPCHARACTER ch = (LPCHARACTER) ent;
- if (ch->IsPC())
- return;
- if (!ch->IsMonster())
- return;
- if (ch->GetVictim() && ch->GetVictim() != m_ch)
- return;
- if (ch->GetMobAttackRange() > 150)
- {
- int iNewRange = 150;//(int)(ch->GetMobAttackRange() * 0.2);
- if (iNewRange < 150)
- iNewRange = 150;
- ch->AddAffect(AFFECT_BOW_DISTANCE, POINT_BOW_DISTANCE, iNewRange - ch->GetMobAttackRange(), AFF_NONE, 3*60, 0, false);
- }
- }
- }
- };
- struct FuncPullMonster
- {
- LPCHARACTER m_ch;
- int m_iLength;
- FuncPullMonster(LPCHARACTER ch, int iLength = 300)
- {
- m_ch = ch;
- m_iLength = iLength;
- }
- void operator()(LPENTITY ent)
- {
- if (ent->IsType(ENTITY_CHARACTER))
- {
- LPCHARACTER ch = (LPCHARACTER) ent;
- if (ch->IsPC())
- return;
- if (!ch->IsMonster())
- return;
- //if (ch->GetVictim() && ch->GetVictim() != m_ch)
- //return;
- float fDist = DISTANCE_APPROX(m_ch->GetX() - ch->GetX(), m_ch->GetY() - ch->GetY());
- if (fDist > 3000 || fDist < 100)
- return;
- float fNewDist = fDist - m_iLength;
- if (fNewDist < 100)
- fNewDist = 100;
- float degree = GetDegreeFromPositionXY(ch->GetX(), ch->GetY(), m_ch->GetX(), m_ch->GetY());
- float fx;
- float fy;
- GetDeltaByDegree(degree, fDist - fNewDist, &fx, &fy);
- long tx = (long)(ch->GetX() + fx);
- long ty = (long)(ch->GetY() + fy);
- ch->Sync(tx, ty);
- ch->Goto(tx, ty);
- ch->CalculateMoveDuration();
- ch->SyncPacket();
- }
- }
- };
- void CHARACTER::ForgetMyAttacker()
- {
- LPSECTREE pSec = GetSectree();
- if (pSec)
- {
- FuncForgetMyAttacker f(this);
- pSec->ForEachAround(f);
- }
- ReviveInvisible(5);
- }
- void CHARACTER::AggregateMonster()
- {
- LPSECTREE pSec = GetSectree();
- if (pSec)
- {
- FuncAggregateMonster f(this);
- pSec->ForEachAround(f);
- #ifdef ENABLE_AGGREGATE_MONSTER_EFFECT
- EffectPacket(SE_AGGREGATE_MONSTER_EFFECT);
- #endif
- }
- }
- void CHARACTER::AttractRanger()
- {
- LPSECTREE pSec = GetSectree();
- if (pSec)
- {
- FuncAttractRanger f(this);
- pSec->ForEachAround(f);
- }
- }
- void CHARACTER::PullMonster()
- {
- LPSECTREE pSec = GetSectree();
- if (pSec)
- {
- FuncPullMonster f(this);
- pSec->ForEachAround(f);
- }
- }
- void CHARACTER::UpdateAggrPointEx(LPCHARACTER pAttacker, EDamageType type, int dam, CHARACTER::TBattleInfo & info)
- {
- // ĆŻÁ¤ °ř°ÝŸŔÔżˇ µű¶ó ´ő żĂ¶ó°Ł´Ů
- switch (type)
- {
- case DAMAGE_TYPE_NORMAL_RANGE:
- dam = (int) (dam*1.2f);
- break;
- case DAMAGE_TYPE_RANGE:
- dam = (int) (dam*1.5f);
- break;
- case DAMAGE_TYPE_MAGIC:
- dam = (int) (dam*1.2f);
- break;
- default:
- break;
- }
- // °ř°ÝŔÚ°ˇ ÇöŔç ´ë»óŔÎ °ćżě ş¸łĘ˝ş¸¦ ÁŘ´Ů.
- if (pAttacker == GetVictim())
- dam = (int) (dam * 1.2f);
- info.iAggro += dam;
- if (info.iAggro < 0)
- info.iAggro = 0;
- //sys_log(0, "UpdateAggrPointEx for %s by %s dam %d total %d", GetName(), pAttacker->GetName(), dam, total);
- if (GetParty() && dam > 0 && type != DAMAGE_TYPE_SPECIAL)
- {
- LPPARTY pParty = GetParty();
- // ¸®´őŔÎ °ćżě żµÇâ·ÂŔĚ Á»´ő °ÇĎ´Ů
- int iPartyAggroDist = dam;
- if (pParty->GetLeaderPID() == GetVID())
- iPartyAggroDist /= 2;
- else
- iPartyAggroDist /= 3;
- pParty->SendMessage(this, PM_AGGRO_INCREASE, iPartyAggroDist, pAttacker->GetVID());
- }
- ChangeVictimByAggro(info.iAggro, pAttacker);
- }
- void CHARACTER::UpdateAggrPoint(LPCHARACTER pAttacker, EDamageType type, int dam)
- {
- if (IsDead() || IsStun())
- return;
- TDamageMap::iterator it = m_map_kDamage.find(pAttacker->GetVID());
- if (it == m_map_kDamage.end())
- {
- m_map_kDamage.insert(TDamageMap::value_type(pAttacker->GetVID(), TBattleInfo(0, dam)));
- it = m_map_kDamage.find(pAttacker->GetVID());
- }
- UpdateAggrPointEx(pAttacker, type, dam, it->second);
- }
- void CHARACTER::ChangeVictimByAggro(int iNewAggro, LPCHARACTER pNewVictim)
- {
- if (get_dword_time() - m_dwLastVictimSetTime < 3000) // 3ĂĘ´Â ±â´Ů·ÁľßÇŃ´Ů
- return;
- if (pNewVictim == GetVictim())
- {
- if (m_iMaxAggro < iNewAggro)
- {
- m_iMaxAggro = iNewAggro;
- return;
- }
- // Aggro°ˇ °¨ĽŇÇŃ °ćżě
- TDamageMap::iterator it;
- TDamageMap::iterator itFind = m_map_kDamage.end();
- for (it = m_map_kDamage.begin(); it != m_map_kDamage.end(); ++it)
- {
- if (it->second.iAggro > iNewAggro)
- {
- LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(it->first);
- if (ch && !ch->IsDead() && DISTANCE_APPROX(ch->GetX() - GetX(), ch->GetY() - GetY()) < 5000)
- {
- itFind = it;
- iNewAggro = it->second.iAggro;
- }
- }
- }
- if (itFind != m_map_kDamage.end())
- {
- m_iMaxAggro = iNewAggro;
- SetVictim(CHARACTER_MANAGER::instance().Find(itFind->first));
- m_dwStateDuration = 1;
- }
- }
- else
- {
- if (m_iMaxAggro < iNewAggro)
- {
- m_iMaxAggro = iNewAggro;
- SetVictim(pNewVictim);
- m_dwStateDuration = 1;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement