Explicación del Código Fuente: RoyalBattleGround

Explicación del Código Fuente: RoyalBattleGround

El código fuente de RoyalBattleGround es parte de un sistema diseñado para implementar un evento de Battle Royale en MuOnline. Este sistema permite a los jugadores participar en un evento competitivo donde luchan entre sí hasta que solo quede un jugador. A continuación, desglosaré las principales secciones y funciones del código.

1. Definición de la Clase

cpp

Copiar
class cRoyalBattleGround {
public:
cRoyalBattleGround();
~cRoyalBattleGround();
void Init();
void Read(char* path);
void MainProc();
// Otras funciones...
};

La clase cRoyalBattleGround es el núcleo del sistema. En su constructor (cRoyalBattleGround), se inicializan las variables necesarias para el evento, como el tipo de moneda, el estado del evento y los temporizadores.

2. Inicialización

cpp

Copiar
void cRoyalBattleGround::Init() {
this->m_TypeCoin = 0; // Tipo de moneda
this->m_Enable = true; // Habilitar el evento
// Inicializar otros parámetros
this->Read(gPath.GetFullPath("Event\\BattleRoyale\\RoyalBattleGround.dat"));
this->ClearProc();
this->SendPhaseToAllUsers();
}

La función Init es responsable de configurar el evento. Aquí se define el tipo de moneda que se utilizará, se habilita el evento y se leen las configuraciones desde un archivo .dat.

3. Lectura de Configuración

cpp

Copiar
void cRoyalBattleGround::Read(char* path) {
CMemScript* lpMemScript = new CMemScript;
if (lpMemScript->SetBuffer(path) == 0) {
ErrorMessageBox(lpMemScript->GetLastError());
delete lpMemScript;
return;
}

// Procesamiento de secciones
while (true) {
if (lpMemScript->GetToken() == TOKEN_END) {
break;
}
int section = lpMemScript->GetNumber();
// Manejo de cada sección del archivo
}
delete lpMemScript;
}

Esta función se encarga de leer la configuración del evento desde un archivo. Dependiendo de la sección, se configuran diferentes parámetros, como los tiempos de apertura y las recompensas.

4. Procesamiento Principal

cpp

Copiar
void cRoyalBattleGround::MainProc() {
DWORD elapsed = GetTickCount() - this->m_TickCount;
if (this->m_TargetTime == -1 || elapsed < 1000) {
return;
}
this->m_TickCount = GetTickCount();
this->m_RemainTime = (int)difftime(this->m_TargetTime, time(0));
switch (this->m_State) {
case RBG_STATE::RBG_STATE_BLANK:
this->BlankProc();
break;
// Otros estados…
}
}

MainProc es la función que se ejecuta continuamente para actualizar el estado del evento. Dependiendo del estado actual (como BLANK, OPEN, BATTLE_STAGE), se llaman a diferentes procedimientos para manejar la lógica del evento.

5. Manejo de Jugadores

cpp

Copiar
bool cRoyalBattleGround::AddMember(int aIndex) {
LPOBJ lpObj = &gObj[aIndex];
if (gObjIsConnectedGP(aIndex) == 0) {
return false; // El jugador no está conectado
}

// Verificación de espacio y costo de entrada
if (this->m_TotalPlayer >= RBG_MAX_PLAYER) {
gNotice.GCNoticeSend(aIndex, 1, 0, 0, 0, 0, 0, «El evento está lleno»);
return false;
}

// Procesar la entrada del jugador
this->Player[bestChoice].Index = aIndex;
this->CountMember();
return true;
}

La función AddMember se encarga de agregar un jugador al evento. Verifica si el jugador está conectado y si hay espacio disponible. También maneja el costo de entrada.

6. Procesamiento de Fases del Evento

El evento se divide en varias fases, cada una controlada por funciones específicas como BlankProc, OpenProc, PrepareProc, y StageXProc. Cada una de estas funciones maneja la lógica para su respectiva fase del evento, como la preparación de jugadores, la gestión del tiempo y la asignación de recompensas.

7. Gestión de Recompensas

cpp

Copiar
void cRoyalBattleGround::RewardProc() {
for (int i = 0; i < RBG_MAX_PLAYER; i++) {
int aIndex = this->Player[i].Index;
if (aIndex != -1) {
// Verificar conexión y asignar recompensas
}
}
this->SetState(RBG_STATE::RBG_STATE_CLEAR);
}

La función RewardProc se encarga de distribuir las recompensas a los jugadores al finalizar el evento. Se basa en el rendimiento de cada jugador y las configuraciones definidas previamente.

AQU EL CODGO COMPLETO

  • RoyalBattleGround.cpp
#include "stdafx.h"
#include "RoyalBattleGround.h"
#include "Util.h"
#include "Path.h"
#include "MemScript.h"
#include "ScheduleManager.h"
#include "Map.h"
#include "Notice.h"
#include "DSProtocol.h"
#include "ObjectManager.h"
#include "MasterSkillTree.h"
#include "Protocol.h"
#include "ItemBagManager.h"
#include "Move.h"
#include "CustomRankUser.h"
#include "Gate.h"
cRoyalBattleGround RoyalBattleGround;

cRoyalBattleGround::cRoyalBattleGround()
{

}

cRoyalBattleGround::~cRoyalBattleGround()
{
}

void cRoyalBattleGround::Init()
{
    this->m_TypeCoin = 0;
    this->m_Enable = true;
    this->m_RegenMax = 1;
    this->m_State = RBG_STATE_BLANK;
    this->m_RemainTime = 0;
    this->m_TargetTime = 0;
    this->m_EndTime = 0;
    this->m_TickCount = GetTickCount();
    this->m_TotalPlayerJoin = 0;
    this->m_RBGStartTime.clear();
    this->m_RBG_Items.clear();
    this->m_RBG_Phases.clear();
    this->m_BackupCharacter.clear();
    this->m_SinhTonSkillBlock.clear();
    this->m_Reward.clear();

    this->Read(gPath.GetFullPath("Event\\BattleRoyale\\RoyalBattleGround.dat"));
    this->ClearProc();

    this->SendPhaseToAllUsers();
}
char* GetNameCoinType(int TypeCoin)
{
    switch (TypeCoin)
    {
    case 0:
        return "Zen";
        break;
    case 1:
        return "XCoin";
        break;
    case 2:
        return "HCoin";
        break;
    case 3:
        return "Point";
        break;
    default:
        break;
    }
    return "NULL";
}
void cRoyalBattleGround::Read(char* path)
{
    CMemScript* lpMemScript = new CMemScript;

    if (lpMemScript == 0)
    {
        ErrorMessageBox(MEM_SCRIPT_ALLOC_ERROR, path);
        return;
    }

    if (lpMemScript->SetBuffer(path) == 0)
    {
        ErrorMessageBox(lpMemScript->GetLastError());
        delete lpMemScript;
        return;
    }

    this->m_RBGStartTime.clear();
    this->m_RBG_Items.clear();
    this->m_RBG_Phases.clear();
    this->m_Reward.clear();

    try
    {
        while (true)
        {
            if (lpMemScript->GetToken() == TOKEN_END)
            {
                break;
            }

            int section = lpMemScript->GetNumber();

            while (true)
            {
                if (section == 0)
                {
                    if (strcmp("end", lpMemScript->GetAsString()) == 0)
                    {
                        break;
                    }


                    this->m_Enable = lpMemScript->GetNumber();

                    this->m_Timer_Open = lpMemScript->GetAsNumber();

                    this->m_Timer_Prepare = lpMemScript->GetAsNumber();

                    this->m_Timer_Stage1 = lpMemScript->GetAsNumber();

                    this->m_Timer_Stage2 = lpMemScript->GetAsNumber();

                    this->m_Timer_Stage3 = lpMemScript->GetAsNumber();

                    this->m_Timer_StageEnd = lpMemScript->GetAsNumber();

                }
                else if (section == 1)
                {
                    if (strcmp("end", lpMemScript->GetAsString()) == 0)
                    {
                        break;
                    }

                    ROYAL_BATTLE_GROUND_START_TIME info;

                    info.Year = lpMemScript->GetNumber();

                    info.Month = lpMemScript->GetAsNumber();

                    info.Day = lpMemScript->GetAsNumber();

                    info.DayOfWeek = lpMemScript->GetAsNumber();

                    info.Hour = lpMemScript->GetAsNumber();

                    info.Minute = lpMemScript->GetAsNumber();

                    info.Second = lpMemScript->GetAsNumber();

                    this->m_RBGStartTime.push_back(info);
                }
                else if (section == 2)
                {
                    if (strcmp("end", lpMemScript->GetAsString()) == 0)
                    {
                        break;
                    }

                    this->m_Map = lpMemScript->GetNumber();

                    this->m_GateIn = lpMemScript->GetAsNumber();

                    this->m_GateOut = lpMemScript->GetAsNumber();

                    this->m_MaxPlayer = lpMemScript->GetAsNumber();

                    this->m_RegenMax = lpMemScript->GetAsNumber();

                    this->m_RewardBonus = lpMemScript->GetAsNumber();

                    this->m_JoinCost = lpMemScript->GetAsNumber();

                    this->m_TypeCoin = lpMemScript->GetAsNumber();


                }
                else if (section == 3)
                {
                    if (strcmp("end", lpMemScript->GetAsString()) == 0)
                    {
                        break;
                    }

                    RBG_Phase info;

                    info.id = lpMemScript->GetNumber();

                    info.HP = lpMemScript->GetAsNumber();

                    info.HPrate = lpMemScript->GetAsFloatNumber();

                    info.ItemCnt = lpMemScript->GetAsNumber();

                    info.ItemLoop = lpMemScript->GetAsNumber();

                    this->m_RBG_Phases.push_back(info);
                }
                else if (section == 4)
                {
                    if (strcmp("end", lpMemScript->GetAsString()) == 0)
                    {
                        break;
                    }

                    ROYAL_BATTLE_GROUND_REWARD info;

                    info.Top = lpMemScript->GetNumber();

                    info.Rate = lpMemScript->GetAsNumber();

                    info.IDItemBag = lpMemScript->GetAsNumber();

                    this->m_Reward.insert(std::pair<int, ROYAL_BATTLE_GROUND_REWARD>(info.Top, info));
                }
                else if (section == 15)
                {
                    if (strcmp("end", lpMemScript->GetAsString()) == 0)
                    {
                        break;
                    }

                    ROYAL_BATTLE_GROUND_ITEM info;

                    info.Index = lpMemScript->GetNumber() * 512 + lpMemScript->GetAsNumber();

                    info.Level = lpMemScript->GetAsNumber();

                    info.Skill = lpMemScript->GetAsNumber();

                    info.Luck = lpMemScript->GetAsNumber();

                    info.Opt = lpMemScript->GetAsNumber();

                    info.Exc = lpMemScript->GetAsNumber();

                    info.Anc = lpMemScript->GetAsNumber();

                    info.Socket[0] = lpMemScript->GetAsNumber();

                    info.Socket[1] = lpMemScript->GetAsNumber();

                    info.Socket[2] = lpMemScript->GetAsNumber();

                    info.Socket[3] = lpMemScript->GetAsNumber();

                    info.Socket[4] = lpMemScript->GetAsNumber();

                    info.SocketBonus = lpMemScript->GetAsNumber();

                    this->m_RBG_Items.push_back(info);
                }
                else
                {
                    break;
                }
            }
        }
    }
    catch (...)
    {
        ErrorMessageBox(lpMemScript->GetLastError());
    }

    delete lpMemScript;
}

