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

1113 lines
26 KiB
C++
Raw Normal View History

2022-03-05 12:44:06 +02:00
#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()));
2022-03-05 12:44:06 +02:00
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)
2022-03-05 12:44:06 +02:00
{
// <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;
2022-03-05 12:44:06 +02:00
for (i=0; i<2000; i++)
{
2022-11-27 14:36:04 +02:00
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;
2022-03-05 12:44:06 +02:00
//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));
2022-11-27 14:36:04 +02:00
ch->SetRotation(Random::get(0, 360));
2022-03-05 12:44:06 +02:00
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());
2022-03-05 12:44:06 +02:00
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)
2022-03-05 12:44:06 +02:00
{
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)
2022-11-27 14:36:04 +02:00
iRot = Random::get(0, 360);
2022-03-05 12:44:06 +02:00
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 )
2022-03-05 12:44:06 +02:00
{
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--)
{
2022-11-27 14:36:04 +02:00
int x = Random::get(sx, ex);
int y = Random::get(sy, ey);
2022-03-05 12:44:06 +02:00
/*
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_)
2022-03-05 12:44:06 +02:00
{
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;
}
2022-11-27 14:36:04 +02:00
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);
2022-03-05 12:44:06 +02:00
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)
2022-03-05 12:44:06 +02:00
{
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)
2022-03-05 12:44:06 +02:00
{
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);
2022-11-27 14:36:04 +02:00
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);
2022-03-05 12:44:06 +02:00
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)
2022-03-05 12:44:06 +02:00
{
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;
}
2022-11-27 14:36:04 +02:00
if (!chFind || Random::get(1, ++n) == 1)
2022-03-05 12:44:06 +02:00
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)
2022-03-05 12:44:06 +02:00
{
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();
}