server/game/src/dungeon.cpp

1360 lines
29 KiB
C++
Raw Normal View History

2022-03-05 12:44:06 +02:00
#include "stdafx.h"
#include "dungeon.h"
#include "char.h"
#include "char_manager.h"
#include "party.h"
#include "affect.h"
#include "packet.h"
#include "desc.h"
#include "config.h"
#include "regen.h"
#include "start_position.h"
#include "item.h"
#include "item_manager.h"
#include "utils.h"
#include "questmanager.h"
CDungeon::CDungeon(IdType id, int lOriginalMapIndex, int lMapIndex)
2022-03-05 12:44:06 +02:00
: m_id(id),
m_lOrigMapIndex(lOriginalMapIndex),
m_lMapIndex(lMapIndex),
m_map_Area(SECTREE_MANAGER::instance().GetDungeonArea(lOriginalMapIndex))
{
Initialize();
//sys_log(0,"DUNGEON create orig %d real %d", lOriginalMapIndex, lMapIndex);
}
CDungeon::~CDungeon()
{
if (m_pParty != NULL)
{
m_pParty->SetDungeon_for_Only_party (NULL);
}
//sys_log(0,"DUNGEON destroy orig %d real %d", m_lOrigMapIndex, m_lMapIndex );
ClearRegen();
event_cancel(&deadEvent);
// <Factor>
event_cancel(&exit_all_event_);
event_cancel(&jump_to_event_);
}
void CDungeon::Initialize()
{
deadEvent = NULL;
// <Factor>
exit_all_event_ = NULL;
jump_to_event_ = NULL;
regen_id_ = 0;
m_iMobKill = 0;
m_iStoneKill = 0;
m_bUsePotion = false;
m_bUseRevive = false;
m_iMonsterCount = 0;
m_bExitAllAtEliminate = false;
m_bWarpAtEliminate = false;
m_iWarpDelay = 0;
m_lWarpMapIndex = 0;
m_lWarpX = 0;
m_lWarpY = 0;
m_stRegenFile = "";
m_pParty = NULL;
}
void CDungeon::SetFlag(std::string name, int value)
{
itertype(m_map_Flag) it = m_map_Flag.find(name);
if (it != m_map_Flag.end())
it->second = value;
else
m_map_Flag.insert(make_pair(name, value));
}
int CDungeon::GetFlag(std::string name)
{
itertype(m_map_Flag) it = m_map_Flag.find(name);
if (it != m_map_Flag.end())
return it->second;
else
return 0;
}
struct FSendDestPosition
{
FSendDestPosition(int x, int y)
2022-03-05 12:44:06 +02:00
{
p1.bHeader = HEADER_GC_DUNGEON;
p1.subheader = DUNGEON_SUBHEADER_GC_DESTINATION_POSITION;
p2.x = x;
p2.y = y;
p1.size = sizeof(p1)+sizeof(p2);
}
void operator()(LPCHARACTER ch)
{
ch->GetDesc()->RawPacket(&p1, sizeof(TPacketGCDungeon));
2022-03-05 12:44:06 +02:00
ch->GetDesc()->Packet(&p2, sizeof(TPacketGCDungeonDestPosition));
}
TPacketGCDungeon p1;
TPacketGCDungeonDestPosition p2;
};
void CDungeon::SendDestPositionToParty(LPPARTY pParty, int x, int y)
2022-03-05 12:44:06 +02:00
{
if (m_map_pkParty.find(pParty) == m_map_pkParty.end())
{
sys_err("PARTY %u not in DUNGEON %d", pParty->GetLeaderPID(), m_lMapIndex);
return;
}
FSendDestPosition f(x, y);
pParty->ForEachNearMember(f);
}
struct FWarpToDungeon
{
FWarpToDungeon(int lMapIndex, LPDUNGEON d)
2022-03-05 12:44:06 +02:00
: m_lMapIndex(lMapIndex), m_pkDungeon(d)
{
LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(lMapIndex);
m_x = pkSectreeMap->m_setting.posSpawn.x;
m_y = pkSectreeMap->m_setting.posSpawn.y;
}
void operator () (LPCHARACTER ch)
{
ch->SaveExitLocation();
ch->WarpSet(m_x, m_y, m_lMapIndex);
//m_pkDungeon->IncPartyMember(ch->GetParty());
}
int m_lMapIndex;
int m_x;
int m_y;
2022-03-05 12:44:06 +02:00
LPDUNGEON m_pkDungeon;
};
void CDungeon::Join(LPCHARACTER ch)
{
if (SECTREE_MANAGER::instance().GetMap(m_lMapIndex) == NULL) {
sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
return;
}
FWarpToDungeon(m_lMapIndex, this) (ch);
}
void CDungeon::JoinParty(LPPARTY pParty)
{
pParty->SetDungeon(this);
m_map_pkParty.insert(std::make_pair(pParty,0));
if (SECTREE_MANAGER::instance().GetMap(m_lMapIndex) == NULL) {
sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
return;
}
FWarpToDungeon f(m_lMapIndex, this);
pParty->ForEachOnlineMember(f);
//sys_log(0, "DUNGEON-PARTY join %p %p", this, pParty);
}
void CDungeon::QuitParty(LPPARTY pParty)
{
pParty->SetDungeon(NULL);
//sys_log(0, "DUNGEON-PARTY quit %p %p", this, pParty);
TPartyMap::iterator it = m_map_pkParty.find(pParty);
if (it != m_map_pkParty.end())
m_map_pkParty.erase(it);
}
EVENTINFO(dungeon_id_info)
{
CDungeon::IdType dungeon_id;
dungeon_id_info()
: dungeon_id(0)
{
}
};
EVENTFUNC(dungeon_dead_event)
{
dungeon_id_info* info = dynamic_cast<dungeon_id_info*>( event->info );
if ( info == NULL )
{
sys_err( "dungeon_dead_event> <Factor> Null pointer" );
return 0;
}
LPDUNGEON pDungeon = CDungeonManager::instance().Find(info->dungeon_id);
if (pDungeon == NULL) {
return 0;
}
pDungeon->deadEvent = NULL;
CDungeonManager::instance().Destroy(info->dungeon_id);
return 0;
}
void CDungeon::IncMember(LPCHARACTER ch)
{
if (m_set_pkCharacter.find(ch) == m_set_pkCharacter.end())
m_set_pkCharacter.insert(ch);
event_cancel(&deadEvent);
}
void CDungeon::DecMember(LPCHARACTER ch)
{
itertype(m_set_pkCharacter) it = m_set_pkCharacter.find(ch);
if (it == m_set_pkCharacter.end()) {
return;
}
m_set_pkCharacter.erase(it);
if (m_set_pkCharacter.empty())
{
dungeon_id_info* info = AllocEventInfo<dungeon_id_info>();
info->dungeon_id = m_id;
event_cancel(&deadEvent);
deadEvent = event_create(dungeon_dead_event, info, PASSES_PER_SEC(10));
}
}
void CDungeon::IncPartyMember(LPPARTY pParty, LPCHARACTER ch)
{
//sys_log(0, "DUNGEON-PARTY inc %p %p", this, pParty);
TPartyMap::iterator it = m_map_pkParty.find(pParty);
if (it != m_map_pkParty.end())
it->second++;
else
m_map_pkParty.insert(std::make_pair(pParty,1));
IncMember(ch);
}
void CDungeon::DecPartyMember(LPPARTY pParty, LPCHARACTER ch)
{
//sys_log(0, "DUNGEON-PARTY dec %p %p", this, pParty);
TPartyMap::iterator it = m_map_pkParty.find(pParty);
if (it == m_map_pkParty.end())
sys_err("cannot find party");
else
{
it->second--;
if (it->second == 0)
QuitParty(pParty);
}
DecMember(ch);
}
struct FWarpToPosition
{
int lMapIndex;
int x;
int y;
FWarpToPosition(int lMapIndex, int x, int y)
2022-03-05 12:44:06 +02:00
: lMapIndex(lMapIndex), x(x), y(y)
{}
void operator()(LPENTITY ent)
{
if (!ent->IsType(ENTITY_CHARACTER)) {
return;
}
LPCHARACTER ch = (LPCHARACTER)ent;
if (!ch->IsPC()) {
return;
}
if (ch->GetMapIndex() == lMapIndex)
{
ch->Show(lMapIndex, x, y, 0);
ch->Stop();
}
else
{
ch->WarpSet(x,y,lMapIndex);
}
}
};
struct FWarpToPositionForce
{
int lMapIndex;
int x;
int y;
FWarpToPositionForce(int lMapIndex, int x, int y)
2022-03-05 12:44:06 +02:00
: lMapIndex(lMapIndex), x(x), y(y)
{}
void operator()(LPENTITY ent)
{
if (!ent->IsType(ENTITY_CHARACTER)) {
return;
}
LPCHARACTER ch = (LPCHARACTER)ent;
if (!ch->IsPC()) {
return;
}
ch->WarpSet(x,y,lMapIndex);
}
};
void CDungeon::JumpAll(int lFromMapIndex, int x, int y)
2022-03-05 12:44:06 +02:00
{
x *= 100;
y *= 100;
LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(lFromMapIndex);
if (!pMap)
{
sys_err("cannot find map by index %d", lFromMapIndex);
return;
}
FWarpToPosition f(m_lMapIndex, x, y);
// <Factor> SECTREE::for_each -> SECTREE::for_each_entity
pMap->for_each(f);
}
void CDungeon::WarpAll(int lFromMapIndex, int x, int y)
2022-03-05 12:44:06 +02:00
{
x *= 100;
y *= 100;
LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(lFromMapIndex);
if (!pMap)
{
sys_err("cannot find map by index %d", lFromMapIndex);
return;
}
FWarpToPositionForce f(m_lMapIndex, x, y);
// <Factor> SECTREE::for_each -> SECTREE::for_each_entity
pMap->for_each(f);
}
void CDungeon::JumpParty(LPPARTY pParty, int lFromMapIndex, int x, int y)
2022-03-05 12:44:06 +02:00
{
x *= 100;
y *= 100;
LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(lFromMapIndex);
if (!pMap)
{
sys_err("cannot find map by index %d", lFromMapIndex);
return;
}
if (pParty->GetDungeon_for_Only_party() == NULL)
{
if (m_pParty == NULL)
{
m_pParty = pParty;
}
else if (m_pParty != pParty)
{
sys_err ("Dungeon already has party. Another party cannot jump in dungeon : index %d", GetMapIndex());
return;
}
pParty->SetDungeon_for_Only_party (this);
}
FWarpToPosition f(m_lMapIndex, x, y);
pParty->ForEachOnMapMember(f, lFromMapIndex);
}
void CDungeon::SetPartyNull()
{
m_pParty = NULL;
}
void CDungeonManager::Destroy(CDungeon::IdType dungeon_id)
{
sys_log(0, "DUNGEON destroy : map index %u", dungeon_id);
LPDUNGEON pDungeon = Find(dungeon_id);
if (pDungeon == NULL) {
return;
}
m_map_pkDungeon.erase(dungeon_id);
int lMapIndex = pDungeon->m_lMapIndex;
2022-03-05 12:44:06 +02:00
m_map_pkMapDungeon.erase(lMapIndex);
DWORD server_timer_arg = lMapIndex;
quest::CQuestManager::instance().CancelServerTimers(server_timer_arg);
SECTREE_MANAGER::instance().DestroyPrivateMap(lMapIndex);
M2_DELETE(pDungeon);
}
LPDUNGEON CDungeonManager::Find(CDungeon::IdType dungeon_id)
{
itertype(m_map_pkDungeon) it = m_map_pkDungeon.find(dungeon_id);
if (it != m_map_pkDungeon.end())
return it->second;
return NULL;
}
LPDUNGEON CDungeonManager::FindByMapIndex(int lMapIndex)
2022-03-05 12:44:06 +02:00
{
itertype(m_map_pkMapDungeon) it = m_map_pkMapDungeon.find(lMapIndex);
if (it != m_map_pkMapDungeon.end()) {
return it->second;
}
return NULL;
}
LPDUNGEON CDungeonManager::Create(int lOriginalMapIndex)
2022-03-05 12:44:06 +02:00
{
DWORD lMapIndex = SECTREE_MANAGER::instance().CreatePrivateMap(lOriginalMapIndex);
if (!lMapIndex)
{
sys_log( 0, "Fail to Create Dungeon : OrginalMapindex %d NewMapindex %d", lOriginalMapIndex, lMapIndex );
return NULL;
}
// <Factor> TODO: Change id assignment, or drop it
CDungeon::IdType id = next_id_++;
while (Find(id) != NULL) {
id = next_id_++;
}
LPDUNGEON pDungeon = M2_NEW CDungeon(id, lOriginalMapIndex, lMapIndex);
if (!pDungeon)
{
sys_err("M2_NEW CDungeon failed");
return NULL;
}
m_map_pkDungeon.insert(std::make_pair(id, pDungeon));
m_map_pkMapDungeon.insert(std::make_pair(lMapIndex, pDungeon));
return pDungeon;
}
CDungeonManager::CDungeonManager()
: next_id_(0)
{
}
CDungeonManager::~CDungeonManager()
{
}
void CDungeon::UniqueSetMaxHP(const std::string& key, int iMaxHP)
{
TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
if (it == m_map_UniqueMob.end())
{
sys_err("Unknown Key : %s", key.c_str());
return;
}
it->second->SetMaxHP(iMaxHP);
}
void CDungeon::UniqueSetHP(const std::string& key, int iHP)
{
TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
if (it == m_map_UniqueMob.end())
{
sys_err("Unknown Key : %s", key.c_str());
return;
}
it->second->SetHP(iHP);
}
void CDungeon::UniqueSetDefGrade(const std::string& key, int iGrade)
{
TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
if (it == m_map_UniqueMob.end())
{
sys_err("Unknown Key : %s", key.c_str());
return;
}
it->second->PointChange(POINT_DEF_GRADE,iGrade - it->second->GetPoint(POINT_DEF_GRADE));
}
void CDungeon::SpawnMoveUnique(const char* key, DWORD vnum, const char* pos_from, const char* pos_to)
{
TAreaMap::iterator it_to = m_map_Area.find(pos_to);
if (it_to == m_map_Area.end())
{
sys_err("Wrong position string : %s", pos_to);
return;
}
TAreaMap::iterator it_from = m_map_Area.find(pos_from);
if (it_from == m_map_Area.end())
{
sys_err("Wrong position string : %s", pos_from);
return;
}
TAreaInfo & ai = it_from->second;
TAreaInfo & ai_to = it_to->second;
int dir = ai.dir;
if (dir==-1)
dir = number(0,359);
LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (pkSectreeMap == NULL) {
sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
return;
}
for (int i=0;i<100;i++)
{
int dx = number(ai.sx, ai.ex);
int dy = number(ai.sy, ai.ey);
int tx = number(ai_to.sx, ai_to.ex);
int ty = number(ai_to.sy, ai_to.ey);
LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(vnum, m_lMapIndex, pkSectreeMap->m_setting.iBaseX+dx, pkSectreeMap->m_setting.iBaseY+dy, 0, false, dir);
if (ch)
{
m_map_UniqueMob.insert(make_pair(std::string(key), ch));
ch->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
ch->SetDungeon(this);
if (ch->Goto(pkSectreeMap->m_setting.iBaseX+tx, pkSectreeMap->m_setting.iBaseY+ty))
ch->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
}
else
{
sys_err("Cannot spawn at %d %d", pkSectreeMap->m_setting.iBaseX+((ai.sx+ai.ex)>>1), pkSectreeMap->m_setting.iBaseY+((ai.sy+ai.ey)>>1));
}
}
}
void CDungeon::SpawnUnique(const char* key, DWORD vnum, const char* pos)
{
TAreaMap::iterator it = m_map_Area.find(pos);
if (it == m_map_Area.end())
{
sys_err("Wrong position string : %s", pos);
return;
}
TAreaInfo & ai = it->second;
int dir = ai.dir;
if (dir==-1)
dir = number(0,359);
LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (pkSectreeMap == NULL) {
sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
return;
}
for (int i=0;i<100;i++)
{
int dx = number(ai.sx, ai.ex);
int dy = number(ai.sy, ai.ey);
LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(vnum, m_lMapIndex, pkSectreeMap->m_setting.iBaseX+dx, pkSectreeMap->m_setting.iBaseY+dy, 0, false, dir);
if (ch)
{
m_map_UniqueMob.insert(make_pair(std::string(key), ch));
ch->SetDungeon(this);
ch->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
break;
}
else
{
sys_err("Cannot spawn at %d %d", pkSectreeMap->m_setting.iBaseX+((ai.sx+ai.ex)>>1), pkSectreeMap->m_setting.iBaseY+((ai.sy+ai.ey)>>1));
}
}
}
void CDungeon::SetUnique(const char* key, DWORD vid)
{
LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(vid);
if (ch)
{
m_map_UniqueMob.insert(make_pair(std::string(key), ch));
ch->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
}
}
void CDungeon::SpawnStoneDoor(const char* key, const char* pos)
{
SpawnUnique(key, 13001, pos);
}
void CDungeon::SpawnWoodenDoor(const char* key, const char* pos)
{
SpawnUnique(key, 13000, pos);
UniqueSetMaxHP(key, 10000);
UniqueSetHP(key, 10000);
UniqueSetDefGrade(key, 300);
}
void CDungeon::PurgeUnique(const std::string& key)
{
TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
if (it == m_map_UniqueMob.end())
{
sys_err("Unknown Key or Dead: %s", key.c_str());
return;
}
LPCHARACTER ch = it->second;
m_map_UniqueMob.erase(it);
M2_DESTROY_CHARACTER(ch);
}
void CDungeon::KillUnique(const std::string& key)
{
TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
if (it == m_map_UniqueMob.end())
{
sys_err("Unknown Key or Dead: %s", key.c_str());
return;
}
LPCHARACTER ch = it->second;
m_map_UniqueMob.erase(it);
ch->Dead();
}
DWORD CDungeon::GetUniqueVid(const std::string& key)
{
TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
if (it == m_map_UniqueMob.end())
{
sys_err("Unknown Key or Dead: %s", key.c_str());
return 0;
}
LPCHARACTER ch = it->second;
return ch->GetVID();
}
float CDungeon::GetUniqueHpPerc(const std::string& key)
{
TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
if (it == m_map_UniqueMob.end())
{
sys_err("Unknown Key : %s", key.c_str());
return false;
}
return (100.f*it->second->GetHP())/it->second->GetMaxHP();
}
void CDungeon::DeadCharacter(LPCHARACTER ch)
{
if (!ch->IsPC())
{
TUniqueMobMap::iterator it = m_map_UniqueMob.begin();
while (it!=m_map_UniqueMob.end())
{
if (it->second == ch)
{
//sys_log(0,"Dead unique %s", it->first.c_str());
m_map_UniqueMob.erase(it);
break;
}
++it;
}
}
}
bool CDungeon::IsUniqueDead(const std::string& key)
{
TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
if (it == m_map_UniqueMob.end())
{
sys_err("Unknown Key or Dead : %s", key.c_str());
return true;
}
return it->second->IsDead();
}
void CDungeon::Spawn(DWORD vnum, const char* pos)
{
//sys_log(0,"DUNGEON Spawn %u %s", vnum, pos);
TAreaMap::iterator it = m_map_Area.find(pos);
if (it == m_map_Area.end())
{
sys_err("Wrong position string : %s", pos);
return;
}
TAreaInfo & ai = it->second;
int dir = ai.dir;
if (dir==-1)
dir = number(0,359);
LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (pkSectreeMap == NULL)
{
sys_err("cannot find map by index %d", m_lMapIndex);
return;
}
int dx = number(ai.sx, ai.ex);
int dy = number(ai.sy, ai.ey);
LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(vnum, m_lMapIndex, pkSectreeMap->m_setting.iBaseX+dx, pkSectreeMap->m_setting.iBaseY+dy, 0, false, dir);
if (ch)
ch->SetDungeon(this);
}
LPCHARACTER CDungeon::SpawnMob(DWORD vnum, int x, int y, int dir)
{
LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (pkSectreeMap == NULL) {
sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
return NULL;
}
sys_log(0, "CDungeon::SpawnMob %u %d %d", vnum, x, y);
LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(vnum, m_lMapIndex, pkSectreeMap->m_setting.iBaseX+x*100, pkSectreeMap->m_setting.iBaseY+y*100, 0, false, dir == 0 ? -1 : (dir - 1) * 45);
if (ch)
{
ch->SetDungeon(this);
sys_log(0, "CDungeon::SpawnMob name %s", ch->GetName());
}
return ch;
}
LPCHARACTER CDungeon::SpawnMob_ac_dir(DWORD vnum, int x, int y, int dir)
{
LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (pkSectreeMap == NULL) {
sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
return NULL;
}
sys_log(0, "CDungeon::SpawnMob %u %d %d", vnum, x, y);
LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(vnum, m_lMapIndex, pkSectreeMap->m_setting.iBaseX+x*100, pkSectreeMap->m_setting.iBaseY+y*100, 0, false, dir);
if (ch)
{
ch->SetDungeon(this);
sys_log(0, "CDungeon::SpawnMob name %s", ch->GetName());
}
return ch;
}
void CDungeon::SpawnNameMob(DWORD vnum, int x, int y, const char* name)
{
LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (pkSectreeMap == NULL) {
sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
return;
}
LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(vnum, m_lMapIndex, pkSectreeMap->m_setting.iBaseX+x, pkSectreeMap->m_setting.iBaseY+y, 0, false, -1);
if (ch)
{
ch->SetName(name);
ch->SetDungeon(this);
}
}
void CDungeon::SpawnGotoMob(int lFromX, int lFromY, int lToX, int lToY)
2022-03-05 12:44:06 +02:00
{
const int MOB_GOTO_VNUM = 20039;
LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (pkSectreeMap == NULL) {
sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
return;
}
sys_log(0, "SpawnGotoMob %d %d to %d %d", lFromX, lFromY, lToX, lToY);
lFromX = pkSectreeMap->m_setting.iBaseX+lFromX*100;
lFromY = pkSectreeMap->m_setting.iBaseY+lFromY*100;
LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(MOB_GOTO_VNUM, m_lMapIndex, lFromX, lFromY, 0, false, -1);
if (ch)
{
char buf[30+1];
snprintf(buf, sizeof(buf), ". %d %d", lToX, lToY);
2022-03-05 12:44:06 +02:00
ch->SetName(buf);
ch->SetDungeon(this);
}
}
LPCHARACTER CDungeon::SpawnGroup(DWORD vnum, int x, int y, float radius, bool bAggressive, int count)
2022-03-05 12:44:06 +02:00
{
LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (pkSectreeMap == NULL) {
sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
return NULL;
}
int iRadius = (int) radius;
int sx = pkSectreeMap->m_setting.iBaseX + x - iRadius;
int sy = pkSectreeMap->m_setting.iBaseY + y - iRadius;
int ex = sx + iRadius;
int ey = sy + iRadius;
LPCHARACTER ch = NULL;
while (count--)
{
LPCHARACTER chLeader = CHARACTER_MANAGER::instance().SpawnGroup(vnum, m_lMapIndex, sx, sy, ex, ey, NULL, bAggressive, this);
if (chLeader && !ch)
ch = chLeader;
}
return ch;
}
void CDungeon::SpawnRegen(const char* filename, bool bOnce)
{
if (!filename)
{
sys_err("CDungeon::SpawnRegen(filename=NULL, bOnce=%d) - m_lMapIndex[%d]", bOnce, m_lMapIndex);
return;
}
LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (!pkSectreeMap)
{
sys_err("CDungeon::SpawnRegen(filename=%s, bOnce=%d) - m_lMapIndex[%d]", filename, bOnce, m_lMapIndex);
return;
}
regen_do(filename, m_lMapIndex, pkSectreeMap->m_setting.iBaseX, pkSectreeMap->m_setting.iBaseY, this, bOnce);
}
void CDungeon::AddRegen(LPREGEN regen)
{
regen->id = regen_id_++;
m_regen.push_back(regen);
}
void CDungeon::ClearRegen()
{
for (itertype(m_regen) it = m_regen.begin(); it != m_regen.end(); ++it)
{
LPREGEN regen = *it;
event_cancel(&regen->event);
M2_DELETE(regen);
}
m_regen.clear();
}
bool CDungeon::IsValidRegen(LPREGEN regen, size_t regen_id) {
itertype(m_regen) it = std::find(m_regen.begin(), m_regen.end(), regen);
if (it == m_regen.end()) {
return false;
}
LPREGEN found = *it;
return (found->id == regen_id);
}
void CDungeon::SpawnMoveGroup(DWORD vnum, const char* pos_from, const char* pos_to, int count)
{
TAreaMap::iterator it_to = m_map_Area.find(pos_to);
if (it_to == m_map_Area.end())
{
sys_err("Wrong position string : %s", pos_to);
return;
}
TAreaMap::iterator it_from = m_map_Area.find(pos_from);
if (it_from == m_map_Area.end())
{
sys_err("Wrong position string : %s", pos_from);
return;
}
TAreaInfo & ai = it_from->second;
TAreaInfo & ai_to = it_to->second;
int dir = ai.dir;
if (dir == -1)
dir = number(0,359);
LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (pkSectreeMap == NULL) {
sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
return;
}
while (count--)
{
int tx = number(ai_to.sx, ai_to.ex)+pkSectreeMap->m_setting.iBaseX;
int ty = number(ai_to.sy, ai_to.ey)+pkSectreeMap->m_setting.iBaseY;
CHARACTER_MANAGER::instance().SpawnMoveGroup(vnum, m_lMapIndex, pkSectreeMap->m_setting.iBaseX+ai.sx, pkSectreeMap->m_setting.iBaseY+ai.sy, pkSectreeMap->m_setting.iBaseX+ai.ex, pkSectreeMap->m_setting.iBaseY+ai.ey, tx, ty, NULL, true);
}
}
namespace
{
// DUNGEON_KILL_ALL_BUG_FIX
struct FKillSectree
{
void operator () (LPENTITY ent)
{
if (ent->IsType(ENTITY_CHARACTER))
{
LPCHARACTER ch = (LPCHARACTER) ent;
if (!ch->IsPC() && !ch->IsPet())
ch->Dead();
}
}
};
// END_OF_DUNGEON_KILL_ALL_BUG_FIX
struct FPurgeSectree
{
void operator () (LPENTITY ent)
{
if (ent->IsType(ENTITY_CHARACTER))
{
LPCHARACTER ch = (LPCHARACTER) ent;
if (!ch->IsPC() && !ch->IsPet()) {
M2_DESTROY_CHARACTER(ch);
}
}
else if (ent->IsType(ENTITY_ITEM))
{
LPITEM item = (LPITEM) ent;
M2_DESTROY_ITEM(item);
}
else
sys_err("unknown entity type %d is in dungeon", ent->GetType());
}
};
}
// DUNGEON_KILL_ALL_BUG_FIX
void CDungeon::KillAll()
{
LPSECTREE_MAP pkMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (pkMap == NULL) {
sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
return;
}
FKillSectree f;
pkMap->for_each(f);
}
// END_OF_DUNGEON_KILL_ALL_BUG_FIX
void CDungeon::Purge()
{
LPSECTREE_MAP pkMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (pkMap == NULL) {
sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
return;
}
FPurgeSectree f;
pkMap->for_each(f);
}
void CDungeon::IncKillCount(LPCHARACTER pkKiller, LPCHARACTER pkVictim)
{
if (pkVictim->IsStone())
m_iStoneKill ++;
else
m_iMobKill ++;
}
void CDungeon::UsePotion(LPCHARACTER ch)
{
m_bUsePotion = true;
}
void CDungeon::UseRevive(LPCHARACTER ch)
{
m_bUseRevive = true;
}
bool CDungeon::IsUsePotion()
{
return m_bUsePotion;
}
bool CDungeon::IsUseRevive()
{
return m_bUseRevive;
}
int CDungeon::GetKillMobCount()
{
return m_iMobKill;
}
int CDungeon::GetKillStoneCount()
{
return m_iStoneKill;
}
struct FCountMonster
{
int n;
FCountMonster() : n(0) {};
void operator()(LPENTITY ent)
{
if (ent->IsType(ENTITY_CHARACTER))
{
LPCHARACTER ch = (LPCHARACTER) ent;
if (!ch->IsPC())
n++;
}
}
};
int CDungeon::CountRealMonster()
{
LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(m_lOrigMapIndex);
if (!pMap)
{
sys_err("cannot find map by index %d", m_lOrigMapIndex);
return 0;
}
FCountMonster f;
// <Factor> SECTREE::for_each -> SECTREE::for_each_entity
pMap->for_each(f);
return f.n;
}
struct FExitDungeon
{
void operator()(LPENTITY ent)
{
if (ent->IsType(ENTITY_CHARACTER))
{
LPCHARACTER ch = (LPCHARACTER) ent;
if (ch->IsPC())
ch->ExitToSavedLocation();
}
}
};
void CDungeon::ExitAll()
{
LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (!pMap)
{
sys_err("cannot find map by index %d", m_lMapIndex);
return;
}
FExitDungeon f;
// <Factor> SECTREE::for_each -> SECTREE::for_each_entity
pMap->for_each(f);
}
// DUNGEON_NOTICE
namespace
{
struct FNotice
{
FNotice(const char * psz) : m_psz(psz)
{
}
void operator() (LPENTITY ent)
{
if (ent->IsType(ENTITY_CHARACTER))
{
LPCHARACTER ch = (LPCHARACTER) ent;
ch->ChatPacket(CHAT_TYPE_NOTICE, "%s", m_psz);
}
}
const char * m_psz;
};
}
void CDungeon::Notice(const char* msg)
{
sys_log(0, "XXX Dungeon Notice %p %s", this, msg);
LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (!pMap)
{
sys_err("cannot find map by index %d", m_lMapIndex);
return;
}
FNotice f(msg);
pMap->for_each(f);
}
// END_OF_DUNGEON_NOTICE
struct FExitDungeonToStartPosition
{
void operator () (LPENTITY ent)
{
if (ent->IsType(ENTITY_CHARACTER))
{
LPCHARACTER ch = (LPCHARACTER) ent;
if (ch->IsPC())
{
PIXEL_POSITION posWarp;
// <20><><EFBFBD><EFBFBD> <20><> <20>ε<EFBFBD><CEB5><EFBFBD><EFBFBD><EFBFBD> <20>ִ<EFBFBD> <20><><EFBFBD><EFBFBD> <20>ƴ϶<C6B4> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD> <20><> <20>ε<EFBFBD><CEB5><EFBFBD><EFBFBD><EFBFBD> <20>ִ´<D6B4>.
if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(g_start_map[ch->GetEmpire()], ch->GetEmpire(), posWarp))
ch->WarpSet(posWarp.x, posWarp.y);
else
ch->ExitToSavedLocation();
}
}
}
};
void CDungeon::ExitAllToStartPosition()
{
LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (!pMap)
{
sys_err("cannot find map by index %d", m_lMapIndex);
return;
}
FExitDungeonToStartPosition f;
// <Factor> SECTREE::for_each -> SECTREE::for_each_entity
pMap->for_each(f);
}
EVENTFUNC(dungeon_jump_to_event)
{
dungeon_id_info * info = dynamic_cast<dungeon_id_info *>(event->info);
if ( info == NULL )
{
sys_err( "dungeon_jump_to_event> <Factor> Null pointer" );
return 0;
}
LPDUNGEON pDungeon = CDungeonManager::instance().Find(info->dungeon_id);
pDungeon->jump_to_event_ = NULL;
if (pDungeon)
pDungeon->JumpToEliminateLocation();
else
sys_err("cannot find dungeon with map index %u", info->dungeon_id);
return 0;
}
EVENTFUNC(dungeon_exit_all_event)
{
dungeon_id_info * info = dynamic_cast<dungeon_id_info *>(event->info);
if ( info == NULL )
{
sys_err( "dungeon_exit_all_event> <Factor> Null pointer" );
return 0;
}
LPDUNGEON pDungeon = CDungeonManager::instance().Find(info->dungeon_id);
pDungeon->exit_all_event_ = NULL;
if (pDungeon)
pDungeon->ExitAll();
return 0;
}
void CDungeon::CheckEliminated()
{
if (m_iMonsterCount > 0)
return;
if (m_bExitAllAtEliminate)
{
sys_log(0, "CheckEliminated: exit");
m_bExitAllAtEliminate = false;
if (m_iWarpDelay)
{
dungeon_id_info* info = AllocEventInfo<dungeon_id_info>();
info->dungeon_id = m_id;
event_cancel(&exit_all_event_);
exit_all_event_ = event_create(dungeon_exit_all_event, info, PASSES_PER_SEC(m_iWarpDelay));
}
else
{
ExitAll();
}
}
else if (m_bWarpAtEliminate)
{
sys_log(0, "CheckEliminated: warp");
m_bWarpAtEliminate = false;
if (m_iWarpDelay)
{
dungeon_id_info* info = AllocEventInfo<dungeon_id_info>();
info->dungeon_id = m_id;
event_cancel(&jump_to_event_);
jump_to_event_ = event_create(dungeon_jump_to_event, info, PASSES_PER_SEC(m_iWarpDelay));
}
else
{
JumpToEliminateLocation();
}
}
else
sys_log(0, "CheckEliminated: none");
}
void CDungeon::SetExitAllAtEliminate(int time)
2022-03-05 12:44:06 +02:00
{
sys_log(0, "SetExitAllAtEliminate: time %d", time);
m_bExitAllAtEliminate = true;
m_iWarpDelay = time;
}
void CDungeon::SetWarpAtEliminate(int time, int lMapIndex, int x, int y, const char* regen_file)
2022-03-05 12:44:06 +02:00
{
m_bWarpAtEliminate = true;
m_iWarpDelay = time;
m_lWarpMapIndex = lMapIndex;
m_lWarpX = x;
m_lWarpY = y;
if (!regen_file || !*regen_file)
m_stRegenFile.clear();
else
m_stRegenFile = regen_file;
sys_log(0, "SetWarpAtEliminate: time %d map %d %dx%d regenfile %s", time, lMapIndex, x, y, m_stRegenFile.c_str());
}
void CDungeon::JumpToEliminateLocation()
{
LPDUNGEON pDungeon = CDungeonManager::instance().FindByMapIndex(m_lWarpMapIndex);
if (pDungeon)
{
pDungeon->JumpAll(m_lMapIndex, m_lWarpX, m_lWarpY);
if (!m_stRegenFile.empty())
{
pDungeon->SpawnRegen(m_stRegenFile.c_str());
m_stRegenFile.clear();
}
}
else
{
// <20>Ϲ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (!pMap)
{
sys_err("no map by index %d", m_lMapIndex);
return;
}
FWarpToPosition f(m_lWarpMapIndex, m_lWarpX * 100, m_lWarpY * 100);
// <Factor> SECTREE::for_each -> SECTREE::for_each_entity
pMap->for_each(f);
}
}
struct FNearPosition
{
int x;
int y;
2022-03-05 12:44:06 +02:00
int dist;
bool ret;
FNearPosition(int x, int y, int d) :
2022-03-05 12:44:06 +02:00
x(x), y(y), dist(d), ret(true)
{
}
void operator()(LPENTITY ent)
{
if (ret == false)
return;
if (ent->IsType(ENTITY_CHARACTER))
{
LPCHARACTER ch = (LPCHARACTER) ent;
if (ch->IsPC())
{
if (DISTANCE_APPROX(ch->GetX() - x * 100, ch->GetY() - y * 100) > dist * 100)
ret = false;
}
}
}
};
bool CDungeon::IsAllPCNearTo(int x, int y, int dist)
{
LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
if (!pMap)
{
sys_err("cannot find map by index %d", m_lMapIndex);
return false;
}
FNearPosition f(x, y, dist);
// <Factor> SECTREE::for_each -> SECTREE::for_each_entity
pMap->for_each(f);
return f.ret;
}
void CDungeon::CreateItemGroup (std::string& group_name, ItemGroup& item_group)
{
m_map_ItemGroup.insert (ItemGroupMap::value_type (group_name, item_group));
}
const CDungeon::ItemGroup* CDungeon::GetItemGroup (std::string& group_name)
{
ItemGroupMap::iterator it = m_map_ItemGroup.find (group_name);
if (it != m_map_ItemGroup.end())
return &(it->second);
else
return NULL;
}