void cRoyalBattleGround::MainProc()
{
    DWORD elapsed = GetTickCount() - this->m_TickCount;
    if (this->m_TargetTime == -1 || elapsed < 1000){
        return;
    }
    this->m_TickCount = GetTickCount();
    this->m_RemainTime = (int)difftime(this->m_TargetTime, time(0));

    if (this->m_State == RBG_STATE_BLANK)
    {
        gServerDisplayer.EventRoyalBattleGround = this->m_RemainTime;
    }
    else
    {
        if (gServerDisplayer.EventRoyalBattleGround != 0)
        {
            gServerDisplayer.EventRoyalBattleGround = 0;
        }
    }
    switch (this->m_State)
    {
    case RBG_STATE::RBG_STATE_BLANK:
        this->BlankProc();
        break;
    case RBG_STATE::RBG_STATE_OPEN:
        this->OpenProc();
        break;
    case RBG_STATE::RBG_STATE_PREPARE:
        this->PrepareProc();
        break;
    case RBG_STATE::RBG_STATE_BATTLE_STAGE_1:
        this->Stage1Proc();
        break;
    case RBG_STATE::RBG_STATE_BATTLE_STAGE_2:
        this->Stage2Proc();
        break;
    case RBG_STATE::RBG_STATE_BATTLE_STAGE_3:
        this->Stage3Proc();
        break;
    case RBG_STATE::RBG_STATE_BATTLE_END:
        this->StageEndProc();
        break;
    case RBG_STATE::RBG_STATE_REWARD:
        this->RewardProc();
        break;
    case RBG_STATE::RBG_STATE_CLEAR:
        this->ClearProc();
        break;
    }
}

void cRoyalBattleGround::SetState(int state)
{
    this->m_State = state;
}

void cRoyalBattleGround::CheckSync()
{
    if (this->m_RBGStartTime.empty() != 0)
    {
        this->SetState(RBG_STATE::RBG_STATE_BLANK);
        this->m_TargetTime = -1;
        this->m_EndTime = 0;
        return;
    }

    CTime ScheduleTime;

    CScheduleManager ScheduleManager;

    for (std::vector<ROYAL_BATTLE_GROUND_START_TIME>::iterator it = this->m_RBGStartTime.begin(); it != this->m_RBGStartTime.end(); it++)
    {
        ScheduleManager.AddSchedule(it->Year, it->Month, it->Day, it->Hour, it->Minute, it->Second, it->DayOfWeek);
    }

    if (ScheduleManager.GetSchedule(&ScheduleTime) == 0)
    {
        this->SetState(RBG_STATE::RBG_STATE_BLANK);
        this->m_TargetTime = -1;
        this->m_EndTime = 0;
        return;
    }

    this->m_RemainTime = (int)difftime(ScheduleTime.GetTime(), time(0));

    this->m_TargetTime = (int)ScheduleTime.GetTime();

    this->m_EndTime = (int)ScheduleTime.GetTime() +
        this->m_Timer_Open * 60 +
        this->m_Timer_Prepare * 60 +
        this->m_Timer_Stage1 * 60 +
        this->m_Timer_Stage2 * 60 +
        this->m_Timer_Stage3 * 60 +
        this->m_Timer_StageEnd * 60;
}

bool cRoyalBattleGround::GetEnabled()
{
    return this->m_Enable;
}
int cRoyalBattleGround::GetState()
{
    return this->m_State;
}
bool cRoyalBattleGround::IsOpen()
{
    return this->m_State != RBG_STATE::RBG_STATE_BLANK;
}
bool cRoyalBattleGround::IsPlaying()
{
    return this->m_State != RBG_STATE::RBG_STATE_BLANK && this->m_State != RBG_STATE::RBG_STATE_OPEN;
}
int  cRoyalBattleGround::GetOpenRemainTime()
{
    return this->m_RemainTime;
}
int cRoyalBattleGround::GetPlayRemainTime()
{
    return (int)difftime(this->m_EndTime, time(0));
}

int cRoyalBattleGround::GetRemainTime()
{
    this->m_RemainTime = (int)difftime(this->m_TargetTime, time(0));
    return this->m_RemainTime;
}
void cRoyalBattleGround::BlankProc()
{
    if (this->m_RemainTime <= 0)
    {
        this->m_TargetTime += this->m_Timer_Open * 60;
        this->SetState(RBG_STATE::RBG_STATE_OPEN);
        this->RemoveObject();
        this->SendPhaseToAllUsers();
        gNotice.GCNoticeSendToAll(0, 0, 0, 0, 0, 0, "[Battle Royale Event] será fechado em %d minutos", this->m_Timer_Open);
    }
}

void cRoyalBattleGround::OpenProc()
{
    if (this->m_RemainTime <= 0)
    {
        if (this->CountMember() < 2)
        {
            gNotice.GCNoticeSendToAll(0, 0, 0, 0, 0, 0, "[Battle Royale Event] Cancelado por falta de jogadores!");

            for (int n = 0; n < RBG_MAX_PLAYER; n++)
            {
                if (OBJECT_RANGE(this->Player[n].Index) == 0 || this->Player[n].Live == 0)
                {
                    continue;
                }

                gNotice.GCNoticeSend(this->Player[n].Index, 1, 0, 0, 0, 0, 0, "[Battle Royale Event] Reembolso (%d) (%s)", this->m_JoinCost, GetNameCoinType(this->m_TypeCoin));
                GDSetCoinSend(this->Player[n].Index, +(this->m_TypeCoin == 1 ? this->m_JoinCost : 0), +(this->m_TypeCoin == 2 ? this->m_JoinCost : 0), +(this->m_TypeCoin == 3 ? this->m_JoinCost : 0), "[Royal]Re Coin");
                this->UserMoveOut(this->Player[n].Index);
            }
            this->SetState(RBG_STATE::RBG_STATE_CLEAR);
            return;
        }
        this->m_TargetTime += this->m_Timer_Prepare * 60;
        this->SetState(RBG_STATE::RBG_STATE_PREPARE);
        this->SendPhaseToEventUsers();
    }
    else
    {
        if (this->m_RemainTime % 60 == 0)
        {
            gNotice.GCNoticeSendToAll(0, 0, 0, 0, 0, 0, "[Battle Royale Event] Fechado após %d minutos", this->m_RemainTime / 60);
        }
    }
}

