1
0
forked from metin2/server
server/game/src/char_manager.cpp

1113 lines
26 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "stdafx.h"
#include "constants.h"
#include "utils.h"
#include "desc.h"
#include "char.h"
#include "char_manager.h"
#include "mob_manager.h"
#include "party.h"
#include "regen.h"
#include "p2p.h"
#include "dungeon.h"
#include "db.h"
#include "config.h"
#include "xmas_event.h"
#include "questmanager.h"
#include "questlua.h"
#include "locale_service.h"
#ifndef __GNUC__
#include <boost/bind.hpp>
#endif
CHARACTER_MANAGER::CHARACTER_MANAGER() :
m_iVIDCount(0),
m_pkChrSelectedStone(NULL),
m_bUsePendingDestroy(false)
{
RegisterRaceNum(xmas::MOB_XMAS_FIRWORK_SELLER_VNUM);
RegisterRaceNum(xmas::MOB_SANTA_VNUM);
RegisterRaceNum(xmas::MOB_XMAS_TREE_VNUM);
m_iMobItemRate = 100;
m_iMobDamageRate = 100;
m_iMobGoldAmountRate = 100;
m_iMobGoldDropRate = 100;
m_iMobExpRate = 100;
m_iMobItemRatePremium = 100;
m_iMobGoldAmountRatePremium = 100;
m_iMobGoldDropRatePremium = 100;
m_iMobExpRatePremium = 100;
m_iUserDamageRate = 100;
m_iUserDamageRatePremium = 100;
}
CHARACTER_MANAGER::~CHARACTER_MANAGER()
{
Destroy();
}
void CHARACTER_MANAGER::Destroy()
{
itertype(m_map_pkChrByVID) it = m_map_pkChrByVID.begin();
while (it != m_map_pkChrByVID.end()) {
LPCHARACTER ch = it->second;
M2_DESTROY_CHARACTER(ch); // m_map_pkChrByVID is changed here
it = m_map_pkChrByVID.begin();
}
}
void CHARACTER_MANAGER::GracefulShutdown()
{
NAME_MAP::iterator it = m_map_pkPCChr.begin();
while (it != m_map_pkPCChr.end())
(it++)->second->Disconnect("GracefulShutdown");
}
DWORD CHARACTER_MANAGER::AllocVID()
{
++m_iVIDCount;
return m_iVIDCount;
}
LPCHARACTER CHARACTER_MANAGER::CreateCharacter(const char * name, DWORD dwPID)
{
DWORD dwVID = AllocVID();
#ifdef M2_USE_POOL
LPCHARACTER ch = pool_.Construct();
#else
LPCHARACTER ch = M2_NEW CHARACTER;
#endif
ch->Create(name, dwVID, dwPID ? true : false);
m_map_pkChrByVID.insert(std::make_pair(dwVID, ch));
if (dwPID)
{
char szName[CHARACTER_NAME_MAX_LEN + 1];
str_lower(name, szName, sizeof(szName));
m_map_pkPCChr.insert(NAME_MAP::value_type(szName, ch));
m_map_pkChrByPID.insert(std::make_pair(dwPID, ch));
}
return (ch);
}
#ifndef DEBUG_ALLOC
void CHARACTER_MANAGER::DestroyCharacter(LPCHARACTER ch)
#else
void CHARACTER_MANAGER::DestroyCharacter(LPCHARACTER ch, const char* file, size_t line)
#endif
{
if (!ch)
return;
// <Factor> Check whether it has been already deleted or not.
itertype(m_map_pkChrByVID) it = m_map_pkChrByVID.find(ch->GetVID());
if (it == m_map_pkChrByVID.end()) {
sys_err("[CHARACTER_MANAGER::DestroyCharacter] <Factor> %d not found", (int)(ch->GetVID()));
return; // prevent duplicated destrunction
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ҽӵ<D2BC> <20><><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD><CFB5><EFBFBD>.
if (ch->IsNPC() && !ch->IsPet() && ch->GetRider() == NULL)
{
if (ch->GetDungeon())
{
ch->GetDungeon()->DeadCharacter(ch);
}
}
if (m_bUsePendingDestroy)
{
m_set_pkChrPendingDestroy.insert(ch);
return;
}
m_map_pkChrByVID.erase(it);
if (true == ch->IsPC())
{
char szName[CHARACTER_NAME_MAX_LEN + 1];
str_lower(ch->GetName(), szName, sizeof(szName));
NAME_MAP::iterator it = m_map_pkPCChr.find(szName);
if (m_map_pkPCChr.end() != it)
m_map_pkPCChr.erase(it);
}
if (0 != ch->GetPlayerID())
{
itertype(m_map_pkChrByPID) it = m_map_pkChrByPID.find(ch->GetPlayerID());
if (m_map_pkChrByPID.end() != it)
{
m_map_pkChrByPID.erase(it);
}
}
UnregisterRaceNumMap(ch);
RemoveFromStateList(ch);
#ifdef M2_USE_POOL
pool_.Destroy(ch);
#else
#ifndef DEBUG_ALLOC
M2_DELETE(ch);
#else
M2_DELETE_EX(ch, file, line);
#endif
#endif
}
LPCHARACTER CHARACTER_MANAGER::Find(DWORD dwVID)
{
itertype(m_map_pkChrByVID) it = m_map_pkChrByVID.find(dwVID);
if (m_map_pkChrByVID.end() == it)
return NULL;
// <Factor> Added sanity check
LPCHARACTER found = it->second;
if (found != NULL && dwVID != (DWORD)found->GetVID()) {
sys_err("[CHARACTER_MANAGER::Find] <Factor> %u != %u", dwVID, (DWORD)found->GetVID());
return NULL;
}
return found;
}
LPCHARACTER CHARACTER_MANAGER::Find(const VID & vid)
{
LPCHARACTER tch = Find((DWORD) vid);
if (!tch || tch->GetVID() != vid)
return NULL;
return tch;
}
LPCHARACTER CHARACTER_MANAGER::FindByPID(DWORD dwPID)
{
itertype(m_map_pkChrByPID) it = m_map_pkChrByPID.find(dwPID);
if (m_map_pkChrByPID.end() == it)
return NULL;
// <Factor> Added sanity check
LPCHARACTER found = it->second;
if (found != NULL && dwPID != found->GetPlayerID()) {
sys_err("[CHARACTER_MANAGER::FindByPID] <Factor> %u != %u", dwPID, found->GetPlayerID());
return NULL;
}
return found;
}
LPCHARACTER CHARACTER_MANAGER::FindPC(const char * name)
{
char szName[CHARACTER_NAME_MAX_LEN + 1];
str_lower(name, szName, sizeof(szName));
NAME_MAP::iterator it = m_map_pkPCChr.find(szName);
if (it == m_map_pkPCChr.end())
return NULL;
// <Factor> Added sanity check
LPCHARACTER found = it->second;
if (found != NULL && strncasecmp(szName, found->GetName(), CHARACTER_NAME_MAX_LEN) != 0) {
sys_err("[CHARACTER_MANAGER::FindPC] <Factor> %s != %s", name, found->GetName());
return NULL;
}
return found;
}
LPCHARACTER CHARACTER_MANAGER::SpawnMobRandomPosition(DWORD dwVnum, int lMapIndex)
{
// <20>ֱ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20>ְ<EFBFBD><D6B0><EFBFBD>
{
if (dwVnum == 5001 && !quest::CQuestManager::instance().GetEventFlag("japan_regen"))
{
sys_log(1, "WAEGU[5001] regen disabled.");
return NULL;
}
}
// <20><><EFBFBD>¸<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20>ְ<EFBFBD> <20><>
{
if (dwVnum == 5002 && !quest::CQuestManager::instance().GetEventFlag("newyear_mob"))
{
sys_log(1, "HAETAE (new-year-mob) [5002] regen disabled.");
return NULL;
}
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>̺<EFBFBD>Ʈ
{
if (dwVnum == 5004 && !quest::CQuestManager::instance().GetEventFlag("independence_day"))
{
sys_log(1, "INDEPENDECE DAY [5004] regen disabled.");
return NULL;
}
}
const CMob * pkMob = CMobManager::instance().Get(dwVnum);
if (!pkMob)
{
sys_err("no mob data for vnum %u", dwVnum);
return NULL;
}
if (!map_allow_find(lMapIndex))
{
sys_err("not allowed map %u", lMapIndex);
return NULL;
}
LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(lMapIndex);
if (pkSectreeMap == NULL) {
return NULL;
}
int i;
int x, y;
for (i=0; i<2000; i++)
{
x = Random::get(1, (pkSectreeMap->m_setting.iWidth / 100) - 1) * 100 + pkSectreeMap->m_setting.iBaseX;
y = Random::get(1, (pkSectreeMap->m_setting.iHeight / 100) - 1) * 100 + pkSectreeMap->m_setting.iBaseY;
//LPSECTREE tree = SECTREE_MANAGER::instance().Get(lMapIndex, x, y);
LPSECTREE tree = pkSectreeMap->Find(x, y);
if (!tree)
continue;
DWORD dwAttr = tree->GetAttribute(x, y);
if (IS_SET(dwAttr, ATTR_BLOCK | ATTR_OBJECT))
continue;
if (IS_SET(dwAttr, ATTR_BANPK))
continue;
break;
}
if (i == 2000)
{
sys_err("cannot find valid location");
return NULL;
}
LPSECTREE sectree = SECTREE_MANAGER::instance().Get(lMapIndex, x, y);
if (!sectree)
{
sys_log(0, "SpawnMobRandomPosition: cannot create monster at non-exist sectree %d x %d (map %d)", x, y, lMapIndex);
return NULL;
}
LPCHARACTER ch = CHARACTER_MANAGER::instance().CreateCharacter(pkMob->m_table.szLocaleName);
if (!ch)
{
sys_log(0, "SpawnMobRandomPosition: cannot create new character");
return NULL;
}
ch->SetProto(pkMob);
// if mob is npc with no empire assigned, assign to empire of map
if (pkMob->m_table.bType == CHAR_TYPE_NPC)
if (ch->GetEmpire() == 0)
ch->SetEmpire(SECTREE_MANAGER::instance().GetEmpireFromMapIndex(lMapIndex));
ch->SetRotation(Random::get(0, 360));
if (!ch->Show(lMapIndex, x, y, 0, false))
{
M2_DESTROY_CHARACTER(ch);
sys_err(0, "SpawnMobRandomPosition: cannot show monster");
return NULL;
}
char buf[512+1];
int local_x = x - pkSectreeMap->m_setting.iBaseX;
int local_y = y - pkSectreeMap->m_setting.iBaseY;
snprintf(buf, sizeof(buf), "spawn %s[%d] random position at %d %d %d %d (time: %ld)", ch->GetName(), dwVnum, x, y, local_x, local_y, get_global_time());
if (test_server)
SendNotice(buf);
sys_log(0, buf);
return (ch);
}
LPCHARACTER CHARACTER_MANAGER::SpawnMob(DWORD dwVnum, int lMapIndex, int x, int y, int z, bool bSpawnMotion, int iRot, bool bShow)
{
const CMob * pkMob = CMobManager::instance().Get(dwVnum);
if (!pkMob)
{
sys_err("SpawnMob: no mob data for vnum %u", dwVnum);
return NULL;
}
if (!(pkMob->m_table.bType == CHAR_TYPE_NPC || pkMob->m_table.bType == CHAR_TYPE_WARP || pkMob->m_table.bType == CHAR_TYPE_GOTO) || mining::IsVeinOfOre (dwVnum))
{
LPSECTREE tree = SECTREE_MANAGER::instance().Get(lMapIndex, x, y);
if (!tree)
{
sys_log(0, "no sectree for spawn at %d %d mobvnum %d mapindex %d", x, y, dwVnum, lMapIndex);
return NULL;
}
DWORD dwAttr = tree->GetAttribute(x, y);
bool is_set = false;
if ( mining::IsVeinOfOre (dwVnum) ) is_set = IS_SET(dwAttr, ATTR_BLOCK);
else is_set = IS_SET(dwAttr, ATTR_BLOCK | ATTR_OBJECT);
if ( is_set )
{
// SPAWN_BLOCK_LOG
static bool s_isLog=quest::CQuestManager::instance().GetEventFlag("spawn_block_log");
static DWORD s_nextTime=get_global_time()+10000;
DWORD curTime=get_global_time();
if (curTime>s_nextTime)
{
s_nextTime=curTime;
s_isLog=quest::CQuestManager::instance().GetEventFlag("spawn_block_log");
}
if (s_isLog)
sys_log(0, "SpawnMob: BLOCKED position for spawn %s %u at %d %d (attr %u)", pkMob->m_table.szName, dwVnum, x, y, dwAttr);
// END_OF_SPAWN_BLOCK_LOG
return NULL;
}
if (IS_SET(dwAttr, ATTR_BANPK))
{
sys_log(0, "SpawnMob: BAN_PK position for mob spawn %s %u at %d %d", pkMob->m_table.szName, dwVnum, x, y);
return NULL;
}
}
LPSECTREE sectree = SECTREE_MANAGER::instance().Get(lMapIndex, x, y);
if (!sectree)
{
sys_log(0, "SpawnMob: cannot create monster at non-exist sectree %d x %d (map %d)", x, y, lMapIndex);
return NULL;
}
LPCHARACTER ch = CHARACTER_MANAGER::instance().CreateCharacter(pkMob->m_table.szLocaleName);
if (!ch)
{
sys_log(0, "SpawnMob: cannot create new character");
return NULL;
}
if (iRot == -1)
iRot = Random::get(0, 360);
ch->SetProto(pkMob);
// if mob is npc with no empire assigned, assign to empire of map
if (pkMob->m_table.bType == CHAR_TYPE_NPC)
if (ch->GetEmpire() == 0)
ch->SetEmpire(SECTREE_MANAGER::instance().GetEmpireFromMapIndex(lMapIndex));
ch->SetRotation(iRot);
if (bShow && !ch->Show(lMapIndex, x, y, z, bSpawnMotion))
{
M2_DESTROY_CHARACTER(ch);
sys_log(0, "SpawnMob: cannot show monster");
return NULL;
}
return (ch);
}
LPCHARACTER CHARACTER_MANAGER::SpawnMobRange(DWORD dwVnum, int lMapIndex, int sx, int sy, int ex, int ey, bool bIsException, bool bSpawnMotion, bool bAggressive )
{
const CMob * pkMob = CMobManager::instance().Get(dwVnum);
if (!pkMob)
return NULL;
if (pkMob->m_table.bType == CHAR_TYPE_STONE) // <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SPAWN <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ִ<EFBFBD>.
bSpawnMotion = true;
int i = 16;
while (i--)
{
int x = Random::get(sx, ex);
int y = Random::get(sy, ey);
/*
if (bIsException)
if (is_regen_exception(x, y))
continue;
*/
LPCHARACTER ch = SpawnMob(dwVnum, lMapIndex, x, y, 0, bSpawnMotion);
if (ch)
{
sys_log(1, "MOB_SPAWN: %s(%d) %dx%d", ch->GetName(), (DWORD) ch->GetVID(), ch->GetX(), ch->GetY());
if ( bAggressive )
ch->SetAggressive();
return (ch);
}
}
return NULL;
}
void CHARACTER_MANAGER::SelectStone(LPCHARACTER pkChr)
{
m_pkChrSelectedStone = pkChr;
}
bool CHARACTER_MANAGER::SpawnMoveGroup(DWORD dwVnum, int lMapIndex, int sx, int sy, int ex, int ey, int tx, int ty, LPREGEN pkRegen, bool bAggressive_)
{
CMobGroup * pkGroup = CMobManager::Instance().GetGroup(dwVnum);
if (!pkGroup)
{
sys_err("NOT_EXIST_GROUP_VNUM(%u) Map(%u) ", dwVnum, lMapIndex);
return false;
}
LPCHARACTER pkChrMaster = NULL;
LPPARTY pkParty = NULL;
const std::vector<DWORD> & c_rdwMembers = pkGroup->GetMemberVector();
bool bSpawnedByStone = false;
bool bAggressive = bAggressive_;
if (m_pkChrSelectedStone)
{
bSpawnedByStone = true;
if (m_pkChrSelectedStone->GetDungeon())
bAggressive = true;
}
for (DWORD i = 0; i < c_rdwMembers.size(); ++i)
{
LPCHARACTER tch = SpawnMobRange(c_rdwMembers[i], lMapIndex, sx, sy, ex, ey, true, bSpawnedByStone);
if (!tch)
{
if (i == 0) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ͱ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><ECBFA1> <20>׳<EFBFBD> <20><><EFBFBD><EFBFBD>
return false;
continue;
}
sx = tch->GetX() - Random::get(300, 500);
sy = tch->GetY() - Random::get(300, 500);
ex = tch->GetX() + Random::get(300, 500);
ey = tch->GetY() + Random::get(300, 500);
if (m_pkChrSelectedStone)
tch->SetStone(m_pkChrSelectedStone);
else if (pkParty)
{
pkParty->Join(tch->GetVID());
pkParty->Link(tch);
}
else if (!pkChrMaster)
{
pkChrMaster = tch;
pkChrMaster->SetRegen(pkRegen);
pkParty = CPartyManager::instance().CreateParty(pkChrMaster);
}
if (bAggressive)
tch->SetAggressive();
if (tch->Goto(tx, ty))
tch->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
}
return true;
}
bool CHARACTER_MANAGER::SpawnGroupGroup(DWORD dwVnum, int lMapIndex, int sx, int sy, int ex, int ey, LPREGEN pkRegen, bool bAggressive_, LPDUNGEON pDungeon)
{
const DWORD dwGroupID = CMobManager::Instance().GetGroupFromGroupGroup(dwVnum);
if( dwGroupID != 0 )
{
return SpawnGroup(dwGroupID, lMapIndex, sx, sy, ex, ey, pkRegen, bAggressive_, pDungeon);
}
else
{
sys_err( "NOT_EXIST_GROUP_GROUP_VNUM(%u) MAP(%ld)", dwVnum, lMapIndex );
return false;
}
}
LPCHARACTER CHARACTER_MANAGER::SpawnGroup(DWORD dwVnum, int lMapIndex, int sx, int sy, int ex, int ey, LPREGEN pkRegen, bool bAggressive_, LPDUNGEON pDungeon)
{
CMobGroup * pkGroup = CMobManager::Instance().GetGroup(dwVnum);
if (!pkGroup)
{
sys_err("NOT_EXIST_GROUP_VNUM(%u) Map(%u) ", dwVnum, lMapIndex);
return NULL;
}
LPCHARACTER pkChrMaster = NULL;
LPPARTY pkParty = NULL;
const std::vector<DWORD> & c_rdwMembers = pkGroup->GetMemberVector();
bool bSpawnedByStone = false;
bool bAggressive = bAggressive_;
if (m_pkChrSelectedStone)
{
bSpawnedByStone = true;
if (m_pkChrSelectedStone->GetDungeon())
bAggressive = true;
}
LPCHARACTER chLeader = NULL;
for (DWORD i = 0; i < c_rdwMembers.size(); ++i)
{
LPCHARACTER tch = SpawnMobRange(c_rdwMembers[i], lMapIndex, sx, sy, ex, ey, true, bSpawnedByStone);
if (!tch)
{
if (i == 0) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ͱ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><ECBFA1> <20>׳<EFBFBD> <20><><EFBFBD><EFBFBD>
return NULL;
continue;
}
if (i == 0)
chLeader = tch;
tch->SetDungeon(pDungeon);
sx = tch->GetX() - Random::get(300, 500);
sy = tch->GetY() - Random::get(300, 500);
ex = tch->GetX() + Random::get(300, 500);
ey = tch->GetY() + Random::get(300, 500);
if (m_pkChrSelectedStone)
tch->SetStone(m_pkChrSelectedStone);
else if (pkParty)
{
pkParty->Join(tch->GetVID());
pkParty->Link(tch);
}
else if (!pkChrMaster)
{
pkChrMaster = tch;
pkChrMaster->SetRegen(pkRegen);
pkParty = CPartyManager::instance().CreateParty(pkChrMaster);
}
if (bAggressive)
tch->SetAggressive();
}
return chLeader;
}
struct FuncUpdateAndResetChatCounter
{
void operator () (LPCHARACTER ch)
{
ch->ResetChatCounter();
ch->CFSM::Update();
}
};
void CHARACTER_MANAGER::Update(int iPulse)
{
using namespace std;
#ifdef __GNUC__
using namespace __gnu_cxx;
#endif
BeginPendingDestroy();
// PC ij<><C4B3><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ʈ
{
if (!m_map_pkPCChr.empty())
{
// <20><><EFBFBD><EFBFBD><EFBFBD>̳<EFBFBD> <20><><EFBFBD><EFBFBD>
CHARACTER_VECTOR v;
v.reserve(m_map_pkPCChr.size());
#ifdef __GNUC__
transform(m_map_pkPCChr.begin(), m_map_pkPCChr.end(), back_inserter(v), select2nd<NAME_MAP::value_type>());
#else
transform(m_map_pkPCChr.begin(), m_map_pkPCChr.end(), back_inserter(v), boost::bind(&NAME_MAP::value_type::second, _1));
#endif
if (0 == (iPulse % PASSES_PER_SEC(5)))
{
FuncUpdateAndResetChatCounter f;
for_each(v.begin(), v.end(), f);
}
else
{
//for_each(v.begin(), v.end(), mem_fun(&CFSM::Update));
for_each(v.begin(), v.end(), bind2nd(mem_fun(&CHARACTER::UpdateCharacter), iPulse));
}
}
// for_each_pc(bind2nd(mem_fun(&CHARACTER::UpdateCharacter), iPulse));
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ʈ
{
if (!m_set_pkChrState.empty())
{
CHARACTER_VECTOR v;
v.reserve(m_set_pkChrState.size());
#ifdef __GNUC__
transform(m_set_pkChrState.begin(), m_set_pkChrState.end(), back_inserter(v), identity<CHARACTER_SET::value_type>());
#else
v.insert(v.end(), m_set_pkChrState.begin(), m_set_pkChrState.end());
#endif
for_each(v.begin(), v.end(), bind2nd(mem_fun(&CHARACTER::UpdateStateMachine), iPulse));
}
}
// <20><>Ÿ <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ʈ
{
CharacterVectorInteractor i;
if (CHARACTER_MANAGER::instance().GetCharactersByRaceNum(xmas::MOB_SANTA_VNUM, i))
{
for_each(i.begin(), i.end(),
bind2nd(mem_fun(&CHARACTER::UpdateStateMachine), iPulse));
}
}
// 1<>ð<EFBFBD><C3B0><EFBFBD> <20>ѹ<EFBFBD><D1B9><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
if (0 == (iPulse % PASSES_PER_SEC(3600)))
{
for (itertype(m_map_dwMobKillCount) it = m_map_dwMobKillCount.begin(); it != m_map_dwMobKillCount.end(); ++it)
DBManager::instance().SendMoneyLog(MONEY_LOG_MONSTER_KILL, it->first, it->second);
m_map_dwMobKillCount.clear();
}
// <20>׽<EFBFBD>Ʈ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 60<36>ʸ<EFBFBD><CAB8><EFBFBD> ij<><C4B3><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
if (test_server && 0 == (iPulse % PASSES_PER_SEC(60)))
sys_log(0, "CHARACTER COUNT vid %zu pid %zu", m_map_pkChrByVID.size(), m_map_pkChrByPID.size());
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> DestroyCharacter <20>ϱ<EFBFBD>
FlushPendingDestroy();
}
void CHARACTER_MANAGER::ProcessDelayedSave()
{
CHARACTER_SET::iterator it = m_set_pkChrForDelayedSave.begin();
while (it != m_set_pkChrForDelayedSave.end())
{
LPCHARACTER pkChr = *it++;
pkChr->SaveReal();
}
m_set_pkChrForDelayedSave.clear();
}
bool CHARACTER_MANAGER::AddToStateList(LPCHARACTER ch)
{
assert(ch != NULL);
CHARACTER_SET::iterator it = m_set_pkChrState.find(ch);
if (it == m_set_pkChrState.end())
{
m_set_pkChrState.insert(ch);
return true;
}
return false;
}
void CHARACTER_MANAGER::RemoveFromStateList(LPCHARACTER ch)
{
CHARACTER_SET::iterator it = m_set_pkChrState.find(ch);
if (it != m_set_pkChrState.end())
{
//sys_log(0, "RemoveFromStateList %p", ch);
m_set_pkChrState.erase(it);
}
}
void CHARACTER_MANAGER::DelayedSave(LPCHARACTER ch)
{
m_set_pkChrForDelayedSave.insert(ch);
}
bool CHARACTER_MANAGER::FlushDelayedSave(LPCHARACTER ch)
{
CHARACTER_SET::iterator it = m_set_pkChrForDelayedSave.find(ch);
if (it == m_set_pkChrForDelayedSave.end())
return false;
m_set_pkChrForDelayedSave.erase(it);
ch->SaveReal();
return true;
}
void CHARACTER_MANAGER::RegisterForMonsterLog(LPCHARACTER ch)
{
m_set_pkChrMonsterLog.insert(ch);
}
void CHARACTER_MANAGER::UnregisterForMonsterLog(LPCHARACTER ch)
{
m_set_pkChrMonsterLog.erase(ch);
}
void CHARACTER_MANAGER::PacketMonsterLog(LPCHARACTER ch, const void* buf, int size)
{
itertype(m_set_pkChrMonsterLog) it;
for (it = m_set_pkChrMonsterLog.begin(); it!=m_set_pkChrMonsterLog.end();++it)
{
LPCHARACTER c = *it;
if (ch && DISTANCE_APPROX(c->GetX()-ch->GetX(), c->GetY()-ch->GetY())>6000)
continue;
LPDESC d = c->GetDesc();
if (d)
d->Packet(buf, size);
}
}
void CHARACTER_MANAGER::KillLog(DWORD dwVnum)
{
const DWORD SEND_LIMIT = 10000;
itertype(m_map_dwMobKillCount) it = m_map_dwMobKillCount.find(dwVnum);
if (it == m_map_dwMobKillCount.end())
m_map_dwMobKillCount.insert(std::make_pair(dwVnum, 1));
else
{
++it->second;
if (it->second > SEND_LIMIT)
{
DBManager::instance().SendMoneyLog(MONEY_LOG_MONSTER_KILL, it->first, it->second);
m_map_dwMobKillCount.erase(it);
}
}
}
void CHARACTER_MANAGER::RegisterRaceNum(DWORD dwVnum)
{
m_set_dwRegisteredRaceNum.insert(dwVnum);
}
void CHARACTER_MANAGER::RegisterRaceNumMap(LPCHARACTER ch)
{
DWORD dwVnum = ch->GetRaceNum();
if (m_set_dwRegisteredRaceNum.find(dwVnum) != m_set_dwRegisteredRaceNum.end()) // <20><><EFBFBD>ϵ<EFBFBD> <20><>ȣ <20≯<EFBFBD>
{
sys_log(0, "RegisterRaceNumMap %s %u", ch->GetName(), dwVnum);
m_map_pkChrByRaceNum[dwVnum].insert(ch);
}
}
void CHARACTER_MANAGER::UnregisterRaceNumMap(LPCHARACTER ch)
{
DWORD dwVnum = ch->GetRaceNum();
itertype(m_map_pkChrByRaceNum) it = m_map_pkChrByRaceNum.find(dwVnum);
if (it != m_map_pkChrByRaceNum.end())
it->second.erase(ch);
}
bool CHARACTER_MANAGER::GetCharactersByRaceNum(DWORD dwRaceNum, CharacterVectorInteractor & i)
{
std::map<DWORD, CHARACTER_SET>::iterator it = m_map_pkChrByRaceNum.find(dwRaceNum);
if (it == m_map_pkChrByRaceNum.end())
return false;
// <20><><EFBFBD><EFBFBD><EFBFBD>̳<EFBFBD> <20><><EFBFBD><EFBFBD>
i = it->second;
return true;
}
#define FIND_JOB_WARRIOR_0 (1 << 3)
#define FIND_JOB_WARRIOR_1 (1 << 4)
#define FIND_JOB_WARRIOR_2 (1 << 5)
#define FIND_JOB_WARRIOR (FIND_JOB_WARRIOR_0 | FIND_JOB_WARRIOR_1 | FIND_JOB_WARRIOR_2)
#define FIND_JOB_ASSASSIN_0 (1 << 6)
#define FIND_JOB_ASSASSIN_1 (1 << 7)
#define FIND_JOB_ASSASSIN_2 (1 << 8)
#define FIND_JOB_ASSASSIN (FIND_JOB_ASSASSIN_0 | FIND_JOB_ASSASSIN_1 | FIND_JOB_ASSASSIN_2)
#define FIND_JOB_SURA_0 (1 << 9)
#define FIND_JOB_SURA_1 (1 << 10)
#define FIND_JOB_SURA_2 (1 << 11)
#define FIND_JOB_SURA (FIND_JOB_SURA_0 | FIND_JOB_SURA_1 | FIND_JOB_SURA_2)
#define FIND_JOB_SHAMAN_0 (1 << 12)
#define FIND_JOB_SHAMAN_1 (1 << 13)
#define FIND_JOB_SHAMAN_2 (1 << 14)
#define FIND_JOB_SHAMAN (FIND_JOB_SHAMAN_0 | FIND_JOB_SHAMAN_1 | FIND_JOB_SHAMAN_2)
//
// (job+1)*3+(skill_group)
//
LPCHARACTER CHARACTER_MANAGER::FindSpecifyPC(unsigned int uiJobFlag, int lMapIndex, LPCHARACTER except, int iMinLevel, int iMaxLevel)
{
LPCHARACTER chFind = NULL;
itertype(m_map_pkChrByPID) it;
int n = 0;
for (it = m_map_pkChrByPID.begin(); it != m_map_pkChrByPID.end(); ++it)
{
LPCHARACTER ch = it->second;
if (ch == except)
continue;
if (ch->GetLevel() < iMinLevel)
continue;
if (ch->GetLevel() > iMaxLevel)
continue;
if (ch->GetMapIndex() != lMapIndex)
continue;
if (uiJobFlag)
{
unsigned int uiChrJob = (1 << ((ch->GetJob() + 1) * 3 + ch->GetSkillGroup()));
if (!IS_SET(uiJobFlag, uiChrJob))
continue;
}
if (!chFind || Random::get(1, ++n) == 1)
chFind = ch;
}
return chFind;
}
int CHARACTER_MANAGER::GetMobItemRate(LPCHARACTER ch)
{
//PREVENT_TOXICATION_FOR_CHINA
if ( LC_IsNewCIBN() )
{
if ( ch->IsOverTime( OT_3HOUR ) )
{
if (ch && ch->GetPremiumRemainSeconds(PREMIUM_ITEM) > 0)
return m_iMobItemRatePremium/2;
return m_iMobItemRate/2;
}
else if ( ch->IsOverTime( OT_5HOUR ) )
{
return 0;
}
}
//END_PREVENT_TOXICATION_FOR_CHINA
if (ch && ch->GetPremiumRemainSeconds(PREMIUM_ITEM) > 0)
return m_iMobItemRatePremium;
return m_iMobItemRate;
}
int CHARACTER_MANAGER::GetMobDamageRate(LPCHARACTER ch)
{
return m_iMobDamageRate;
}
int CHARACTER_MANAGER::GetMobGoldAmountRate(LPCHARACTER ch)
{
if ( !ch )
return m_iMobGoldAmountRate;
//PREVENT_TOXICATION_FOR_CHINA
if ( LC_IsNewCIBN() )
{
if ( ch->IsOverTime( OT_3HOUR ) )
{
if (ch && ch->GetPremiumRemainSeconds(PREMIUM_GOLD) > 0)
return m_iMobGoldAmountRatePremium/2;
return m_iMobGoldAmountRate/2;
}
else if ( ch->IsOverTime( OT_5HOUR ) )
{
return 0;
}
}
//END_PREVENT_TOXICATION_FOR_CHINA
if (ch && ch->GetPremiumRemainSeconds(PREMIUM_GOLD) > 0)
return m_iMobGoldAmountRatePremium;
return m_iMobGoldAmountRate;
}
int CHARACTER_MANAGER::GetMobGoldDropRate(LPCHARACTER ch)
{
if ( !ch )
return m_iMobGoldDropRate;
//PREVENT_TOXICATION_FOR_CHINA
if ( LC_IsNewCIBN() )
{
if ( ch->IsOverTime( OT_3HOUR ) )
{
if (ch && ch->GetPremiumRemainSeconds(PREMIUM_GOLD) > 0)
return m_iMobGoldDropRatePremium/2;
return m_iMobGoldDropRate/2;
}
else if ( ch->IsOverTime( OT_5HOUR ) )
{
return 0;
}
}
//END_PREVENT_TOXICATION_FOR_CHINA
if (ch && ch->GetPremiumRemainSeconds(PREMIUM_GOLD) > 0)
return m_iMobGoldDropRatePremium;
return m_iMobGoldDropRate;
}
int CHARACTER_MANAGER::GetMobExpRate(LPCHARACTER ch)
{
if ( !ch )
return m_iMobExpRate;
if ( LC_IsNewCIBN() )
{
if ( ch->IsOverTime( OT_3HOUR ) )
{
if (ch && ch->GetPremiumRemainSeconds(PREMIUM_EXP) > 0)
return m_iMobExpRatePremium/2;
return m_iMobExpRate/2;
}
else if ( ch->IsOverTime( OT_5HOUR ) )
{
return 0;
}
}
if (ch && ch->GetPremiumRemainSeconds(PREMIUM_EXP) > 0)
return m_iMobExpRatePremium;
return m_iMobExpRate;
}
int CHARACTER_MANAGER::GetUserDamageRate(LPCHARACTER ch)
{
if (!ch)
return m_iUserDamageRate;
if (ch && ch->GetPremiumRemainSeconds(PREMIUM_EXP) > 0)
return m_iUserDamageRatePremium;
return m_iUserDamageRate;
}
void CHARACTER_MANAGER::SendScriptToMap(int lMapIndex, const std::string & s)
{
LPSECTREE_MAP pSecMap = SECTREE_MANAGER::instance().GetMap(lMapIndex);
if (NULL == pSecMap)
return;
struct packet_script p;
p.header = HEADER_GC_SCRIPT;
p.skin = 1;
p.src_size = s.size();
quest::FSendPacket f;
p.size = p.src_size + sizeof(struct packet_script);
f.buf.write(&p, sizeof(struct packet_script));
f.buf.write(&s[0], s.size());
pSecMap->for_each(f);
}
bool CHARACTER_MANAGER::BeginPendingDestroy()
{
// Begin <20><> <20>Ŀ<EFBFBD> Begin<69><6E> <20><> <20>ϴ<EFBFBD> <20><><EFBFBD>쿡 Flush <20><><EFBFBD><EFBFBD> <20>ʴ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
// <20>̹<EFBFBD> <20><><EFBFBD>۵Ǿ<DBB5><C7BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> false <20><><EFBFBD><EFBFBD> ó<><C3B3>
if (m_bUsePendingDestroy)
return false;
m_bUsePendingDestroy = true;
return true;
}
void CHARACTER_MANAGER::FlushPendingDestroy()
{
using namespace std;
m_bUsePendingDestroy = false; // <20>÷<EFBFBD><C3B7>׸<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ؾ<EFBFBD> <20><><EFBFBD><EFBFBD> Destroy ó<><C3B3><EFBFBD><EFBFBD> <20><>
if (!m_set_pkChrPendingDestroy.empty())
{
sys_log(0, "FlushPendingDestroy size %d", m_set_pkChrPendingDestroy.size());
CHARACTER_SET::iterator it = m_set_pkChrPendingDestroy.begin(),
end = m_set_pkChrPendingDestroy.end();
for ( ; it != end; ++it) {
M2_DESTROY_CHARACTER(*it);
}
m_set_pkChrPendingDestroy.clear();
}
}
CharacterVectorInteractor::CharacterVectorInteractor(const CHARACTER_SET & r)
{
using namespace std;
#ifdef __GNUC__
using namespace __gnu_cxx;
#endif
reserve(r.size());
#ifdef __GNUC__
transform(r.begin(), r.end(), back_inserter(*this), identity<CHARACTER_SET::value_type>());
#else
insert(end(), r.begin(), r.end());
#endif
if (CHARACTER_MANAGER::instance().BeginPendingDestroy())
m_bMyBegin = true;
}
CharacterVectorInteractor::~CharacterVectorInteractor()
{
if (m_bMyBegin)
CHARACTER_MANAGER::instance().FlushPendingDestroy();
}