void cRoyalBattleGround::PrepareProc()
{
    if (this->m_RemainTime <= 0)
    {

        this->CalcUserRank();
        this->m_TargetTime += this->m_Timer_Stage1 * 60;
        this->SetState(RBG_STATE::RBG_STATE_BATTLE_STAGE_1);
        this->MakeZonePhase(1);
        this->SendPhaseToEventUsers();
        this->MoveUserPosition();
    }
}

void cRoyalBattleGround::Stage1Proc()
{
    if (this->m_RemainTime <= 0)
    {
        this->m_TargetTime += this->m_Timer_Stage2 * 60;
        this->SetState(RBG_STATE::RBG_STATE_BATTLE_STAGE_2);
        this->ThuongCoin(RBG_STATE::RBG_STATE_BATTLE_STAGE_1);
        this->MakeZonePhase(2);
        this->SendPhaseToEventUsers();
    }
    else
    {
        this->MakeDropItem();
        this->DangerousZone();
    }
}
void cRoyalBattleGround::Stage2Proc()
{
    if (this->m_RemainTime <= 0)
    {
        this->m_TargetTime += this->m_Timer_Stage3 * 60;
        this->SetState(RBG_STATE::RBG_STATE_BATTLE_STAGE_3);
        this->ThuongCoin(RBG_STATE::RBG_STATE_BATTLE_STAGE_2);
        this->MakeZonePhase(3);
        this->SendPhaseToEventUsers();
    }
    else
    {
        this->MakeDropItem();
        this->DangerousZone();
    }
}
void cRoyalBattleGround::Stage3Proc()
{
    if (this->m_RemainTime <= 0)
    {
        this->m_TargetTime += this->m_Timer_StageEnd * 60;
        this->SetState(RBG_STATE::RBG_STATE_BATTLE_END);
        this->ThuongCoin(RBG_STATE::RBG_STATE_BATTLE_STAGE_3);
        this->SendPhaseToEventUsers();

        GCServerMsgStringSendToMap(this->m_Map, 0, "[Battle Royale Event] Fim do Evento, prepare-se para recompensas!!", this->m_TotalPlayerJoin, this->m_TotalReward);
    }
    else
    {
        this->MakeDropItem();
        this->DangerousZone();
    }
}
void cRoyalBattleGround::StageEndProc()
{
    if (this->m_RemainTime <= 0)
    {
        this->SetState(RBG_STATE::RBG_STATE_REWARD);
    }
}

void cRoyalBattleGround::RewardProc()
{
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        int aIndex = this->Player[i].Index;
        if (aIndex != -1)
        {
            if (gObjIsConnectedGP(aIndex) == 0)
            {
                continue;
            }
            std::map<int, ROYAL_BATTLE_GROUND_REWARD>::iterator it = this->m_Reward.find(this->Player[i].Rank);
            if (it == this->m_Reward.end())
            {
                continue;
            }

            this->RollBackCharacterInfo(aIndex);

            if (it->second.IDItemBag != -1)
            {
                LogAdd(LOG_RED, "[Battle Royale Event] Bônus %d (ItemBag %d)", this->Player[i].Rank, it->second.IDItemBag);
                gItemBagManager.DropItemByIndexItemBag(it->second.IDItemBag, &gObj[aIndex]);
            }
            int CongCoin = (this->m_TotalReward * it->second.Rate) / 100;
            gNotice.GCNoticeSend(aIndex, 0, 0, 0, 0, 0, 0, "[%s] Classificação (%d) Recebido: %d (%s)", gObj[aIndex].Name, this->Player[i].Rank, CongCoin, GetNameCoinType(this->m_TypeCoin));
            if (this->m_TypeCoin > 0)
            {
                GDSetCoinSend(aIndex, +(this->m_TypeCoin == 1 ? CongCoin : 0), +(this->m_TypeCoin == 2 ? CongCoin : 0), +(this->m_TypeCoin == 3 ? CongCoin : 0), "[EventChayBo]ThuongTop");
            }
            else
            {
                gObj[aIndex].Money += (int)CongCoin;
                GCMoneySend(aIndex, gObj[aIndex].Money);
            }

            this->DelMember(aIndex);
        }
    }
    this->SetState(RBG_STATE::RBG_STATE_CLEAR);
}

void cRoyalBattleGround::ClearProc()
{
    this->CheckSync();
    this->SetState(RBG_STATE::RBG_STATE_BLANK);
    this->SendPhaseToEventUsers();
    this->ClearSection();
}
void cRoyalBattleGround::ClearSection()
{
    this->DelAllMembers();
    this->SetZone(0, 0, 255, 255);
    this->m_TotalReward = this->m_RewardBonus;
}

void cRoyalBattleGround::ChangeUserInfo()
{
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        int aIndex = this->Player[i].Index;
        if (aIndex != -1)
        {
            if (gObjIsConnectedGP(aIndex) == 0)
            {
                this->DelMember(aIndex);
                continue;
            }

            this->ChangeUserInfo(aIndex);
        }
    }
}

void cRoyalBattleGround::MoveUserPosition()
{
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        int aIndex = this->Player[i].Index;
        if (aIndex != -1)
        {
            if (gObjIsConnectedGP(aIndex) == 0)
            {
                this->DelMember(aIndex);
                continue;
            }
            LPOBJ lpObj = &gObj[aIndex];
            int x, y;
            if (this->GetPosRandomFromBo(&x, &y) == 0)
            {
                continue;
            }
        }
    }
}

bool cRoyalBattleGround::CheckUserList(int aIndex)
{
    if (!this->IsOpen())
    {
        return false;
    }
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        if (this->Player[i].Index == aIndex)
        {
            return true;
        }
    }
    return false;
}

bool cRoyalBattleGround::CheckUserPostion(int aIndex)
{
    LPOBJ lpObj = &gObj[aIndex];

    if (gObjIsConnectedGP(aIndex) == 0)
    {
        return false;
    }

    if (!this->IsOpen())
    {
        return false;
    }
    bool isEventUser = this->CheckUserList(aIndex);
    if (!isEventUser && lpObj->Map == this->m_Map)
    {
        gObjMoveGate(lpObj->Index, this->m_GateOut);
        return true;
    }
    else if (isEventUser && lpObj->Map != this->m_Map)
    {
        this->DelMember(aIndex);
    }

    return false;
}

void cRoyalBattleGround::RemoveObject()
{
    for (int n = 0; n < MAX_OBJECT_MONSTER; n++)
    {
        if (gObj[n].Type != OBJECT_MONSTER && gObj[n].Type != OBJECT_NPC)
        {
            continue;
        }

        if (gObj[n].Map != this->m_Map)
        {
            continue;
        }

#if(GAMESERVER_TYPE==1)
        if (gObj[n].CsNpcType != 0)
        {
            continue;
        }
#endif
        gObjDel(n);
    }
}

void cRoyalBattleGround::MemberRequestJoin(int aIndex)
{
    if (this->AddMember(aIndex))
    {
        LogAdd(LOG_GREEN, "Add member: %s", gObj[aIndex].Name);
        this->SendPhaseToUser(aIndex);
        this->BackupAddUser(aIndex);
        this->ChangeUserInfo(aIndex);
        this->SendPointToEventUsers();
        return;
    }
    LogAdd(LOG_GREEN, "Add member failed!");
}

bool cRoyalBattleGround::AddMember(int aIndex)
{
    LPOBJ lpObj = &gObj[aIndex];

    if (gObjIsConnectedGP(aIndex) == 0)
    {
        return false;
    }

    this->CountMember();

    if (this->m_TotalPlayer >= RBG_MAX_PLAYER)
    {
        gNotice.GCNoticeSend(aIndex, 1, 0, 0, 0, 0, 0, "O evento está lotado");
        //
        return false;
    }

    if (this->m_State != RBG_STATE_OPEN)
    {
        gNotice.GCNoticeSend(aIndex, 1, 0, 0, 0, 0, 0, "Ainda não é hora de entrar!");
        return false;
    }

    int bestChoice = -1;
    int worstChoice = -1;
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        if (this->Player[i].Index == aIndex)
        {
            return false;
        }
        else if (bestChoice == -1 && this->Player[i].Index == -1)
        {
            bestChoice = i;
        }
    }
    if (bestChoice != -1)
    {
        if (m_TypeCoin == 0)
        {
            if (lpObj->Money < this->m_JoinCost)
            {
                gNotice.GCNoticeSend(aIndex, 1, 0, 0, 0, 0, 0, "Zen insuficiente!");
                return false;
            }
            /*
            cost
            */
            lpObj->Money -= this->m_JoinCost;
            GCMoneySend(lpObj->Index, lpObj->Money);
        }
        else
        {
            if (this->m_TypeCoin == 1 && lpObj->Coin1 < this->m_JoinCost)
            {
                gNotice.GCNoticeSend(aIndex, 1, 0, 0, 0, 0, 0, "XCoin insuficiente!");
                return false;
            }
            if (this->m_TypeCoin == 2 && lpObj->Coin2 < this->m_JoinCost)
            {
                gNotice.GCNoticeSend(aIndex, 1, 0, 0, 0, 0, 0, "HCoin insuficiente!");
                return false;
            }
            if (this->m_TypeCoin == 3 && lpObj->Coin3 < this->m_JoinCost)
            {
                gNotice.GCNoticeSend(aIndex, 1, 0, 0, 0, 0, 0, "Point insuficiente!");
                return false;
            }
            //==Tru Coin
            GDSetCoinSend(aIndex, -(this->m_TypeCoin == 1 ? this->m_JoinCost : 0), -(this->m_TypeCoin == 2 ? this->m_JoinCost : 0), -(this->m_TypeCoin == 3 ? this->m_JoinCost : 0), "[EventChayBo]CoinThamgia");
        }

        this->m_TotalReward += this->m_JoinCost;

        this->Player[bestChoice].Index = aIndex;
        this->Player[bestChoice].Point = 0;
        this->Player[bestChoice].Live = true;
        gObjMoveGate(lpObj->Index, this->m_GateIn);
        this->CountMember();
        this->m_TotalPlayerJoin++;
        GCServerMsgStringSendToMap(this->m_Map, 1, "[Battle Royale Event] Total de %d participantes (Total do Premio %d [%s])", this->m_TotalPlayerJoin, this->m_TotalReward, GetNameCoinType(this->m_TypeCoin));
        return true;
    }
    gNotice.GCNoticeSend(aIndex, 1, 0, 0, 0, 0, 0, "Join battle failed!");
    return false;
}
bool cRoyalBattleGround::DelMember(int aIndex)
{
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        if (this->Player[i].Index == aIndex)
        {
            this->Player[i].Index = -1;
            this->Player[i].Point = 0;
            this->Player[i].Live = false;

            if (gObjIsConnectedGP(aIndex))
            {
                gObjMoveGate(aIndex, this->m_GateOut);
                this->RollBackCharacterInfo(aIndex);
                this->BackupDelUser(aIndex);
                this->SendPhaseToUser(aIndex, true);
            }
            return true;
        }
    }
    return false;
}
bool cRoyalBattleGround::DelAllMembers()
{
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        if (this->Player[i].Index != -1)
        {
            if (gObjIsConnectedGP(this->Player[i].Index))
            {
                gObjMoveGate(this->Player[i].Index, this->m_GateOut);
            }
        }
        this->Player[i].Reset();
    }
    this->m_TotalPlayerJoin = 0;
    return true;
}
int  cRoyalBattleGround::CountMember()
{
    this->m_TotalPlayer = 0;
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        if (this->Player[i].Index != -1)
        {
            if (gObjIsConnectedGP(this->Player[i].Index) == 0)
            {
                this->DelMember(this->Player[i].Index);
                continue;
            }

            this->m_TotalPlayer++;
        }
    }
    return this->m_TotalPlayer;
}

int  cRoyalBattleGround::GetPoint(int aIndex)
{
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        if (this->Player[i].Index == aIndex)
        {
            return this->Player[i].Point;
        }
    }
    return 0;
}

int  cRoyalBattleGround::GetTop(int aIndex)
{
    this->CalcUserRank();
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        if (this->Player[i].Index == aIndex)
        {
            return this->Player[i].Rank;
        }
    }
    return 0;
}
void cRoyalBattleGround::SendPointToUser(int aIndex)
{
    LPOBJ lpObj = &gObj[aIndex];

    if (gObjIsConnectedGP(aIndex) == 0)
    {
        return;
    }

    PSWMSG_ROYAL_BATTLE_GROUND_POINT_SEND pMsg = { 0 };

    pMsg.header.set(0xA9, 0x11, sizeof(pMsg));

    pMsg.Alive = this->m_TotalPlayer;

    pMsg.Total = this->m_TotalPlayerJoin;

    pMsg.Kill = this->GetPoint(aIndex);

    pMsg.Top = this->GetTop(aIndex);

    DataSend(aIndex, (BYTE*)&pMsg, sizeof(pMsg));
}

void cRoyalBattleGround::SendBXH(int aIndex)
{
    this->CalcUserRank();

    BYTE send[4096];

    PMSG_NEW_HEALTH_BAR_SEND pMsg;

    pMsg.header.set(0xA9, 0x14, 0);

    int size = sizeof(pMsg);

    pMsg.count = 0;

    BEVENTDATA_BXH info;

    int CountRank = 0;
    for (int n = 0; n < 10; n++)
    {
        if (OBJECT_RANGE(this->Player[this->mIndexRank[n]].Index) == 0)
        {
            continue;
        }
        if (this->Player[this->mIndexRank[n]].Rank > 0 && this->Player[this->mIndexRank[n]].Rank <= 10)
        {
            memcpy(info.szName, gObj[this->Player[this->mIndexRank[n]].Index].Name, sizeof(info.szName));
            info.Kill = this->Player[this->mIndexRank[n]].Point;
            pMsg.count++;

            memcpy(&send[size], &info, sizeof(info));
            size += sizeof(info);

            CountRank++;
        }

    }
    pMsg.header.size[0] = SET_NUMBERHB(size);
    pMsg.header.size[1] = SET_NUMBERLB(size);
    // ---
    memcpy(send, &pMsg, sizeof(pMsg));

    DataSend(aIndex, send, size);
}
void cRoyalBattleGround::SendPointToEventUsers()
{
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        if (this->Player[i].Index != -1)
        {
            this->SendPointToUser(this->Player[i].Index);
            this->SendBXH(this->Player[i].Index);
        }
    }
}
void cRoyalBattleGround::SendPhaseToUser(int aIndex, bool Close)
{
    LPOBJ lpObj = &gObj[aIndex];

    if (gObjIsConnectedGP(aIndex) == 0)
    {
        return;
    }

    PSWMSG_ROYAL_BATTLE_GROUND_PHASE_SEND pMsg = { 0 };

    pMsg.header.set(0xA9, 0x10, sizeof(pMsg));

    pMsg.Phase = Close ? this->m_State : RBG_STATE::RBG_STATE_BLANK;

    pMsg.Remain = this->m_RemainTime;
    pMsg.Map = this->m_Map;

    pMsg.Zone[0] = this->m_Zone[0];
    pMsg.Zone[1] = this->m_Zone[1];
    pMsg.Zone[2] = this->m_Zone[2];
    pMsg.Zone[3] = this->m_Zone[3];

    DataSend(aIndex, (BYTE*)&pMsg, sizeof(pMsg));
}
void cRoyalBattleGround::SendPhaseToAllUsers()
{
    this->GetRemainTime();
    for (int n = OBJECT_START_USER; n < MAX_OBJECT; n++)
    {
        if (gObjIsConnectedGP(n) != 0)
        {
            this->SendPhaseToUser(n);
        }
    }
}

void cRoyalBattleGround::SendPhaseToEventUsers()
{
    this->GetRemainTime();
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        if (this->Player[i].Index != -1)
        {
            if (gObjIsConnectedGP(this->Player[i].Index) != 0)
            {
                this->SendPhaseToUser(this->Player[i].Index);
            }
        }
    }
}

void cRoyalBattleGround::SendKillToEventUsers(int aIndex, int bIndex)
{
    PSWMSG_ROYAL_BATTLE_GROUND_KILL_SEND pMsg = { 0 };

    pMsg.header.set(0xA9, 0x12, sizeof(pMsg));

    pMsg.ComboKill = 0;

    pMsg.Rank = 0;

    memcpy(pMsg.Player, gObj[aIndex].Name, sizeof(gObj[aIndex].Name));

    memcpy(pMsg.Target, gObj[bIndex].Name, sizeof(gObj[bIndex].Name));

    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        if (this->Player[i].Index != -1)
        {
            if (gObjIsConnectedGP(this->Player[i].Index) != 0)
            {
                DataSend(this->Player[i].Index, (BYTE*)&pMsg, sizeof(pMsg));
            }
        }
    }
}

void cRoyalBattleGround::KillProc(int aIndex, int bIndex)
{
    LPOBJ lpObj = &gObj[aIndex];
    LPOBJ lpTarget = &gObj[bIndex];

    if (gObjIsConnectedGP(aIndex) == 0 || gObjIsConnectedGP(bIndex) == 0)
    {
        return;
    }
    if (lpObj->Type != OBJECT_USER || lpTarget->Type != OBJECT_USER)
    {
        return;
    }

    if (!this->CheckUserList(aIndex) || !this->CheckUserList(bIndex))
    {
        return;
    }
    this->CountMember();
    this->AddPlayerPoint(aIndex, 1);
    this->SendKillToEventUsers(aIndex, bIndex);
    this->RewardProc(bIndex);
    this->DelMember(bIndex);
    this->CountMember();
    this->SendPointToEventUsers();
}

void cRoyalBattleGround::AddPlayerPoint(int aIndex, int point)
{
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        if (this->Player[i].Index == aIndex)
        {
            if (gObjIsConnectedGP(this->Player[i].Index) != 0)
                this->Player[i].Point += point;
        }
    }
}

void cRoyalBattleGround::SetPlayerPoint(int aIndex, int point)
{
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        if (this->Player[i].Index == aIndex)
        {
            if (gObjIsConnectedGP(this->Player[i].Index) != 0)
                this->Player[i].Point = point;
        }
    }
}

void cRoyalBattleGround::RewardProc(int aIndex)
{
    this->CountMember();
    LogAdd(LOG_RED, "RewardProc: %d player left -> top %d", this->m_TotalPlayer, this->m_TotalPlayer);

    for (int i = 0; i < this->m_Reward.size(); i++)
    {
        if (this->m_Reward[i].Top == this->m_TotalPlayer)
        {
            gNotice.GCNoticeSend(aIndex, 1, 0, 0, 0, 0, 0, "Você é o melhor %d!", this->m_TotalPlayer);
        }
    }
}

void cRoyalBattleGround::RecvRequest(BYTE* lpMsg, int aIndex)
{
    PMSG_ROYAL_BATTLE_GROUND_REQUEST_RECV* Data = (PMSG_ROYAL_BATTLE_GROUND_REQUEST_RECV*)lpMsg;
    switch (Data->type)
    {
    case 0x0:
        switch (Data->value)
        {
        case 0x0:
            break;
        case 0x1:
            this->MemberRequestJoin(aIndex);
            break;
        default:
            break;
        }
        break;
    default:
        break;
    }

}

RBG_Phase* cRoyalBattleGround::GetPhase(int id)
{
    for (int i = 0; i < this->m_RBG_Phases.size(); i++)
    {
        if (this->m_RBG_Phases[i].id == id)
        {
            return &this->m_RBG_Phases[i];
        }
    }

    return 0;
}

void cRoyalBattleGround::MakeZonePhase(int id)
{
    RBG_Phase *phase = this->GetPhase(id);
    if (phase != 0)
    {
        if (!this->m_Zone[0] && !this->m_Zone[1])
        {
        
        }
        else
        {
        
        }

        this->m_PhaseLastDrop = GetTickCount();
        this->m_PhaseDropDelay = phase->ItemLoop;
        this->m_PhaseDropCount = phase->ItemCnt;
        this->m_ZoneHP = phase->HP;
        this->m_ZoneHPrate = phase->HPrate;
        this->SendPhaseToEventUsers();
    }
    else
    {
        this->m_PhaseLastDrop = GetTickCount();
        this->m_PhaseDropDelay = 999999;
        this->m_PhaseDropCount = 0;
        this->m_ZoneHP = 0;
        this->m_ZoneHPrate = 0;
        this->SendPhaseToEventUsers();
    }
}

void cRoyalBattleGround::SetZone(short X, short Y, short W, short H)
{
    this->m_Zone[0] = X;
    this->m_Zone[1] = Y;
    this->m_Zone[2] = W;
    this->m_Zone[3] = H;
}

void cRoyalBattleGround::MakeDropItem()
{
    if (this->m_RBG_Items.size() == 0 || !this->m_PhaseDropCount || this->m_PhaseLastDrop + this->m_PhaseDropDelay > GetTickCount())
    {
        return;
    }

    this->m_PhaseLastDrop = GetTickCount();

    for (int i = 0; i < this->m_PhaseDropCount; i++)
    {

        short x, y;
        while (true)
        {
            x = this->m_Zone[0] + GetLargeRand() % this->m_Zone[2];
            y = this->m_Zone[1] + GetLargeRand() % this->m_Zone[3];

            if (gMap[this->m_Map].CheckAttr(x, y, 4) == 0 && gMap[this->m_Map].CheckAttr(x, y, 8) == 0)
            {
                ROYAL_BATTLE_GROUND_ITEM* item = &this->m_RBG_Items[GetLargeRand() % this->m_RBG_Items.size()];

                GDCreateItemSend(this->Player[0].Index, this->m_Map, x, y, item->Index, (BYTE)item->Level, 0, item->Skill, item->Luck, item->Opt, -1, item->Exc, item->Anc, 0, 0, 0, 0, 0);
                break;
            }
        }
    }
}

void cRoyalBattleGround::DangerousZone()
{
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        if (this->Player[i].Index != -1)
        {
            if (gObjIsConnectedGP(this->Player[i].Index) != 0)
            {
                if (this->CheckSafeZone(this->Player[i].Index))
                {
                    continue;
                }
                this->ZoneHitUser(this->Player[i].Index);
            }
        }
    }
}

bool cRoyalBattleGround::CheckSafeZone(int aIndex)
{
    if (this->m_State != RBG_STATE_BATTLE_STAGE_1 &&
        this->m_State != RBG_STATE_BATTLE_STAGE_2 &&
        this->m_State != RBG_STATE_BATTLE_STAGE_3)
    {
        return true;
    }

    LPOBJ lpObj = &gObj[aIndex];

    if (gObjIsConnectedGP(aIndex) == 0)

        return true;

    if (lpObj->X >= this->m_Zone[0] && lpObj->X <= (this->m_Zone[0] + this->m_Zone[2]) &&
        lpObj->Y >= this->m_Zone[1] && lpObj->Y <= (this->m_Zone[1] + this->m_Zone[3]))
    {
        return true;
    }
    return false;
}

void cRoyalBattleGround::ZoneHitUser(int aIndex)
{
    LPOBJ lpObj = &gObj[aIndex];

    if (gObjIsConnectedGP(aIndex) == 0)
        return;

    if (this->m_ZoneHP || this->m_ZoneHPrate)
    {
        int TruMauNgoaiBo = (lpObj->Life*this->m_ZoneHPrate);
        TruMauNgoaiBo += this->m_ZoneHP;
        lpObj->Life -= TruMauNgoaiBo;

        gEffectManager.AddEffect(lpObj, 0, EFFECT_SWORD_SLASH, 20, 0, 0, 0, 0);//ok
        gObjectManager.CharacterLifeCheck(lpObj, lpObj, (TruMauNgoaiBo), 0, 0, 0, 0, lpObj->Shield);
    }
}

bool CBBackUpCharacter(int aIndex) // OK
{
    if (OBJECT_RANGE(aIndex) == 0)
    {
        return 0;
    }

    LPOBJ lpObj = &gObj[aIndex];

    if (lpObj->CB_Status == 1)
    {
        return 0;
    }

    for (int n = 0; n < MAX_SKILL_LIST; n++)
    {
        lpObj->SkillBackup[n] = lpObj->Skill[n];
    }

    for (int n = 0; n < INVENTORY_SIZE; n++)
    {
        lpObj->Inventory2[n] = lpObj->Inventory1[n];
    }

#if(GAMESERVER_UPDATE>=802)

    for (int n = 0; n < EVENT_INVENTORY_SIZE; n++)
    {
        lpObj->EventInventory2[n] = lpObj->EventInventory1[n];
    }

#endif

    memcpy(lpObj->InventoryMap2, lpObj->InventoryMap1, INVENTORY_SIZE);

#if(GAMESERVER_UPDATE>=802)

    memcpy(lpObj->EventInventoryMap2, lpObj->EventInventoryMap1, EVENT_INVENTORY_SIZE);

#endif

    gObjSetInventory2Pointer(lpObj);

    gObjSetEventInventory2Pointer(lpObj);

    lpObj->CB_Status = 1;
    return 1;
}



bool CBResetCharacter(int aIndex) // OK
{
    if (OBJECT_RANGE(aIndex) == 0)
    {
        return 0;
    }

    LPOBJ lpObj = &gObj[aIndex];

    if (lpObj->CB_Status != 1)
    {
        return 0;
    }

    for (int n = 0; n < MAX_SKILL_LIST; n++)
    {
        lpObj->Skill[n] = lpObj->SkillBackup[n];
    }

    for (int n = 0; n < INVENTORY_SIZE; n++)
    {
        lpObj->Inventory2[n].Clear();
    }

#if(GAMESERVER_UPDATE>=802)

    for (int n = 0; n < EVENT_INVENTORY_SIZE; n++)
    {
        lpObj->EventInventory2[n].Clear();
    }

#endif

    gObjSetInventory1Pointer(lpObj);

    gObjSetEventInventory1Pointer(lpObj);

    lpObj->CB_Status = 0;
    return 1;
}
bool cRoyalBattleGround::BackupAddUser(int aIndex)
{
    LPOBJ lpObj = &gObj[aIndex];

    if (gObjIsConnectedGP(aIndex) == 0)
        return false;

    for (int i = 0; i < this->m_BackupCharacter.size(); i++)
    {
        OBJECTSTRUCT bu = this->m_BackupCharacter[i];
        if (bu.Index == aIndex)
        {
            this->BackupDelUser(aIndex);
            goto PUSH_IT;
            return true;
        }
    }
PUSH_IT:
    OBJECTSTRUCT nObj;

    nObj = gObj[aIndex];
    memcpy(&nObj.Effect, gObj[aIndex].Effect, sizeof(gObj[aIndex].Effect));
    memcpy(&nObj.Skill, gObj[aIndex].Skill, sizeof(gObj[aIndex].Skill));

    CBBackUpCharacter(aIndex);

    this->m_BackupCharacter.push_back(nObj);
    return true;
}

OBJECTSTRUCT cRoyalBattleGround::BackupGetUser(int aIndex)
{
    for (int i = 0; i < this->m_BackupCharacter.size(); i++)
    {
        OBJECTSTRUCT cObj = this->m_BackupCharacter[i];
        if (cObj.Index == aIndex)
        {
            return cObj;
        }
    }
    OBJECTSTRUCT nObj;
    nObj.Index = -1;

    return nObj;
}
bool cRoyalBattleGround::BackupDelUser(int aIndex)
{
    for (int i = 0; i < this->m_BackupCharacter.size(); i++)
    {
        OBJECTSTRUCT cObj = this->m_BackupCharacter[i];
        if (cObj.Index == aIndex)
        {
            this->m_BackupCharacter.erase(this->m_BackupCharacter.begin() + i);
            return true;
        }
    }
    return false;
}

bool cRoyalBattleGround::RollBackCharacterInfo(int aIndex)
{
    LPOBJ lpObj = &gObj[aIndex];

    if (gObjIsConnectedGP(aIndex) == 0)
        return false;

    OBJECTSTRUCT lpObjBackup = this->BackupGetUser(aIndex);
    if (lpObjBackup.Index == -1)
    {

        return false;
    }

    CBResetCharacter(aIndex);

    for (int n = 0; n < MAX_EFFECT_LIST; n++){
        lpObj->Effect[n] = lpObj->EffectBackup[n];
    }


    for (int n = 0; n < MAX_MASTER_SKILL_LIST; n++)
    {
        lpObj->MasterSkill[n] = lpObj->MasterSkillBackup[n];
    }

    gObj[aIndex].Money = lpObjBackup.Money;

    gObj[aIndex].MasterLevel = lpObjBackup.MasterLevel;
    gObj[aIndex].MasterPoint = lpObjBackup.MasterPoint;
    gObj[aIndex].Level = lpObjBackup.Level;
    gObj[aIndex].LevelUpPoint = lpObjBackup.LevelUpPoint;

    gObj[aIndex].Strength = lpObjBackup.Strength;
    gObj[aIndex].Dexterity = lpObjBackup.Dexterity;
    gObj[aIndex].Vitality = lpObjBackup.Vitality;
    gObj[aIndex].Energy = lpObjBackup.Energy;
    gObj[aIndex].Leadership = lpObjBackup.Leadership;
    gObj[aIndex].AddStrength = lpObjBackup.AddStrength;
    gObj[aIndex].AddDexterity = lpObjBackup.AddDexterity;
    gObj[aIndex].AddVitality = lpObjBackup.AddVitality;
    gObj[aIndex].AddEnergy = lpObjBackup.AddEnergy;
    gObj[aIndex].AddLeadership = lpObjBackup.AddLeadership;

    gSkillManager.GCSkillListSend(lpObj, 0);


    GCMoneySend(aIndex, lpObj->Money);

    gObjectManager.CharacterCalcAttribute(lpObj->Index);
    GCNewCharacterInfoSend(lpObj);

    if (gSkillManager.SkillChangeUse(aIndex) != 0)
    {
        gObjViewportListProtocolCreate(&gObj[aIndex]);
        gObjectManager.CharacterUpdateMapEffect(&gObj[aIndex]);
    }

    gItemManager.GCItemListSend(lpObj->Index);
    GCMoneySend(lpObj->Index, lpObj->Money);
    gObjectManager.CharacterMakePreviewCharSet(lpObj->Index);
    gItemManager.GCItemEquipmentSend(lpObj->Index);

    gObjectManager.CharacterCalcAttribute(lpObj->Index);
    GCNewCharacterInfoSend(lpObj);

    this->BackupDelUser(aIndex);
    GDCharacterInfoSaveSend(lpObj->Index);

    return true;
}

void cRoyalBattleGround::ChangeUserInfo(int aIndex)
{
    LPOBJ lpObj = &gObj[aIndex];
    int n;

    if (gObjIsConnectedGP(aIndex) == 0)
        return;

    GDCharacterInfoSaveSend(lpObj->Index);


    //delete item
    int MaxValue = gItemManager.GetInventoryMaxValue(lpObj);
    for (n = 0; n < MaxValue; n++)
    {
        gItemManager.InventoryDelItem(lpObj->Index, n);
        gItemManager.GCItemDeleteSend(lpObj->Index, n, 1);
    }
    for (int o = INVENTORY_EXT4_SIZE; o < INVENTORY_FULL_SIZE; o++)
    {
        gItemManager.InventoryDelItem(lpObj->Index, o);
        gItemManager.GCItemDeleteSend(lpObj->Index, o, 1);
    }

    for (n = 0; n < MAX_EFFECT_LIST; n++)
    {
        lpObj->EffectBackup[n] = lpObj->Effect[n];
        gEffectManager.DelEffect(lpObj, n);
    }

    lpObj->MasterLevel = 1;

    lpObj->MasterPoint = 0;

    for (int n = 0; n < MAX_MASTER_SKILL_LIST; n++)
    {
        lpObj->MasterSkillBackup[n] = lpObj->MasterSkill[n];
        lpObj->MasterSkill[n].Clear();
    }

    gSkillManager.GCSkillListSend(lpObj, 0);

    lpObj->Money = 2000000000;

    GCMoneySend(aIndex, lpObj->Money);

    //delete stat
    lpObj->Strength = 50;
    lpObj->Dexterity = 50;
    lpObj->Vitality = 50;
    lpObj->Energy = 50;
    lpObj->Leadership = 0;

    lpObj->AddStrength = 0;
    lpObj->AddDexterity = 0;
    lpObj->AddVitality = 0;
    lpObj->AddEnergy = 0;
    lpObj->AddLeadership = 0;

    lpObj->LevelUpPoint = 15000;
    lpObj->Level = 400;
    lpObj->ChangeSkin = 0;

    gCustomRankUser.GCReqRankLevelUser(lpObj->Index, lpObj->Index);

    if (gSkillManager.SkillChangeUse(aIndex) != 0)
    {
        gObjViewportListProtocolCreate(&gObj[aIndex]);
        gObjectManager.CharacterUpdateMapEffect(&gObj[aIndex]);
    }
    gItemManager.GCItemListSend(lpObj->Index);
    GCMoneySend(lpObj->Index, lpObj->Money);
    gObjectManager.CharacterMakePreviewCharSet(lpObj->Index);
    gItemManager.GCItemEquipmentSend(lpObj->Index);
    gObjectManager.CharacterCalcAttribute(lpObj->Index);
    GCNewCharacterInfoSend(lpObj);


    return;
}


void cRoyalBattleGround::StartBattle()
{
    this->ClearProc();

    this->m_RemainTime = 10;

    this->m_TargetTime = time(0) + 10;

    this->m_EndTime = this->m_TargetTime +
        this->m_Timer_Open * 60 +
        this->m_Timer_Prepare * 60 +
        this->m_Timer_Stage1 * 60 +
        this->m_Timer_Stage2 * 60 +
        this->m_Timer_Stage3 * 60 +
        this->m_Timer_StageEnd * 60;

    this->SendPhaseToAllUsers();
}

bool cRoyalBattleGround::CheckPrepareZone(int aIndex)
{
    return this->m_State != RBG_STATE_BATTLE_STAGE_1 &&
        this->m_State != RBG_STATE_BATTLE_STAGE_2 &&
        this->m_State != RBG_STATE_BATTLE_STAGE_3 &&
        this->CheckUserList(aIndex);
}

bool cRoyalBattleGround::IsOnMapEvent(int aIndex)
{
    LPOBJ lpObj = &gObj[aIndex];

    if (gObjIsConnectedGP(aIndex) == 0)
        return false;

    return lpObj->Map == this->m_Map;
}

void cRoyalBattleGround::UserMoveOut(int aIndex)
{

    LPOBJ lpObj = &gObj[aIndex];

    if (gObjIsConnectedGP(aIndex) == 0)
        return;

    if (this->m_State >= RBG_STATE_BATTLE_STAGE_1 && this->m_State <= RBG_STATE_BATTLE_END)
    {
        this->KillProc(aIndex, aIndex);
        return;
    }

    this->DelMember(aIndex);
    this->CountMember();
    this->SendPointToEventUsers();
    return;
}

bool cRoyalBattleGround::UserDieProc(LPOBJ lpObj, LPOBJ lpTarget)
{
    if (!this->IsOnMapEvent(lpObj->Index))
    {
        return 0;
    }
    if (!RoyalBattleGround.CheckUserList(lpObj->Index))
    {
        return 0;
    }
    if (this->m_State < RBG_STATE_PREPARE && this->m_State > RBG_STATE_BATTLE_STAGE_3)
    {
        return 0;
    }

    RBG_Player* lpUserA = this->GetUser(lpObj->Index);

    if (lpUserA == 0)
    {
        return 0;
    }

    RBG_Player* lpUserB = this->GetUser(lpTarget->Index);

    if (lpUserB == 0)
    {
        return 0;
    }

    lpUserA->Regen++; 

    if (lpUserA->Point > 0)
    {
        lpUserA->Point -= 1;
    }
    LogAdd(LOG_RED, "[%s] Kill [%s]", lpObj->Name, lpTarget->Name);

    if (lpUserB->Index != lpUserA->Index)
    {
        lpUserB->Point += 1; 
        this->SendKillToEventUsers(lpUserB->Index, lpUserA->Index);
    }
    if (lpUserA->Regen >= 5)
    {
        this->DelMember(lpUserA->Index);
    }
    this->CountMember();
    this->SendPointToEventUsers();
    return 1;
}
void cRoyalBattleGround::CalcUserRank() // OK
{

    for (int stt = 0; stt < 10; stt++)
    {
        this->mIndexRank[stt] = -1;
    }
    for (int n = 0; n < RBG_MAX_PLAYER; n++)
    {
        if (OBJECT_RANGE(this->Player[n].Index) == 0)
        {
            continue;
        }

        int rank = RBG_MAX_PLAYER;

        for (int i = 0; i < RBG_MAX_PLAYER; i++)
        {
            if (OBJECT_RANGE(this->Player[i].Index) == 0 || this->Player[i].Live == 0)
            {
                rank--;
                continue;
            }

            if (this->Player[n].Index == this->Player[i].Index)
            {
                rank--;
                continue;
            }

            if (this->Player[n].Point > this->Player[i].Point)
            {
                rank--;
                continue;
            }
            if (this->Player[n].Point == this->Player[i].Point && this->Player[n].Regen < this->Player[i].Regen)
            {
                rank--;
                continue;
            }
            if (this->Player[n].Point == this->Player[i].Point && n < i)
            {
                rank--;
                continue;
            }
        }

        this->Player[n].Rank = (rank + 1);

        if (this->Player[n].Rank >= 1 && this->Player[n].Rank <= 10)
        {
            int Stt = this->Player[n].Rank - 1;
            this->mIndexRank[Stt] = n;
        }
    }
}
RBG_Player* cRoyalBattleGround::GetUser(int aIndex) // OK
{
    if (OBJECT_RANGE(aIndex) == 0)
    {
        return 0;
    }
    for (int i = 0; i < RBG_MAX_PLAYER; i++)
    {
        if (this->Player[i].Index == aIndex)
        {
            return &this->Player[i];
        }
    }

    return 0;
}


bool cRoyalBattleGround::GetPosRandomFromBo(int* x, int* y)
{
    int px, py;
    while (true)
    {
        px = this->m_Zone[0] + (GetLargeRand() % ((this->m_Zone[2] + this->m_Zone[0]) - this->m_Zone[0]));
        py = this->m_Zone[1] + (GetLargeRand() % ((this->m_Zone[3] + this->m_Zone[1]) - this->m_Zone[1]));

        if (gMap[this->m_Map].CheckAttr(px, py, 4) == 0 && gMap[this->m_Map].CheckAttr(px, py, 8) == 0)
        {
            (*x) = px;
            (*y) = py;
            return 1;
            break;
        }
    }
    return 0;
}

bool cRoyalBattleGround::GetUserRespawnLocation(LPOBJ lpObj, int* gate, int* map, int* x, int* y, int* dir, int* level) // OK
{
    if (this->m_Enable == 0)
    {
        return 0;
    }


    if (this->m_State < RBG_STATE_BATTLE_STAGE_1 && this->m_State > RBG_STATE_BATTLE_STAGE_3)
    {
        return 0;
    }

    RBG_Player* lpUser = this->GetUser(lpObj->Index);

    if (lpUser == 0)
    {
        return 0;
    }

    if (this->m_RegenMax != -1 && lpUser->Regen >= this->m_RegenMax)
    {
        if (gGate.GetGate(this->m_GateOut, gate, map, x, y, dir, level) != 0)
        {
            this->DelMember(lpObj->Index);
            this->CountMember();
            this->SendPointToEventUsers();
            return 1;
        }

    }
    else
    {
        int xX, yY;
        if (this->GetPosRandomFromBo(&xX, &yY) == 0)
        {
            return 1;
        }
        (*gate) = 0;
        (*map) = lpObj->Map;
        (*x) = xX;
        (*y) = yY;
        (*dir) = 3;
        (*level) = 0;

        return 1;
    }


    return 0;
}

void cRoyalBattleGround::ThuongCoin(int State) // OK
{
}


void cRoyalBattleGround::EventTeleport(int aIndex, int map, int x, int y) // OK
{
    if (OBJECT_RANGE(aIndex) == 0)
    {
        return;
    }

    if (MAP_RANGE(map) == 0)
    {
        return;
    }

    LPOBJ lpObj = &gObj[aIndex];

    lpObj->State = OBJECT_DELCMD;


    lpObj->X = x;
    lpObj->Y = y;
    lpObj->TX = x;
    lpObj->TY = y;
    lpObj->Map = map;
    lpObj->PathCount = 0;
    lpObj->Teleport = 0;
    lpObj->ViewState = 0;
    lpObj->MiniMapState = 0;
    lpObj->MiniMapValue = -1;

    gObjClearViewport(lpObj);

    gMove.GCTeleportSend(aIndex, 1, lpObj->Map, (BYTE)lpObj->X, (BYTE)lpObj->Y, lpObj->Dir);

    gObjViewportListProtocolCreate(lpObj);

    gObjectManager.CharacterUpdateMapEffect(lpObj);

    lpObj->RegenMapNumber = lpObj->Map;
    lpObj->RegenMapX = (BYTE)lpObj->X;
    lpObj->RegenMapY = (BYTE)lpObj->Y;
    lpObj->RegenOk = 1;
}

 

  • RoyalBattleGround.h
#pragma once
#include "Protocol.h"
#define	RBG_MAX_PLAYER	100

enum RBG_STATE
{
    RBG_STATE_BLANK = 0,
    RBG_STATE_OPEN = 1,
    RBG_STATE_PREPARE = 2,
    RBG_STATE_BATTLE_STAGE_1 = 3,
    RBG_STATE_BATTLE_STAGE_2 = 4,
    RBG_STATE_BATTLE_STAGE_3 = 5,
    RBG_STATE_BATTLE_END = 6,
    RBG_STATE_REWARD = 7,
    RBG_STATE_CLEAR = 8,
};

struct ROYAL_BATTLE_GROUND_START_TIME
{
    int Year;
    int Month;
    int Day;
    int DayOfWeek;
    int Hour;
    int Minute;
    int Second;
};

struct ROYAL_BATTLE_GROUND_ITEM
{
    short Index;
    short Level;
    short Skill;
    short Luck;
    short Opt;
    short Exc;
    short Anc;
    short Socket[5];
    short SocketBonus;
};

struct ROYAL_BATTLE_GROUND_REWARD
{
    short Top;
    short Rate;
    int IDItemBag;
};

struct RBG_Player
{
    void Reset() // OK
    {
        Index = -1;
        Rank = 0;
        Regen = 0;
        Live = 0;
    }
    bool  Live;
    short Index;
    int	  Point;
    int	  Regen;
    int	  Rank;
};

struct RBG_Phase
{
    short	id;
    int		HP;
    float	HPrate;
    short	ItemCnt;
    int		ItemLoop;
    int		Coint;
    int		Type;
};
struct SKILLBLOCK_INFO_SINHTON
{
    int Index;
    int IDSkill;
};
struct PSWMSG_ROYAL_BATTLE_GROUND_PHASE_SEND {
    PSWMSG_HEAD header;
    int		Phase;
    int		Remain;
    int		Map;
    short	Zone[4];
};

struct PSWMSG_ROYAL_BATTLE_GROUND_POINT_SEND {
    PSWMSG_HEAD header;
    int		Alive;
    int		Kill;
    int		LiveCount;
    int		Total;
    int		Top;
};

struct PSWMSG_ROYAL_BATTLE_GROUND_ZONE_SEND {
    PSWMSG_HEAD header;
    float X;
    float Y;
};

struct PSWMSG_ROYAL_BATTLE_GROUND_KILL_SEND {
    PSWMSG_HEAD header;
    int		ComboKill;
    int		Rank;
    char	Player[11];
    char	Target[11];
};

struct PMSG_ROYAL_BATTLE_GROUND_REQUEST_RECV
{
    PBMSG_HEAD2_Origin h;
    BYTE type;
    int  value;
};


struct BACKUPOBJECTSTRUCT_HEADER
{
    BACKUPOBJECTSTRUCT_HEADER() // OK
    {
        this->CommonStruct = new OBJECTSTRUCT;

        for (int n = 0; n < MAX_OBJECT; n++){ this->ObjectStruct[n] = this->CommonStruct; }
    }

    OBJECTSTRUCT& operator[](int index) // OK
    {
        return (*this->ObjectStruct[index]);
    }

    OBJECTSTRUCT* CommonStruct;
    OBJECTSTRUCT* ObjectStruct[MAX_OBJECT];
};
struct BEVENTDATA_BXH
{
    char szName[11];
    int Kill;
};
class cRoyalBattleGround
{
public:
    cRoyalBattleGround();
    ~cRoyalBattleGround();
    void Init();
    void Read(char* configFile);
    void MainProc();
    void CheckSync();
    void SetState(int);
    void BlankProc();
    void OpenProc();
    void PrepareProc();
    void Stage1Proc();
    void Stage2Proc();
    void Stage3Proc();
    void StageEndProc();
    void RewardProc();
    void ClearProc();
    void ClearSection();
    void ChangeUserInfo(int aIndex);
    void ChangeUserInfo();
    void MoveUserPosition();
    bool CheckUserPostion(int aIndex);
    bool CheckUserList(int aIndex);
    void RemoveObject();
    int  GetPoint(int aIndex);
    void SendPointToUser(int aIndex);
    void SendPointToEventUsers();
    void SendPhaseToUser(int aIndex, bool Close = true);
    void SendPhaseToAllUsers();
    void SendPhaseToEventUsers();
    void SendKillToEventUsers(int aIndex, int bIndex);
    void KillProc(int aIndex, int bIndex);
    void AddPlayerPoint(int aIndex, int point);
    void SetPlayerPoint(int aIndex, int point);
    void RewardProc(int aIndex);
    void MemberRequestJoin(int aIndex);
    bool AddMember(int aIndex);
    bool DelMember(int aIndex);
    bool DelAllMembers();
    int  CountMember();
    bool GetEnabled();
    int  GetState();
    bool IsOpen();
    bool IsPlaying();
    int  GetOpenRemainTime();
    int  GetPlayRemainTime();
    int  GetRemainTime();
    void RecvRequest(BYTE* lpMsg, int aIndex);
    RBG_Phase* GetPhase(int id);
    void MakeZonePhase(int id);
    void SetZone(short X, short Y, short W, short H);
    void MakeDropItem();
    void DangerousZone();
    void ZoneHitUser(int aIndex);
    bool CheckSafeZone(int aIndex);
    bool BackupAddUser(int aIndex);
    OBJECTSTRUCT BackupGetUser(int aIndex);
    bool BackupDelUser(int aIndex);
    bool RollBackCharacterInfo(int aIndex);
    void StartBattle();
    bool CheckPrepareZone(int aIndex);
    void UserMoveOut(int aIndex);
    bool IsOnMapEvent(int aIndex);
    bool UserDieProc(LPOBJ lpObj, LPOBJ lpTarget);
    RBG_Player* GetUser(int aIndex);
    void CalcUserRank();
    bool GetPosRandomFromBo(int* x, int* y);
    bool GetUserRespawnLocation(LPOBJ lpObj, int* gate, int* map, int* x, int* y, int* dir, int* level);
    int  GetTop(int aIndex);
    void EventTeleport(int aIndex, int map, int x, int y);
private:
    bool m_Enable;
    int m_Timer_Open;
    int m_Timer_Prepare;
    int m_Timer_Stage1;
    int m_Timer_Stage2;
    int m_Timer_Stage3;
    int m_Timer_StageEnd;
    int m_State;
    int m_RemainTime;
    int m_TargetTime;
    int m_EndTime;
    int m_TickCount;
    int m_TotalPlayer;
    int m_TotalPlayerJoin;
    int m_Map;
    int m_GateIn;
    int m_GateOut;
    int m_RewardBonus;
    int m_Zone[4];
    int m_PhaseLastDrop;
    int m_PhaseDropCount;
    int m_PhaseDropDelay;
    int m_ZoneHP;
    int m_RegenMax;
    float m_ZoneHPrate;
    DWORD m_TotalReward;
    DWORD m_JoinCost;
    int  m_TypeCoin;
    DWORD m_MaxPlayer;

    RBG_Player		Player[RBG_MAX_PLAYER];
    std::vector<ROYAL_BATTLE_GROUND_START_TIME> m_RBGStartTime;
    std::vector<ROYAL_BATTLE_GROUND_ITEM> m_RBG_Items;
    std::vector<RBG_Phase> m_RBG_Phases;
    std::vector<OBJECTSTRUCT> m_BackupCharacter;
    std::vector<SKILLBLOCK_INFO_SINHTON> m_SinhTonSkillBlock;
    std::map<int, ROYAL_BATTLE_GROUND_REWARD> m_Reward;
    OBJECTSTRUCT_HEADER bObj;
    int mIndexRank[10];
    void SendBXH(int aIndex);
    void ThuongCoin(int State);
};

extern cRoyalBattleGround RoyalBattleGround;
  • Attack.cpp = Procure por bool CAttack::Attack \/
#include "RoyalBattleGround.h"

bool CAttack::Attack(LPOBJ lpObj, LPOBJ lpTarget, CSkill* lpSkill, bool send, BYTE flag, int Bdamage, int count, bool combo) // OK
{

if (RoyalBattleGround.CheckPrepareZone(lpTarget->Index)) //ADICIONE ISSO!
    {
        return 0;
    }
  • DSProtocol.cpp = Procure por DGCharacterInfoRecv
#include "RoyalBattleGround.h"

void DGCharacterInfoRecv(SDHP_CHARACTER_INFO_RECV* lpMsg) // OK
{

if (!RoyalBattleGround.IsPlaying())
    {
        RoyalBattleGround.GetRemainTime();
        RoyalBattleGround.SendPhaseToUser(lpObj->Index);
    }
  • Protocol.cpp
#include "RoyalBattleGround.h"

void ProtocolCore(BYTE head, BYTE* lpMsg, int size, int aIndex, int encrypt, int serial) // OK
{

case 0x33:
                RoyalBattleGround.RecvRequest(lpMsg, aIndex);
                break;
  • ObjectManager.cpp
#include "RoyalBattleGround.h"

void CObjectManager::CharacterGameCloseSet(int aIndex,int type) // OK
{

if (RoyalBattleGround.CheckUserList(aIndex))
    {
        RoyalBattleGround.UserMoveOut(aIndex);
    }

//

else if (RoyalBattleGround.CheckUserList(lpObj->Index))
    {
        result = RoyalBattleGround.GetUserRespawnLocation(lpObj, &gate, &map, &x, &y, &dir, &level);
    }
  • ServerInfo.cpp
#include "RoyalBattleGround.h"

RoyalBattleGround.Init();
  • ViewPort.cpp
#include "RoyalBattleGround.h"

if (RoyalBattleGround.CheckUserList(lpObj->Index))
    {
        return 1;
    }
  • User.cpp

 

#include "RoyalBattleGround.h"

RoyalBattleGround.MainProc();

else if (RoyalBattleGround.UserDieProc(lpObj, lpTarget))
    {
        return;
    }

//

RoyalBattleGround.KillProc(lpTarget->Index, lpObj->Index);

if (RoyalBattleGround.CheckUserList(lpObj->Index))
    {
        return;
    }

//

if (!RoyalBattleGround.IsOnMapEvent(aIndex) && RoyalBattleGround.CheckUserList(aIndex))
    {
        RoyalBattleGround.UserMoveOut(aIndex);
    }


RoyalBattleGround.CheckUserPostion(lpObj->Index);

FALTA O MAIN.DLL E MAIS ALGUMAS COISAS NO GS!

FALTA: ServerDisplay.cpp e GameServer.Cpp <= [S.D.cpp Mostrar Horario no GS] & [Start Event Battle Royale no GS]

DEPOIS EU ADICIONO AQUI O CODIGO!

QUE VAI NO MAIN.DLL

NAO É POR NPCTALK!!! É POR JANELA DE TELEPORTE NO F9

AGUARDE…

 

Descargar

Oros Archivos

Conclusión

El código fuente de RoyalBattleGround está diseñado para proporcionar un evento dinámico y emocionante dentro de MuOnline. La estructura modular permite que el evento se gestione eficientemente, desde la inicialización hasta la entrega de recompensas. Este sistema no solo mejora la jugabilidad, sino que también fomenta la competencia entre los jugadores.

 

::CREDITOS::
[DEV-TEAM EMULADOR]

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *