PDA

View Full Version : Source blood 8 and fix class 3 envet .



bachcotsau
22-05-08, 12:25 PM
Hiện có code để fix nhưng lại không có bộ source SS3 EP2 và hiểu biết VB nên share tạm Source fix event blood lên đây .



// BloodCastle.h
// ------------------------------
// Decompiled by BachCotSau
// Date : 2008-22-5
// ------------------------------
#ifndef BLOODCASTLE_H
#define BLOODCASTLE_H

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "..\common\zzzitem.h"
#include "MapItem.h"
#include "user.h"

#define MAX_BLOOD_CASTLE_LEVEL 8
#define MAX_BLOOD_CASTLE_SUB_BRIDGE 10

#define BC_STATE_NONE 0
#define BC_STATE_CLOSED 1
#define BC_STATE_PLAYING 2
#define BC_STATE_PLAYEND 3


#define BC_MAP_RANGE(value) ( (( (value) )<BLOOD_CASTLE_1)?FALSE:(( (value) )>BLOOD_CASTLE_7)?FALSE:TRUE )
#define BC_WEAPON_LEVEL_RANGE(x) ( (((x))<0)?FALSE:(((x))>2)?FALSE:TRUE )
#define BC_TIME_RANGE(x) ( (((x))<0)?FALSE:(((x))>1)?FALSE:TRUE )
#define BC_STATUE_RANGE(x) ( (((x))<0)?FALSE:(((x))>2)?FALSE:TRUE )
#define BC_BRIDGE_RANGE(x) ( ((x)<0)?FALSE:((x)>MAX_BLOOD_CASTLE_LEVEL-1)?FALSE:TRUE )
#define BC_SUB_BRIDGE_RANGE(x) ( ((x)<0)?FALSE:((x)>MAX_BLOOD_CASTLE_SUB_BRIDGE-1)?FALSE:TRUE )


typedef struct
{
int iIndex; // unk
int iEXP; // unk
int unk8;
int unkC;
BYTE unk10;
bool unk11;

} ST_BLOOD_CASTLE_SUB_INFO;





struct GCS_NOTICE_STATE //Send[C1:9B]
{
PHEADB PHeader;
BYTE btPlayState;
WORD wRemainTime;
WORD wMonsterCount;
WORD wMonsterKillCount;
WORD wUltimateWeaponOwnerIndex;
BYTE btUltimateWeaponLevel;

};


// sizeof ( _BLOODCASTLE_DATA ) == 0x1FC
typedef struct _BLOODCASTLE_DATA
{
CRITICAL_SECTION rtlCritical; // unk - p until 0x
ST_BLOOD_CASTLE_SUB_INFO stBloodCastleSubInfo[MAX_BLOOD_CASTLE_SUB_BRIDGE]; // unk until 0x
int unkE0[20]; // unkE0 - p - until 0x
int nStatueSaintPosNum; // unk - p
int nCastleDoorPosNum; // unk - p
int unk138;
int iBCMapNumber; // unk - p
int unk140;
int unk144;
int unk148;
int iBCState; // unk - p
int iRemainTime; // unk - p
int iTickCount; // unk - p
int iMinutesLeftToEnter; // unk - p
bool bMonsterKillSuccess; // unk - p
bool bBossMonsterKillSuccess; // unk - p
bool unk15E;
bool bCanEnter; // unk - p
bool bCanParty; // unk - p
bool bStartPlaying; // unk - p
bool bIsBloodQuestCompleted; // unk - p
bool bIsLoadedStateClosed; // unk - p
bool bIsLoadedStatePlaying; // unk - p
bool bIsEndOfStatePlaying; // unk- p
bool bIsLoadedStatePlayEnd; // unk - p
float fGateLife; // unk - p
float fStatueLife; // unk - p
int iNormalMonsterCount; // unk - p
int iNormalMonsterKillCount; // unk - p
int unk178;
int iBridgeDestroyTick; // unk - p
int iBossMonsterCount; // unk - p
int iBossMonsterKillCount; // unk-p
int unk188;
int unk18C;
int iUltimateWeaponOwnerIndex; // unk - p
BYTE btUltimateWeaponLevel; // unk-p
int unk198;
int unk19C;
int unk1A0;
char szGateDestroyAccountID[11]; // unk - p
char szGateDestroyCharName[11]; // unk - p
int unk1BC;
int unk1C0;
char szStatueDestroyCharName[11]; // unk - p
char szStatueDestroyAccountID[11]; // unk - p
int unk1DC;
int unk1E0;
char unk1E4[11];
char unk1EF[11];

} BLOODCASTLE_DATA, * LPBLOODCASTLE_DATA;

class CBloodCastle
{

public:

CBloodCastle();
virtual ~CBloodCastle();

void Init(BOOL bEVENT_ENABLE);
void Load(char* filename);
void LoadItemDropRate();
void CheckSync(int iBridgeIndex);
void ClearBridgeData(int iBridgeIndex);
void SetState(int iBridgeIndex, int iBC_STATE);
void Run();

// Procedures of BloodCastle
void ProcState_None(int iBridgeIndex);
void ProcState_Closed(int iBridgeIndex);
void ProcState_Playing(int iBridgeIndex);
void ProcState_PlayEnd(int iBridgeIndex);

// States of BloodCastle
void SetState_None(int iBridgeIndex);
void SetState_Closed(int iBridgeIndex);
void SetState_Playing(int iBridgeIndex);
void SetState_PlayEnd(int iBridgeIndex);

int GetCurrentState(int iBridgeIndex);
int GetCurrentRemainSec(int iBridgeIndex);
int CheckEnterLevel(int iIndex, int iLevel);
bool BloodCastleChaosMix(int iIndex, int iLEVEL);

// Check of BLood Castle
int CheckChaosMixItem(int iIndex);
int CheckEnterItem(int iIndex);
int CheckQuestItem(int iIndex);
bool CheckWalk(int iIndex, int iMoveX, int iMoveY);
bool CheckCanEnter(int iBridgeIndex);
bool CheckCanParty(int iBridgeIndex);
bool CheckQuestItemSerial(int iBridgeIndex, CMapItem * lpItem);
bool CheckPlayStart(int iBridgeIndex);

int GetRemainTime(int iBridgeIndex);

// Monster Related
void ClearMonster(int iBridgeIndex, bool bClearCastleDoor);
void SetMonster(int iBridgeIndex);
void SetBossMonster(int iBridgeIndex);
void SetSaintStatue(int iBridgeIndex);

// Blood Castle User Relarted
int LeaveUserBridge(int iBridgeIndex, int iBridgeSubIndex, int iUserIndex);
int EnterUserBridge(int iBridgeIndex, int iUserIndex);
int LevelUp(int iIndex, int iAddExp);
void CheckUsersOnConnect(int iBridgeIndex);
bool AddExperience(int iIndex, int iEXP);

// Blood Castle Internals
void BlockCastleEntrance(int iBridgeIndex);
void ReleaseCastleEntrance(int iBridgeIndex);
void BlockCastleBridge(int iBridgeIndex);
void ReleaseCastleBridge(int iBridgeIndex);
void BlockCastleDoor(int iBridgeIndex);
void ReleaseCastleDoor(int iBridgeIndex);
void BlockSector(int iMAP_NUM, int iSTART_X, int iSTART_Y, int iEND_X, int iEND_Y);
void ReleaseSector(int iMAP_NUM, int iSTART_X, int iSTART_Y, int iEND_X, int iEND_Y);

// Blood Castle packet relates
void SendCastleEntranceBlockInfo(int iBridgeIndex, bool bLive);
void SendCastleBridgeBlockInfo(int iBridgeIndex, bool bLive);
void SendCastleDoorBlockInfo(int iBridgeIndex, bool bLive);
void SendNoticeMessage(int iBridgeIndex, char * lpszMSG);
void SendNoticeScore(int iBridgeIndex);
void SendNoticeState(int iBridgeIndex, int iPlayState);

// Blood Castle User Internal
bool CheckUserBridgeMember(int iBridgeIndex, int iIndex);
int GetAliveUserTotalEXP(int iBridgeIndex);
void SearchUserDeleteQuestItem(int iIndex);
void SearchUserDropQuestItem(int iIndex);
void SetUserState(int iIndex, int iState);

// Blood Castle Rewards
void GiveReward_Win(int iIndex, int iBridgeIndex);
void GiveReward_Fail(int iBridgeIndex);
int CalcSendRewardEXP(int iIndex, int iEXP);
int CalcSendRewardZEN(int iIndex, int iZEN);
void DropChaosGem(int iIndex);
void SendRewardScore(int iIndex, int iSCORE);

// Blood Castle Messages Packet
void SendBridgeAnyMsg(BYTE * lpMsg, int iSize, int iBridgeIndex);
void SendAllUserAnyMsg(BYTE * lpMsg, int iSize);

// Blood Castle Monster Count Functions
void SetMonsterKillCount(int iBridgeIndex);
bool CheckMonsterKillCount(int iBridgeIndex);
bool CheckMonsterKillSuccess(int iBridgeIndex);
bool CheckBossKillCount(int iBridgeIndex);
bool CheckBossKillSuccess(int iBridgeIndex);

// Blood Castle Misc
bool CheckEveryUserDie(int iBridgeIndex);
bool CheckAngelKingExist(int iBridgeIndex);
int GetWhoGotUltimateWeapon(int iBridgeIndex);
int GetCurrentLiveUserCount(int iBridgeIndex);
bool DropItemDirectly(int iBridgeIndex, int iIndex, int iItemType, int iItemPos);
bool CheckUserHaveUltimateWeapon(int iIndex);

public:

BLOODCASTLE_DATA m_sttBloodCastleData[MAX_BLOOD_CASTLE_LEVEL]; // unk
BYTE m_btEventEnabled; // unk
int m_iWarningTime; // unk
int m_iEventTimeDuration; // unk
int m_iPreparationTime; // unk
int m_iNormalDropRateBase; // unk
int m_iExcellentDropRateBase; // unk
int m_iRegenTime; // unk

};


typedef struct EVENT_LEVEL_LIMITATION
{
int NormalCharacterMinLevel; // Dark Knight, Dark Wizard, Elf,SumMoner
int NormalCharacterMaxLevel; // Dark Knight, Dark Wizard, Elf,SumMoner
int SpecialCharacterMinLevel; // Magic Gladiator, Dark Lord
int SpecialCharacterMaxLevel; // Magic Gladitor, Dark Lord

}EVENT_LEVEL_LIMITATION, * LPEVENT_LEVEL_LIMITATION;


static EVENT_LEVEL_LIMITATION g_sttBLOODCASTLE_LEVEL[MAX_BLOOD_CASTLE_LEVEL] =
{
// Blood Castle 1
15, 80, // Cấp độ 15-80 DK, DW, Elf, SumMoner
10, 60, // Cấp độ 10-60 MG, DL
// Blood Castle 2
81, 130, // DK, DW, Elf, SumMoner
61, 110, // MG, DL

// Blood Castle 3
131, 180, // DK, DW, Elf, SumMoner
111, 160, // MG, DL

// Blood Castle 4
181, 230, // DK, DW, Elf, SumMoner
161, 210, // MG, DL

// Blood Castle 5
231, 280, // DK, DW, Elf, SumMoner
211, 260, // MG, DL

// Blood Castle 6
281, 330, // DK, DW, Elf, SumMoner
261, 310, // MG, DL

// Blood Castle 7
331, 350 MAX_CHAR_LEVEL, // DK, DW, Elf, SumMoner
311, 365 MAX_CHAR_LEVEL // MG, DL

// Blood Castle 8
350 MAX_CHAR_LEVEL, // DK, DW, Elf, SumMoner max 350 -> 1000 lvl
365 MAX_CHAR_LEVEL // MG, DL


};

/*
g_sttBLOO>0F 00 00 00 50 00 00 00 ....P...
006294A0 0A 00 00 00 3C 00 00 00 ....<...
006294A8 51 00 00 00 82 00 00 00 Q...‚...
006294B0 3D 00 00 00 6E 00 00 00 =...n...
006294B8 83 00 00 00 B4 00 00 00 ƒ...´...
006294C0 6F 00 00 00 A0 00 00 00 o...*...
006294C8 B5 00 00 00 E6 00 00 00 µ...æ...
006294D0 A1 00 00 00 D2 00 00 00 ¡...Ò...
006294D8 E7 00 00 00 18 01 00 00 ç.......
006294E0 D3 00 00 00 04 01 00 00 Ó.......
006294E8 19 01 00 00 4A 01 00 00 ....J...
006294F0 05 01 00 00 36 01 00 00 ....6...
006294F8 4B 01 00 00 90 01 00 00 K......
00629500 37 01 00 00 90 01 00 00 7......

*/

extern CBloodCastle g_BloodCastle;

#endif

bachcotsau
22-05-08, 12:32 PM
// BloodCastle.cpp

// GS-N 0.99.60T 0x005004D0 - Completed

/* Disorder with same effect in CBloodCastle::LevelUp
GCLevelUpMsgSend(gObj[iIndex].Index, gObj[iIndex].Level, gObj[iIndex].iFreeStatPoints,
(int)((float)gObj[iIndex].unk104 + gObj[iIndex].fMaxLife), (int)((float)gObj[iIndex].unk108 + gObj[iIndex].fMaxMana),
gObj[iIndex].iMaxBP + gObj[iIndex].unkE8, AddPoint, MaxAddPoint);
Problem with global variables, there is a Zero ( 4 BYTES ) space
*/
#include "stdafx.h"
#include "MonsterHerd.h"
#include "BloodCastle.h"
#include "ChaosCastle.h"
#include "GameMain.h"
#include "GameServer.h"
#include "GameServerAuth.h"
#include "logproc.h"
#include "readscript.h"
#include "DSProtocol.h"
#include "Protocol.h"
#include "TNotice.h"
#include "winutil.h"
#include "ObjUseSkill.h"
#include "ChaosBox.h"
#include "CastleSiegeSync.h"
#include "DSProtocol.h"

CBloodCastle g_BloodCastle;


struct BLOOD_ZONE
{
BYTE btStartX;
BYTE btStartY;
BYTE btEndX;
BYTE btEndY;

} g_btCastleEntranceMapXY[MAX_BLOOD_CASTLE_LEVEL] = {

13, 15, 15, 23, // Blood Castle 1
13, 15, 15, 23, // Blood Castle 2
13, 15, 15, 23, // Blood Castle 3
13, 15, 15, 23, // Blood Castle 4
13, 15, 15, 23, // Blood Castle 5
13, 15, 15, 23, // Blood Castle 6
13, 15, 15, 23 // Blood Castle 7
13, 15, 15, 23 // Blood Castle 8

}, g_btCastleBridgeMapXY[MAX_BLOOD_CASTLE_LEVEL] = {

13, 70, 15, 75, // Bridge of Blood Castle 1
13, 70, 15, 75, // Bridge of Blood Castle 2
13, 70, 15, 75, // Bridge of Blood Castle 3
13, 70, 15, 75, // Bridge of Blood Castle 4
13, 70, 15, 75, // Bridge of Blood Castle 5
13, 70, 15, 75, // Bridge of Blood Castle 6
13, 70, 15, 75 // Bridge of Blood Castle 7
13, 70, 15, 75 // Bridge of Blood Castle 8

}, g_btCastleDoorMapXY[MAX_BLOOD_CASTLE_LEVEL][3]= {

// Blood Castle 1
13, 76, 15, 79, // Door Itself
11, 80, 25, 89, // Zone Beginh Door
8, 80, 10, 83, // Altar

// Blood Castle 2
13, 76, 15, 79, // Door Itself
11, 80, 25, 89, // Zone Beginh Door
8, 80, 10, 83, // Altar

// Blood Castle 3
13, 76, 15, 79, // Door Itself
11, 80, 25, 89, // Zone Beginh Door
8, 80, 10, 83, // Altar

// Blood Castle 4
13, 76, 15, 79, // Door Itself
11, 80, 25, 89, // Zone Beginh Door
8, 80, 10, 83, // Altar

// Blood Castle 5
13, 76, 15, 79, // Door Itself
11, 80, 25, 89, // Zone Beginh Door
8, 80, 10, 83, // Altar

// Blood Castle 6
13, 76, 15, 79, // Door Itself
11, 80, 25, 89, // Zone Beginh Door
8, 80, 10, 83, // Altar

// Blood Castle 7
13, 76, 15, 79, // Door Itself
11, 80, 25, 89, // Zone Beginh Door
8, 80, 10, 83 // Altar

// Blood Castle 8
13, 76, 15, 79, // Door Itself
11, 80, 25, 89, // Zone Beginh Door
8, 80, 10, 83 // Altar
};

struct ST_REWARD_ZEN
{
int NormalCharacter;
int SpecialCharacter;

} g_iQuestWinExpendZEN[MAX_BLOOD_CASTLE_LEVEL] = {

20000, 10000,
50000, 25000,
100000, 50000,
150000, 80000,
200000, 100000,
250000, 120000,
300000, 140000,
350000, 160000

};

//#pragma pack()

int g_iBC_ChoasMixSuccessRate[MAX_BLOOD_CASTLE_LEVEL] = { 80, 80, 80, 80, 80, 80, 80 };
int g_iBC_ChoasMixMoney[MAX_BLOOD_CASTLE_LEVEL] = {50000 , 80000 , 150000, 250000, 400000, 600000, 850000, 950000};

struct ST_BC_EVENT_SCORE
{
int unk0;
int unk4;
int unk8;
int unkC;
int unk10;

} g_iBC_EventScore[MAX_BLOOD_CASTLE_LEVEL] =
{
600, 300, 1000, 800, 400,
600, 300, 1000, 800, 400,
600, 300, 1005, 800, 400,
600, 300, 1005, 800, 400,
600, 300, 1005, 800, 400,
600, 300, 1005, 800, 400,
600, 300, 1005, 800, 400,
600, 300, 1005, 800, 400
};

int g_iBC_EventScore_Fail[MAX_BLOOD_CASTLE_LEVEL] = { -300,-300,-300,-300,-300,-300,-300,-300 };

struct ST_BC_ADD_EXP
{
int unk0;
int unk4;
int unk8;
int unkC;

} g_iBC_Add_Exp[MAX_BLOOD_CASTLE_LEVEL] =
{
20000, 20000, 5000, 160,
50000, 50000, 10000, 180,
80000, 80000, 15000, 200,
90000, 90000, 20000, 220,
100000, 100000, 25000, 240,
110000, 110000, 30000, 260,
120000, 120000, 35000, 280,
140000, 140000, 40000, 300
};



/*::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::*/


CBloodCastle::CBloodCastle()
{
this->m_btEventEnabled = FALSE;
this->m_iWarningTime = 10;
this->m_iNormalDropRateBase = 100;
this->m_iExcellentDropRateBase = 1200;
this->m_iRegenTime = 0;

for ( int i =0; i<MAX_BLOOD_CASTLE_LEVEL ; i++ )
{
this->m_sttBloodCastleData[i].iBCState = 0;
this->m_sttBloodCastleData[i].iBCMapNumber = i + BLOOD_CASTLE_1;
this->m_sttBloodCastleData[i].unk140 = i;
this->m_sttBloodCastleData[i].iRemainTime = -1;
this->m_sttBloodCastleData[i].iTickCount = -1;
this->m_sttBloodCastleData[i].nStatueSaintPosNum = -1;
this->m_sttBloodCastleData[i].nCastleDoorPosNum = -1;
this->m_sttBloodCastleData[i].unk198 = -1;
InitializeCriticalSection(&this->m_sttBloodCastleData[i].rtlCritical);
this->ClearBridgeData(i);
}
}




CBloodCastle::~CBloodCastle()
{
for ( int i =0; i<MAX_BLOOD_CASTLE_LEVEL ; i++ )
{
DeleteCriticalSection(&this->m_sttBloodCastleData[i].rtlCritical);
}
}




void CBloodCastle::Init(BOOL bEVENT_ENABLE)
{
this->m_btEventEnabled = bEVENT_ENABLE;

for ( int i=0; i<MAX_BLOOD_CASTLE_LEVEL ; i++ )
{
for ( int n=0;n<20;n++)
{
this->m_sttBloodCastleData[i].unk198 = -1;
this->m_sttBloodCastleData[i].unkE0[n] = -1;
}
}

for ( int n =0; n<gMSetBase.m_iMonsterCount;n++)
{
if ( BC_MAP_RANGE(gMSetBase.m_sttMonsterSetBase[n].btMapNumber ) != FALSE )
{
BYTE btMonsterType = gMSetBase.m_sttMonsterSetBase[n].wMonsterIndex;
BYTE btMapNumber = gMSetBase.m_sttMonsterSetBase[n].btMapNumber;
BYTE btBloodCastleIndex = btMapNumber - BLOOD_CASTLE_1;

if ( btMonsterType == 232 )
{
this->m_sttBloodCastleData[gMSetBase.m_sttMonsterSetBase[n].btMapNumber - BLOOD_CASTLE_1].unk198 = n;
continue;
}

if ( BC_STATUE_RANGE(btMonsterType - 132) != FALSE )
{
this->m_sttBloodCastleData[btBloodCastleIndex].nStatueSaintPosNum = n;
continue;
}

if ( btMonsterType == 131 )
{
this->m_sttBloodCastleData[btBloodCastleIndex].nCastleDoorPosNum = n;
continue;
}

if ( btMonsterType == 89 || btMonsterType == 95 || btMonsterType == 112 || btMonsterType == 118 || btMonsterType == 124 || btMonsterType == 130 || btMonsterType == 143 )
{
for ( int l=0;l<20;l++)
{
if ( this->m_sttBloodCastleData[btBloodCastleIndex].unkE0[l] == -1 )
{
this->m_sttBloodCastleData[btBloodCastleIndex].unkE0[l] = n;
break;
}
}
}
}

}

for ( i=0;i<MAX_BLOOD_CASTLE_LEVEL;i++)
{
this->SetState(i, BC_STATE_CLOSED);
}
}


void CBloodCastle::Load(char* filename)
{
int Token;
int type;
int BridgeCount;
int iBridgeNum;
SMDFile=fopen(filename, "r");

if (SMDFile == 0)
{
MsgBox("[Blood Castle] Info file Load Fail [%s]", filename);
return;
}

type=-1;
BridgeCount=-1;

while ( true )
{
Token=GetToken();

if ( Token == 2 )
{
break;
}

type=TokenNumber;

while ( true )
{
if ( type == 0 )
{
Token=GetToken();

if (strcmp("end", &TokenString[0]) == 0)
{
break;
}

this->m_iWarningTime = TokenNumber;

Token = GetToken();
this->m_iEventTimeDuration =TokenNumber;

Token = GetToken();
this->m_iPreparationTime = TokenNumber;
}
else if ( type == 1 )
{
Token = GetToken();

if (strcmp("end", &TokenString[0]) == 0)
{
break;
}

this->m_iNormalDropRateBase = TokenNumber;

Token = GetToken();
this->m_iExcellentDropRateBase = TokenNumber;

Token = GetToken();
this->m_iRegenTime = TokenNumber;
}
else if ( type == 2 )
{
Token = GetToken();

if (strcmp("end", &TokenString[0]) == 0)
{
break;
}

iBridgeNum = TokenNumber;

if ( BC_BRIDGE_RANGE(iBridgeNum) != FALSE )
{
Token = GetToken();
this->m_sttBloodCastleData[iBridgeNum].fGateLife = TokenNumber;

Token = GetToken();
this->m_sttBloodCastleData[iBridgeNum].fStatueLife = TokenNumber;
}
else
{
Token = GetToken();
Token = GetToken();
}
}
}
}

fclose(SMDFile);

LogAdd("%s file load!", filename);
}




void CBloodCastle::LoadItemDropRate()
{
g_bBloodCastle=GetPrivateProfileInt(COMMONSERVER_M AINSECTION, "BloodCastleEvent", 0, gDirPath.GetNewPath(COMMONSERVER_FILE));
g_iAngelKingsPaperDropRate=GetPrivateProfileInt(CO MMONSERVER_MAINSECTION, "AngelKingsPaperDropRate", 0, gDirPath.GetNewPath(COMMONSERVER_FILE));
g_iBloodBoneDropRate=GetPrivateProfileInt(COMMONSE RVER_MAINSECTION, "BloodBoneDropRate", 0, gDirPath.GetNewPath(COMMONSERVER_FILE));
g_iStoneDropRate=GetPrivateProfileInt(COMMONSERVER _MAINSECTION, "StoneDropRate", 0, gDirPath.GetNewPath(COMMONSERVER_FILE));
g_bStoneItemDrop=GetPrivateProfileInt(COMMONSERVER _MAINSECTION, "StoneItemDrop", 0, gDirPath.GetNewPath(COMMONSERVER_FILE));
}




void CBloodCastle::CheckSync(int iBridgeIndex)
{
if ( BC_BRIDGE_RANGE(iBridgeIndex) == FALSE )
{
return;
}

tm * today;
time_t ltime;

time(&ltime);
today = localtime(&ltime);

if ( BC_TIME_RANGE(g_iBloodCastle_StartHour-1) == FALSE )
{
g_iBloodCastle_StartHour = 1;
}

switch ( g_iBloodCastle_StartHour )
{
case 2:

if ( (today->tm_hour%2) == 0 )
{
if ( ( today->tm_min*60 + today->tm_sec ) >= 1800 )
{
this->m_sttBloodCastleData[iBridgeIndex].iRemainTime = (9000 - (today->tm_min*60 + today->tm_sec)) * 1000;
}
else
{
this->m_sttBloodCastleData[iBridgeIndex].iRemainTime = (1800 - (today->tm_min*60 + today->tm_sec)) * 1000;
}
}
else
{
this->m_sttBloodCastleData[iBridgeIndex].iRemainTime = (5400 - (today->tm_min*60 + today->tm_sec)) * 1000;
}

if ( this->m_sttBloodCastleData[iBridgeIndex].iRemainTime < 0 )
{
this->m_sttBloodCastleData[iBridgeIndex].iRemainTime += 3600000;
}

this->m_sttBloodCastleData[iBridgeIndex].iTickCount = GetTickCount();
break;

default:

if ( ( today->tm_min*60 + today->tm_sec ) >= 1800 )
{
this->m_sttBloodCastleData[iBridgeIndex].iRemainTime = (9000 - (today->tm_min*60 + today->tm_sec)) * 1000;
}
else
{
this->m_sttBloodCastleData[iBridgeIndex].iRemainTime = (1800 - (today->tm_min*60 + today->tm_sec)) * 1000;
}

if ( this->m_sttBloodCastleData[iBridgeIndex].iRemainTime < 0 )
{
this->m_sttBloodCastleData[iBridgeIndex].iRemainTime += 3600000;
}
this->m_sttBloodCastleData[iBridgeIndex].iTickCount = GetTickCount();

break;

}

LogAddTD("[Blood Castle] (%d) Sync Open Time. [%d] min remain",
iBridgeIndex+1, this->m_sttBloodCastleData[iBridgeIndex].iRemainTime / 60000);


}





void CBloodCastle::ClearBridgeData(int iBridgeIndex)
{
if ( BC_BRIDGE_RANGE(iBridgeIndex) == FALSE )
{
return;
}

this->m_sttBloodCastleData[iBridgeIndex].unk138 = 0;
this->m_sttBloodCastleData[iBridgeIndex].iNormalMonsterCount = 0;
this->m_sttBloodCastleData[iBridgeIndex].iNormalMonsterKillCount = 0;
this->m_sttBloodCastleData[iBridgeIndex].unk178 = 0;
this->m_sttBloodCastleData[iBridgeIndex].iBossMonsterCount = 0;
this->m_sttBloodCastleData[iBridgeIndex].iBossMonsterKillCount = 0;
this->m_sttBloodCastleData[iBridgeIndex].unk188 = 0;
this->m_sttBloodCastleData[iBridgeIndex].btUltimateWeaponLevel = 0;
this->m_sttBloodCastleData[iBridgeIndex].iBridgeDestroyTick = -1;
this->m_sttBloodCastleData[iBridgeIndex].unk18C = -1;
this->m_sttBloodCastleData[iBridgeIndex].iUltimateWeaponOwnerIndex = -1;
this->m_sttBloodCastleData[iBridgeIndex].unk144 = -1;
this->m_sttBloodCastleData[iBridgeIndex].iMinutesLeftToEnter = -1;
this->m_sttBloodCastleData[iBridgeIndex].unk148 = 1;
this->m_sttBloodCastleData[iBridgeIndex].bIsBloodQuestCompleted = false;
this->m_sttBloodCastleData[iBridgeIndex].bIsLoadedStateClosed = false;
this->m_sttBloodCastleData[iBridgeIndex].bIsLoadedStatePlaying = false;
this->m_sttBloodCastleData[iBridgeIndex].bIsEndOfStatePlaying = false;
this->m_sttBloodCastleData[iBridgeIndex].bIsLoadedStatePlayEnd = false;
this->m_sttBloodCastleData[iBridgeIndex].bCanEnter = false;
this->m_sttBloodCastleData[iBridgeIndex].bCanParty = false;
this->m_sttBloodCastleData[iBridgeIndex].bStartPlaying = false;
this->m_sttBloodCastleData[iBridgeIndex].bMonsterKillSuccess = false;
this->m_sttBloodCastleData[iBridgeIndex].bBossMonsterKillSuccess = false;
this->m_sttBloodCastleData[iBridgeIndex].unk15E = false;
this->m_sttBloodCastleData[iBridgeIndex].unk1A0 = -10;
this->m_sttBloodCastleData[iBridgeIndex].unk19C = -10;
this->m_sttBloodCastleData[iBridgeIndex].unk1C0 = -10;
this->m_sttBloodCastleData[iBridgeIndex].unk1BC = -10;
this->m_sttBloodCastleData[iBridgeIndex].unk1E0 = -10;
this->m_sttBloodCastleData[iBridgeIndex].unk1DC = -10;

memset(this->m_sttBloodCastleData[iBridgeIndex].szGateDestroyCharName , 0, sizeof(this->m_sttBloodCastleData[iBridgeIndex].szGateDestroyCharName));
memset(this->m_sttBloodCastleData[iBridgeIndex].szStatueDestroyCharName, 0, sizeof(this->m_sttBloodCastleData[iBridgeIndex].szStatueDestroyCharName));
memset(this->m_sttBloodCastleData[iBridgeIndex].unk1E4, 0, sizeof(this->m_sttBloodCastleData[iBridgeIndex].unk1E4));
memset(this->m_sttBloodCastleData[iBridgeIndex].szGateDestroyAccountID, 0, sizeof(this->m_sttBloodCastleData[iBridgeIndex].szGateDestroyAccountID));
memset(this->m_sttBloodCastleData[iBridgeIndex].szStatueDestroyAccountID, 0, sizeof(this->m_sttBloodCastleData[iBridgeIndex].szStatueDestroyAccountID));
memset(this->m_sttBloodCastleData[iBridgeIndex].unk1EF, 0, sizeof(this->m_sttBloodCastleData[iBridgeIndex].unk1EF));


for (int i=0;i<MAX_BLOOD_CASTLE_SUB_BRIDGE;i++)
{
if ( this->m_sttBloodCastleData[iBridgeIndex].stBloodCastleSubInfo[i].iIndex != -1 )
{
gObj[this->m_sttBloodCastleData[iBridgeIndex].stBloodCastleSubInfo[i].iIndex].iBC_Experience = 0;
gObj[this->m_sttBloodCastleData[iBridgeIndex].stBloodCastleSubInfo[i].iIndex].cBloodCastleBridgeIndex = -1;
gObj[this->m_sttBloodCastleData[iBridgeIndex].stBloodCastleSubInfo[i].iIndex].cBloodCastleSubBridgeIndex = -1;
}

this->m_sttBloodCastleData[iBridgeIndex].stBloodCastleSubInfo[i].iEXP = 0;
this->m_sttBloodCastleData[iBridgeIndex].stBloodCastleSubInfo[i].unk8 = 0;
this->m_sttBloodCastleData[iBridgeIndex].stBloodCastleSubInfo[i].iIndex = -1;
this->m_sttBloodCastleData[iBridgeIndex].stBloodCastleSubInfo[i].unkC = 0;
this->m_sttBloodCastleData[iBridgeIndex].stBloodCastleSubInfo[i].unk10 = 0;
this->m_sttBloodCastleData[iBridgeIndex].stBloodCastleSubInfo[i].unk11 = 0;
}
}





void CBloodCastle::SetState(int iBridgeIndex, int iBC_STATE)
{
if ( BC_BRIDGE_RANGE(iBridgeIndex) == FALSE )
{
return;
}

if ( iBC_STATE < BC_STATE_NONE || iBC_STATE > BC_STATE_PLAYEND )
{
return;
}

this->m_sttBloodCastleData[iBridgeIndex].iBCState = iBC_STATE;

switch ( this->m_sttBloodCastleData[iBridgeIndex].iBCState )
{
case BC_STATE_NONE:
this->SetState_None(iBridgeIndex);
break;

case BC_STATE_CLOSED:
this->SetState_Closed(iBridgeIndex);
break;

case BC_STATE_PLAYING:
this->SetState_Playing(iBridgeIndex);
break;

case BC_STATE_PLAYEND:
this->SetState_PlayEnd(iBridgeIndex);
break;
}
}





void CBloodCastle::Run()
{
if ( this->m_btEventEnabled != FALSE )
{
for (int iBridgeIndex=0;iBridgeIndex<MAX_BLOOD_CASTLE_LEVEL;iBridgeIndex++)
{
switch ( this->m_sttBloodCastleData[iBridgeIndex].iBCState )
{
case BC_STATE_NONE:
this->ProcState_None(iBridgeIndex);
break;

case BC_STATE_CLOSED:
this->ProcState_Closed(iBridgeIndex);
break;

case BC_STATE_PLAYING:
this->ProcState_Playing(iBridgeIndex);
break;

case BC_STATE_PLAYEND:
this->ProcState_PlayEnd(iBridgeIndex);
break;
}
}


#ifdef FOREIGN_GAMESERVER
if ( szAuthKey[13] != AUTHKEY13 )
{
DestroyGIocp();
}
#endif

}

}




struct GC_BLOODCASTLESTATESEND
{
PHEADB PHeader; // C1:92
BYTE btState;
};




void CBloodCastle::ProcState_None(int iBridgeIndex)
{
return;
}




void CBloodCastle::ProcState_Closed(int iBridgeIndex)
{
int iTICK_MSEC = GetTickCount() - this->m_sttBloodCastleData[iBridgeIndex].iTickCount;

if ( iTICK_MSEC >= 1000 )
{
this->m_sttBloodCastleData[iBridgeIndex].iRemainTime -= iTICK_MSEC;
this->m_sttBloodCastleData[iBridgeIndex].iTickCount = GetTickCount();

if ( g_bBloodCastle != FALSE )
{
if ( this->m_sttBloodCastleData[iBridgeIndex].iRemainTime <= ( this->m_iWarningTime * 60 * 1000 ) && this->m_sttBloodCastleData[iBridgeIndex].bCanEnter == false)
{
this->m_sttBloodCastleData[iBridgeIndex].bCanEnter = true;
this->m_sttBloodCastleData[iBridgeIndex].bCanParty = true;
}

if ( this->m_sttBloodCastleData[iBridgeIndex].iRemainTime <= ( this->m_iWarningTime * 60 * 1000 ) && this->m_sttBloodCastleData[iBridgeIndex].iRemainTime > 0 && (this->m_sttBloodCastleData[iBridgeIndex].iRemainTime/60000) !=this->m_sttBloodCastleData[iBridgeIndex].iMinutesLeftToEnter)
{
this->m_sttBloodCastleData[iBridgeIndex].iMinutesLeftToEnter = this->m_sttBloodCastleData[iBridgeIndex].iRemainTime / 60000;

if ( iBridgeIndex == 0 )
{
NOTICE pNotice;

TNotice::MakeNoticeMsgEx((TNotice*)&pNotice, 0, (UCHAR*)lMsg.Get( MSGGET(4, 136)), this->m_sttBloodCastleData[iBridgeIndex].iMinutesLeftToEnter+1);
this->SendAllUserAnyMsg((BYTE *)&pNotice, pNotice.PacketHeader.uSize);
}
}

if ( this->m_sttBloodCastleData[iBridgeIndex].iRemainTime <= 30000 && this->m_sttBloodCastleData[iBridgeIndex].iRemainTime > 0 && this->m_sttBloodCastleData[iBridgeIndex].bIsLoadedStateClosed == false )
{
this->m_sttBloodCastleData[iBridgeIndex].bIsLoadedStateClosed = true;

if ( iBridgeIndex == 0 )
{
GC_BLOODCASTLESTATESEND pMsg;

PHeadSetB(&pMsg.PHeader, 0x92, sizeof(GC_BLOODCASTLESTATESEND));
pMsg.btState = 3;

for (int i= OBJ_STARTUSERINDEX;i<OBJMAX;i++)
{
if ( gObj[i].IsConnected == PLAYER_PLAYING && gObj[i].wObjectType == OBJ_USER)
{
if ( BC_MAP_RANGE(gObj[i].btMapNumber) == FALSE )
{
if ( CC_MAP_RANGE(gObj[i].btMapNumber) == FALSE )
{
DataSend(i, (UCHAR*)&pMsg, pMsg.PHeader.uSize);
}
}
}
}
}
}
}
}

if ( this->m_sttBloodCastleData[iBridgeIndex].iRemainTime <= 0 )
{
if ( g_bBloodCastle != FALSE )
{
this->SetState(iBridgeIndex, BC_STATE_PLAYING);
}
else
{
this->SetState(iBridgeIndex, BC_STATE_CLOSED);
}
}
}






void CBloodCastle::ProcState_Playing(int iBridgeIndex)
{
int iTICK_MSEC = GetTickCount() - this->m_sttBloodCastleData[iBridgeIndex].iTickCount;

if ( iTICK_MSEC >= 1000 )
{
this->m_sttBloodCastleData[iBridgeIndex].iRemainTime -= iTICK_MSEC;
this->m_sttBloodCastleData[iBridgeIndex].iTickCount = GetTickCount();

if ( this->m_sttBloodCastleData[iBridgeIndex].iRemainTime <= ((this->m_iEventTimeDuration*60-30)*1000) )
{
if ( this->m_sttBloodCastleData[iBridgeIndex].bIsLoadedStatePlaying == false )
{
this->m_sttBloodCastleData[iBridgeIndex].bIsLoadedStatePlaying = true;

GC_BLOODCASTLESTATESEND pMsg;
PHeadSetB(&pMsg.PHeader, 0x92, sizeof(GC_BLOODCASTLESTATESEND));
pMsg.btState = 4;
this->SendBridgeAnyMsg((BYTE*)&pMsg, sizeof(GC_BLOODCASTLESTATESEND), iBridgeIndex);
}
}

if ( this->m_sttBloodCastleData[iBridgeIndex].bMonsterKillSuccess != false )
{
if ( this->m_sttBloodCastleData[iBridgeIndex].iBridgeDestroyTick != -1 )
{
if ( GetTickCount() > this->m_sttBloodCastleData[iBridgeIndex].iBridgeDestroyTick )
{
this->ReleaseCastleBridge(iBridgeIndex);
this->SendCastleBridgeBlockInfo(iBridgeIndex, 0);
LogAddTD("[Blood Castle] (%d) Bridge Change Bridge Attribute -> Open", iBridgeIndex+1);
this->m_sttBloodCastleData[iBridgeIndex].iBridgeDestroyTick = -1; // Prevent multiple openings
}
}
}

// Set Play Quest
if ( this->m_sttBloodCastleData[iBridgeIndex].iRemainTime <= ((this->m_iEventTimeDuration*60-60)*1000) && this->m_sttBloodCastleData[iBridgeIndex].bStartPlaying == false )
{
NOTICE pNotice;

this->m_sttBloodCastleData[iBridgeIndex].iRemainTime = (this->m_iEventTimeDuration*60)*1000;
this->m_sttBloodCastleData[iBridgeIndex].bCanParty = false;
TNotice::MakeNoticeMsgEx((TNotice*)&pNotice, 0, (BYTE *)lMsg.Get(MSGGET(4, 137)), iBridgeIndex+1);
this->SendBridgeAnyMsg((BYTE *)&pNotice, pNotice.PacketHeader.uSize, iBridgeIndex);
this->ReleaseCastleEntrance(iBridgeIndex);
this->SendCastleEntranceBlockInfo(iBridgeIndex, 0);
this->m_sttBloodCastleData[iBridgeIndex].bStartPlaying = true;
this->SetMonster(iBridgeIndex);
this->SendNoticeState(iBridgeIndex, false);

LogAddTD("[Blood Castle] (%d) Blood Castle Quest Start", iBridgeIndex+1);
}

if ( this->m_sttBloodCastleData[iBridgeIndex].iRemainTime <= 30000 && this->m_sttBloodCastleData[iBridgeIndex].iRemainTime > 0 && this->m_sttBloodCastleData[iBridgeIndex].bIsEndOfStatePlaying == false) // Set counter to kick?
{
this->m_sttBloodCastleData[iBridgeIndex].bIsEndOfStatePlaying = true;
GC_BLOODCASTLESTATESEND pMsg;
PHeadSetB(&pMsg.PHeader, 0x92, sizeof(GC_BLOODCASTLESTATESEND));
pMsg.btState = 5;
this->SendBridgeAnyMsg((BYTE *)&pMsg, sizeof(GC_BLOODCASTLESTATESEND), iBridgeIndex);
}

if ( this->CheckEveryUserDie(iBridgeIndex) != false )
{
NOTICE pNotice;

TNotice::MakeNoticeMsg((TNotice*)&pNotice, 0, (BYTE *)lMsg.Get(MSGGET(4, 138)));
this->SendBridgeAnyMsg((BYTE *)&pNotice, pNotice.PacketHeader.uSize, iBridgeIndex);

LogAddTD("[Blood Castle] (%d) Blood Castle Quest Fail Result -> Destroy Castle Door [%s][%s]",
iBridgeIndex+1, this->m_sttBloodCastleData[iBridgeIndex].szGateDestroyAccountID,
this->m_sttBloodCastleData[iBridgeIndex].szGateDestroyCharName);

LogAddTD("[Blood Castle] (%d) Blood Castle Quest Fail Result -> Destroy Saint Status [%s][%s]",
iBridgeIndex+1, this->m_sttBloodCastleData[iBridgeIndex].szGateDestroyAccountID,
this->m_sttBloodCastleData[iBridgeIndex].szStatueDestroyCharName);
this->GiveReward_Fail(iBridgeIndex);
this->SetState(iBridgeIndex, BC_STATE_CLOSED);
LogAddTD("[Blood Castle] (%d) Blood Castle Quest Failed -> Every User Out", iBridgeIndex+1);
}
else
{
if ( this->m_sttBloodCastleData[iBridgeIndex].bStartPlaying != false )
{
if ( this->m_sttBloodCastleData[iBridgeIndex].unk15E == false || this->m_sttBloodCastleData[iBridgeIndex].bBossMonsterKillSuccess != false )
{
this->SendNoticeState(iBridgeIndex, 1);
}
else
{
this->SendNoticeState(iBridgeIndex, 4);
}
}
}

}

if ( this->m_sttBloodCastleData[iBridgeIndex].iRemainTime <= 0 )
{
if ( this->m_sttBloodCastleData[iBridgeIndex].bIsBloodQuestCompleted == false )
{
LogAddTD("[Blood Castle] (%d) Blood Castle Quest Fail Result -> Destroy Castle Door [%s][%s]",
iBridgeIndex+1, this->m_sttBloodCastleData[iBridgeIndex].szGateDestroyAccountID,
this->m_sttBloodCastleData[iBridgeIndex].szGateDestroyCharName);

LogAddTD("[Blood Castle] (%d) Blood Castle Quest Fail Result -> Destroy Saint Status [%s][%s]",
iBridgeIndex+1, this->m_sttBloodCastleData[iBridgeIndex].szStatueDestroyAccountID,
this->m_sttBloodCastleData[iBridgeIndex].szStatueDestroyCharName);
this->GiveReward_Fail(iBridgeIndex);

LogAddTD("[Blood Castle] (%d) Blood Castle Quest Failed -> Time Out", iBridgeIndex+1);

}

this->SetState(iBridgeIndex, BC_STATE_PLAYEND);
}
}






void CBloodCastle::ProcState_PlayEnd(int iBridgeIndex)
{
int iTICK_MSEC = GetTickCount() - this->m_sttBloodCastleData[iBridgeIndex].iTickCount;

if ( iTICK_MSEC >= 1000 )
{
this->m_sttBloodCastleData[iBridgeIndex].iRemainTime -= iTICK_MSEC;
this->m_sttBloodCastleData[iBridgeIndex].iTickCount = GetTickCount();

if ( this->m_sttBloodCastleData[iBridgeIndex].iRemainTime <= 30000 && this->m_sttBloodCastleData[iBridgeIndex].iRemainTime > 0 && this->m_sttBloodCastleData[iBridgeIndex].bIsLoadedStatePlayEnd == false)
{
this->m_sttBloodCastleData[iBridgeIndex].bIsLoadedStatePlayEnd = true;
GC_BLOODCASTLESTATESEND pMsg;
PHeadSetB(&pMsg.PHeader, 0x92, sizeof(GC_BLOODCASTLESTATESEND));
pMsg.btState = 6;
this->SendBridgeAnyMsg((BYTE *)&pMsg, sizeof(GC_BLOODCASTLESTATESEND), iBridgeIndex);
}


}

if ( this->m_sttBloodCastleData[iBridgeIndex].iRemainTime <= 0 )
{
this->SetState(iBridgeIndex, BC_STATE_CLOSED);
}
}






void CBloodCastle::SetState_None(int iBridgeIndex)
{
if ( BC_BRIDGE_RANGE(iBridgeIndex) == FALSE )
{
return;
}

this->m_sttBloodCastleData[iBridgeIndex].iRemainTime = -1;
this->m_sttBloodCastleData[iBridgeIndex].iTickCount = -1;
this->SendNoticeState(iBridgeIndex, 2);
this->ClearBridgeData(iBridgeIndex);
this->ClearMonster(iBridgeIndex, 1);

for (int n=OBJ_STARTUSERINDEX;n<OBJMAX;n++)
{
if ( gObj[n].btMapNumber == iBridgeIndex + 11 && gObj[n].IsConnected == PLAYER_PLAYING )
{
gObjMoveGate(n, 22);
}
}

this->BlockCastleDoor(iBridgeIndex);
}




void CBloodCastle::SetState_Closed(int iBridgeIndex)
{
if ( BC_BRIDGE_RANGE(iBridgeIndex) == FALSE )
{
return;
}

this->SendNoticeState(iBridgeIndex, 2);
this->ClearBridgeData(iBridgeIndex);
this->ClearMonster(iBridgeIndex, 1);
this->CheckAngelKingExist(iBridgeIndex);

for (int n=OBJ_STARTUSERINDEX;n<OBJMAX;n++)
{
if ( gObj[n].btMapNumber == iBridgeIndex + 11 && gObj[n].IsConnected > PLAYER_LOGGED )
{
this->SearchUserDeleteQuestItem(n);
gObjMoveGate(n, 22);
}
}

this->BlockCastleDoor(iBridgeIndex);
this->BlockCastleBridge(iBridgeIndex);
this->BlockCastleEntrance(iBridgeIndex);
this->CheckSync(iBridgeIndex);
LogAddTD("[Blood Castle] (%d) SetState CLOSED", iBridgeIndex+1);
}






void CBloodCastle::SetState_Playing(int iBridgeIndex)
{
if ( BC_BRIDGE_RANGE(iBridgeIndex) == FALSE )
{
return;
}

this->m_sttBloodCastleData[iBridgeIndex].bCanEnter = false;
this->m_sttBloodCastleData[iBridgeIndex].iRemainTime = this->m_iEventTimeDuration*60*1000;
this->CheckUsersOnConnect(iBridgeIndex);

NOTICE pNotice;

TNotice::MakeNoticeMsgEx((TNotice*)&pNotice, 1, (BYTE *)lMsg.Get(MSGGET(4, 139)), iBridgeIndex+1, 60);
this->SendBridgeAnyMsg((LPBYTE)&pNotice, pNotice.PacketHeader.uSize, iBridgeIndex);

GC_SERVERCMD ServerCmd;

PHeadSubSetB(&ServerCmd.PHeader, 0xF3, 0x40, sizeof(GC_SERVERCMD));
ServerCmd.btType = 1;
ServerCmd.btCmd1 = 45;
ServerCmd.btCmd2 = 0;

this->SendBridgeAnyMsg((BYTE *)&ServerCmd, ServerCmd.PHeader.uSize, iBridgeIndex);

for (int n=OBJ_STARTUSERINDEX;n<OBJMAX;n++)
{
if ( gObj[n].btMapNumber == iBridgeIndex + 11 && gObj[n].IsConnected > PLAYER_LOGGED )
{
this->SearchUserDeleteQuestItem(n);
}
}

LogAddTD("[Blood Castle] (%d) SetState PLAYING", iBridgeIndex+1);
}






void CBloodCastle::SetState_PlayEnd(int iBridgeIndex)
{
if ( BC_BRIDGE_RANGE(iBridgeIndex) == FALSE )
{
return;
}

this->SendNoticeState(iBridgeIndex, 2);
this->ClearMonster(iBridgeIndex, 0);
this->m_sttBloodCastleData[iBridgeIndex].bCanEnter = false;
this->m_sttBloodCastleData[iBridgeIndex].iRemainTime = this->m_iPreparationTime*60*1000;

LogAddTD("[Blood Castle] (%d) SetState PLAYEND", iBridgeIndex+1);

for (int n=0;n<MAX_BLOOD_CASTLE_SUB_BRIDGE;n++)
{
if ( OBJMAX_RANGE(this->m_sttBloodCastleData[iBridgeIndex].stBloodCastleSubInfo[n].iIndex) != FALSE )
{
this->SearchUserDeleteQuestItem(this->m_sttBloodCastleData[iBridgeIndex].stBloodCastleSubInfo[n].iIndex);
}
}
}









int CBloodCastle::GetCurrentState(int iBridgeIndex)
{
if ( BC_BRIDGE_RANGE(iBridgeIndex) == FALSE )
{
return -1;
}

return this->m_sttBloodCastleData[iBridgeIndex].iBCState;
}






int CBloodCastle::GetCurrentRemainSec(int iBridgeIndex)
{
return this->m_sttBloodCastleData[iBridgeIndex].iRemainTime / 1000;
}






int CBloodCastle::CheckEnterLevel(int iIndex, int iLevel) // RET : [2:Error][1:OverLevel][0:InLevel - Success][-1:UnderLevel]
{
if ( OBJMAX_RANGE(iIndex) == FALSE )
{
return 2;
}

if ( gObj[iIndex].wObjectType != OBJ_USER || gObj[iIndex].IsConnected <= PLAYER_LOGGED )
{
return 2;
}

if ( gObj[iIndex].wClass == 4 || gObj[iIndex].wClass == 3 )
{
if ( gObj[iIndex].Level >= g_sttBLOODCASTLE_LEVEL[iLevel-1].SpecialCharacterMinLevel && gObj[iIndex].Level <= g_sttBLOODCASTLE_LEVEL[iLevel-1].SpecialCharacterMaxLevel )
{
return 0;
}

if ( gObj[iIndex].Level < g_sttBLOODCASTLE_LEVEL[iLevel-1].SpecialCharacterMinLevel )
{
return -1;
}

if ( gObj[iIndex].Level > g_sttBLOODCASTLE_LEVEL[iLevel-1].SpecialCharacterMaxLevel )
{
return 1;
}
}
else
{
if ( gObj[iIndex].Level >= g_sttBLOODCASTLE_LEVEL[iLevel-1].NormalCharacterMinLevel && gObj[iIndex].Level <= g_sttBLOODCASTLE_LEVEL[iLevel-1].NormalCharacterMaxLevel )
{
return 0;
}

if ( gObj[iIndex].Level < g_sttBLOODCASTLE_LEVEL[iLevel-1].NormalCharacterMinLevel )
{
return -1;
}

if ( gObj[iIndex].Level > g_sttBLOODCASTLE_LEVEL[iLevel-1].NormalCharacterMaxLevel )
{
return 1;
}
}

return 2;
}








bool CBloodCastle::BloodCastleChaosMix(int iIndex, int iLEVEL)
{
if ( OBJMAX_RANGE(iIndex) == FALSE )
{
return false;
}

if ( BC_MAP_RANGE( (iLEVEL + 10) ) == FALSE )
{
return false;
}

BOOL bMIX_RESULT = FALSE;

GC_CHAOS_MIX pMsg;

PHeadSetB(&pMsg.PHeader, 0x86, sizeof(GC_CHAOS_MIX));
pMsg.btState = CB_ERROR;
gObj[iIndex].bCBMachineWorking = TRUE;

LogAddTD("[Blood Castle] Cape of Invisivility Mix Chaos Mix Start (Account:%s, Name:%s, Level:%d)",
gObj[iIndex].AccountID, gObj[iIndex].CharName, iLEVEL);
LogChaosItem(&gObj[iIndex], "Cape Of Invisivilty Mix");

int iMIX_SUCCESS_RATE = g_iBC_ChoasMixSuccessRate[iLEVEL - 1];

if ( iMIX_SUCCESS_RATE < 0 || iMIX_SUCCESS_RATE > 100 )
{
DataSend(iIndex, (UCHAR*)&pMsg, pMsg.PHeader.uSize);
LogAddTD("[Blood Castle] Cape of Invisibility Mix Chaos Mix Failed - MixRate Out of Bound (Account:%s, Name:%s, Level:%d",
gObj[iIndex].AccountID, gObj[iIndex].CharName, iLEVEL);

return false;
}

int iMIX_NEED_MONEY = g_iBC_ChoasMixMoney[iLEVEL - 1];
int iChaosTaxMoney = (int)((__int64)(iMIX_NEED_MONEY) * (__int64)(g_CastleSiegeSync.GetTaxRateChaos(iIndex )) / (__int64)100);

if ( iChaosTaxMoney < 0 )
{
iChaosTaxMoney = 0;
}

iMIX_NEED_MONEY += iChaosTaxMoney;

if ( iMIX_NEED_MONEY < 0 )
{
DataSend(iIndex, (UCHAR*)&pMsg, pMsg.PHeader.uSize);
LogAddTD("[Blood Castle] Cape of Invosibility Mix Chaos Mix Failed - MixMoney < 0 (Account:%s, Name:%s, Level:%d",
gObj[iIndex].AccountID, gObj[iIndex].CharName, iLEVEL);

return false;
}

if ( (gObj[iIndex].iZen - iMIX_NEED_MONEY) < 0 ) // Not enoght zen
{
pMsg.btState = CB_BC_NOT_ENOUGH_ZEN;
DataSend(iIndex, (UCHAR*)&pMsg, pMsg.PHeader.uSize);
LogAddTD("[Blood Castle] Cape of Invisibility Mix Chaos Mix Failed - Not Enough Money (Account:%s, Name:%s, Level:%d)",
gObj[iIndex].AccountID, gObj[iIndex].CharName, iLEVEL);

return false;
}

gObj[iIndex].iZen -= iMIX_NEED_MONEY;
g_CastleSiegeSync.AddTributeMoney(iChaosTaxMoney);
GCMoneySend(iIndex, gObj[iIndex].iZen);

if ( (rand()%100) < iMIX_SUCCESS_RATE ) // Siccess
{
int item_num = ITEMGET(13,18); // Invisibility Cloak
ItemSerialCreateSend(iIndex, -1, 0, 0, item_num, iLEVEL, 255, 0, 0, 0, -1, 0, 0);
LogAddTD("[Invisibility Cloak Mix] [%s][%s] CBMix Success %d Money : %d-%d",
gObj[iIndex].AccountID, gObj[iIndex].CharName, iMIX_SUCCESS_RATE, gObj[iIndex].iZen, iMIX_NEED_MONEY);
}
else // Failure
{
ChaosBoxInit(&gObj[iIndex]);
GCUserChaosBoxSend(&gObj[iIndex], 0);
DataSend(iIndex, (UCHAR*)&pMsg, pMsg.PHeader.uSize);
LogAddTD("[Invisibility Cloak Mix] [%s][%s] CBMix Fail %d Money : %d-%d",
gObj[iIndex].AccountID, gObj[iIndex].CharName, iMIX_SUCCESS_RATE, gObj[iIndex].iZen, iMIX_NEED_MONEY);

return false;
}

::gObjInventoryCommit(iIndex);

return true;
}









int CBloodCastle::CheckChaosMixItem(int iIndex)
{
if ( OBJMAX_RANGE(iIndex) == FALSE )
{
return false;
}

int iCHAOS_MIX_LEVEL = 0;
BOOL bIsChaosGemExist = FALSE;
BOOL bIsAngelKingPaperExist = FALSE;
BOOL bIsBloodBoneExist = FALSE;
BOOL bIsOtherItemExist = FALSE;
int iEventItemCount = 0;
int iAngelKingPaperLevel = 0;
int iBloodBoneLevel = 0;

for ( int i=0;i<CHAOS_BOX_SIZE;i++)
{
if ( gObj[iIndex].lpChaosBox[i].IsItem() == TRUE )
{
if ( gObj[iIndex].lpChaosBox[i].m_ItemNumber == ITEMGET(12,15) ) // Chaos
{
bIsChaosGemExist = TRUE;
}
else if ( gObj[iIndex].lpChaosBox[i].m_ItemNumber == ITEMGET(13,16) ) //Scroll of Archangel
{
int iSCROLL_LEVEL = gObj[iIndex].lpChaosBox[i].m_sItemLevel;
iEventItemCount++;
bIsAngelKingPaperExist = TRUE;
iAngelKingPaperLevel = iSCROLL_LEVEL;
}
else if ( gObj[iIndex].lpChaosBox[i].m_ItemNumber == ITEMGET(13,17) ) //Blood Bone
{
int iBLOOD_BONE_LEVEL = gObj[iIndex].lpChaosBox[i].m_sItemLevel;
iEventItemCount++;
bIsBloodBoneExist = TRUE;
iBloodBoneLevel = iBLOOD_BONE_LEVEL;
}
else
{
bIsOtherItemExist = TRUE;
}
}
}

if ( bIsOtherItemExist != FALSE )
{
return 8;
}

if ( bIsAngelKingPaperExist == FALSE && bIsBloodBoneExist == FALSE )
{
return 0;
}

if ( bIsAngelKingPaperExist == FALSE || bIsBloodBoneExist == FALSE )
{
return 11;
}

if ( iEventItemCount > 2 )
{
return 12;
}

if ( iAngelKingPaperLevel != iBloodBoneLevel )
{
return 9;
}

if ( (((iAngelKingPaperLevel-1) < 0)?FALSE:((iAngelKingPaperLevel-1) > MAX_BLOOD_CASTLE_LEVEL-1)?FALSE:TRUE) == FALSE )
{
return 9;
}

if ( (((iBloodBoneLevel-1) < 0)?FALSE:((iBloodBoneLevel-1) > MAX_BLOOD_CASTLE_LEVEL-1)?FALSE:TRUE) == FALSE )
{
return 9;
}

if ( bIsChaosGemExist == FALSE )
{
return 10;
}

if ( gObj[iIndex].wClass == 4 || gObj[iIndex].wClass == 3 )
{
if ( gObj[iIndex].Level < g_sttBLOODCASTLE_LEVEL[0].SpecialCharacterMinLevel )
{
return 14;
}
}
else
{
if ( gObj[iIndex].Level < g_sttBLOODCASTLE_LEVEL[0].NormalCharacterMinLevel )
{
return 14;
}
}

if ( bIsChaosGemExist != FALSE && bIsAngelKingPaperExist != FALSE && bIsBloodBoneExist != FALSE )
{
return iAngelKingPaperLevel;
}

return 0;
}







int CBloodCastle::CheckEnterItem(int iIndex)
{
int iITEM_LEVEL = 0;

if ( OBJMAX_RANGE(iIndex) == FALSE )
{
return 0;
}

if ( gObj[iIndex].wObjectType != OBJ_USER || gObj[iIndex].IsConnected <= PLAYER_LOGGED )
{
return 0;
}

for ( int x=0;x<MAIN_INVENTORY_SIZE;x++)
{
if ( gObj[iIndex].lpInventoryPointer[x].IsItem() == TRUE )
{
if ( gObj[iIndex].lpInventoryPointer[x].m_ItemNumber == ITEMGET(13,18) ) // Invisibility Cloak
{
iITEM_LEVEL = gObj[iIndex].lpInventoryPointer[x].m_sItemLevel;

if ( ((iITEM_LEVEL<0)?FALSE:(iITEM_LEVEL>MAX_BLOOD_CASTLE_LEVEL)?FALSE:TRUE) == FALSE )
{
iITEM_LEVEL = 0;

}

if ( iITEM_LEVEL != 0 )
{
return iITEM_LEVEL;
}
}
}
}

return iITEM_LEVEL;
}







int CBloodCastle::CheckQuestItem(int iIndex)
{
int iITEM_LEVEL = -1;

if ( OBJMAX_RANGE(iIndex) == FALSE )
{
return -1;
}

if ( BC_MAP_RANGE(gObj[iIndex].btMapNumber) == FALSE )
{
return -1;
}


if ( this->m_sttBloodCastleData[gObj[iIndex].btMapNumber - BLOOD_CASTLE_1 ].unk18C == -1 )
{
return -1;
}

if ( gObj[iIndex].wObjectType != OBJ_USER || gObj[iIndex].IsConnected <= PLAYER_LOGGED )
{
return -1;
}

for ( int x=0;x<MAIN_INVENTORY_SIZE;x++)
{
if ( gObj[iIndex].lpInventoryPointer[x].IsItem() == TRUE )
{
if ( gObj[iIndex].lpInventoryPointer[x].m_ItemNumber == ITEMGET(13,19) ) // Absolute Weapon of Archangel QUEST ITEM
{
if ( gObj[iIndex].lpInventoryPointer[x].m_ItemIndex == this->m_sttBloodCastleData[gObj[iIndex].btMapNumber - BLOOD_CASTLE_1].unk18C )
{
iITEM_LEVEL = gObj[iIndex].lpInventoryPointer[x].m_sItemLevel;

if ( iITEM_LEVEL < 0 || iITEM_LEVEL > 2 )
{
iITEM_LEVEL = -1;

}

break;
}
}
}
}

return iITEM_LEVEL;
}






bool CBloodCastle::CheckWalk(int iIndex, int iMoveX, int iMoveY)
{
if ( OBJMAX_RANGE(iIndex) == FALSE )
{
return false;
}

if ( BC_MAP_RANGE(gObj[iIndex].btMapNumber) == FALSE )
{
return false;
}

if ( gObj[iIndex].wObjectType != OBJ_USER || gObj[iIndex].IsConnected <= PLAYER_LOGGED )
{
return false;
}

if ( this->GetCurrentState(gObj[iIndex].btMapNumber ) == TRUE ) // Apply Deathway fix here : Add -BLOOD_CASTLE_1
{
BYTE btMapAttr = MapC[gObj[iIndex].btMapNumber].GetAttr(iMoveX, iMoveY);

if ( (btMapAttr&1) != 1 )
{
return true;
}
}

return false;
}






bool CBloodCastle::CheckCanEnter(int iBridgeIndex)
{
if ( BC_BRIDGE_RANGE(iBridgeIndex) == FALSE )
{
return false;
}

return this->m_sttBloodCastleData[iBridgeIndex].bCanEnter;
}






bool CBloodCastle::CheckCanParty(int iBridgeIndex)
{
if ( BC_BRIDGE_RANGE(iBridgeIndex) == FALSE )
{
return false;
}

return this->m_sttBloodCastleData[iBridgeIndex].bCanParty;
}







bool CBloodCastle::CheckQuestItemSerial(int iBridgeIndex, CMapItem * lpItem)
{
if ( BC_BRIDGE_RANGE(iBridgeIndex) == FALSE )
{
return false;
}

if ( this->m_sttBloodCastleData[iBridgeIndex].unk18C == -1 )
{
return false;
}

if ( lpItem->IsItem() == TRUE )
{
if ( lpItem->m_ItemNumber == ITEMGET(13,19) ) // Absolute Weapon
{
int iLEVEL = lpItem->m_sItemLevel;

if ( BC_WEAPON_LEVEL_RANGE(iLEVEL) != FALSE )
{
if ( this->m_sttBloodCastleData[iBridgeIndex].unk18C == lpItem->m_ItemIndex )
{
return true;
}
}
}
}


return false;

}






bool CBloodCastle::CheckPlayStart(int iBridgeIndex)
{
if ( BC_BRIDGE_RANGE(iBridgeIndex) == FALSE )
{
return false;
}

return this->m_sttBloodCastleData[iBridgeIndex].bStartPlaying;
}






int CBloodCastle::GetRemainTime(int iBridgeIndex)
{
int iREMAIN_MINUTE = 0;

if ( this->GetCurrentState(iBridgeIndex) == 1 )
{
iREMAIN_MINUTE = this->m_sttBloodCastleData[iBridgeIndex].iRemainTime / 60000 - this->m_iWarningTime + 1;
}
else
{
tm * today;
time_t ltime;
time(&ltime);
today = localtime(&ltime);

int iSTART_HOUR = g_iBloodCastle_StartHour;

if ( iSTART_HOUR != 2 )
{
//__asm JMP label2
}
else
{
if ( (today->tm_hour % 2) == 0 )
{
if ( (today->tm_min * 60 + today->tm_sec) >= 1800 )
{
iREMAIN_MINUTE = (9000 - (today->tm_min * 60 + today->tm_sec)) / 60;
}
else
{
iREMAIN_MINUTE = (1800 - (today->tm_min * 60 + today->tm_sec)) / 60;
}
}
else
{
iREMAIN_MINUTE = (1800 - (today->tm_min * 60 + today->tm_sec)) / 60;
}

if ( iREMAIN_MINUTE < 0 )
{
iREMAIN_MINUTE += 60;

}

__asm JMP skip;
}

if ( today->tm_min * 60 + today->tm_sec >= 1800 )
{
iREMAIN_MINUTE = (5400 - (today->tm_min * 60 + today->tm_sec)) / 60;
}
else
{
iREMAIN_MINUTE = (1800 - (today->tm_min * 60 + today->tm_sec)) / 60;
}

if ( iREMAIN_MINUTE < 0 )
{
iREMAIN_MINUTE += 60;
}


}

skip:
return iREMAIN_MINUTE;
}






void CBloodCastle::ClearMonster(int iBridgeIndex, bool bClearCastleDoor)
{
if ( BC_BRIDGE_RANGE(iBridgeIndex) == FALSE )
{
return;
}

for ( int n=0;n<OBJ_MAXMONSTER;n++)
{
if ( gObj[n].btMapNumber == (iBridgeIndex+BLOOD_CASTLE_1))
{
if ( bClearCastleDoor == false && gObj[n].wClass == 131)
{
continue;
}

if ( gObj[n].wClass == 232 )
{
continue;
}

gObjDel(n);
}
}
}






void CBloodCastle::SetMonster(int iBridgeIndex)
{
if ( BC_BRIDGE_RANGE(iBridgeIndex) == FALSE )
{
return;
}

this->SetMonsterKillCount(iBridgeIndex);
int nCastleDoorPosNum = this->m_sttBloodCastleData[iBridgeIndex].nCastleDoorPosNum;
BYTE btMonsterType = gMSetBase.m_sttMonsterSetBase[nCastleDoorPosNum].wMonsterIndex;
BYTE btMapNumber = gMSetBase.m_sttMonsterSetBase[nCastleDoorPosNum].btMapNumber;
BYTE btBloodCastleIndex = btMapNumber - BLOOD_CASTLE_1;

if ( nCastleDoorPosNum != -1 )
{
if ( btMonsterType == 131 )
{
int iIndex = ::gObjAddMonster(btMapNumber);

if ( iIndex >= 0 )
{
::gObjSetPosMonster(iIndex, nCastleDoorPosNum);
::gObjSetMonster(iIndex, btMonsterType);

gObj[iIndex].cBloodCastleBridgeIndex = btBloodCastleIndex;
gObj[iIndex].sItemRate = this->m_iNormalDropRateBase;
gObj[iIndex].btDirection = 1;
gObj[iIndex].sPositionTableNum = -1;
gObj[iIndex].btLive = TRUE;
gObj[iIndex].cKalimaDieRegen = FALSE;
gObj[iIndex].unk1B4 = 1;
gObj[iIndex].iRegenTime = 0;
gObj[iIndex].fMaxLife = this->m_sttBloodCastleData[btBloodCastleIndex].fGateLife;
gObj[iIndex].fLife = this->m_sttBloodCastleData[btBloodCastleIndex].fGateLife;
}
}
}

int result;
for ( int n=0;n<gMSetBase.m_iMonsterCount;n++)
{
if ( BC_MAP_RANGE(gMSetBase.m_sttMonsterSetBase[n].btMapNumber) != FALSE )
{
BYTE btIndex = gMSetBase.m_sttMonsterSetBase[n].wMonsterIndex;
BYTE btMap = gMSetBase.m_sttMonsterSetBase[n].btMapNumber;
BYTE btBridgeIndex = btMap - BLOOD_CASTLE_1;

if ( btBridgeIndex != iBridgeIndex )
{
continue;
}

if ( btIndex == 232 )
{
continue;
}

if ( btIndex == 131 )
{
continue;
}

if ( btIndex == 89 || btIndex == 95 || btIndex == 112 || btIndex == 118 || btIndex == 124 || btIndex == 130 || btIndex == 143 )
{
continue;
}

if ( ( ((btIndex-132)<0)?FALSE:((btIndex-132)>2)?FALSE:TRUE ) != FALSE )
{
continue;
}

result = gObjAddMonster(gMSetBase.m_sttMonsterSetBase[n].btMapNumber);

if ( result >= 0 )
{
gObj[result].sPositionTableNum = n;
gObj[result].sPosX = gMSetBase.m_sttMonsterSetBase[n].btStartX;
gObj[result].sPosY = gMSetBase.m_sttMonsterSetBase[n].btStartY;
gObj[result].btMapNumber = gMSetBase.m_sttMonsterSetBase[n].btMapNumber;
gObj[result].unk118 = gObj[result].sPosX;
gObj[result].unk11A = gObj[result].sPosY;
gObj[result].unk114 = gObj[result].sPosX;
gObj[result].unk116 = gObj[result].sPosY;
gObj[result].btDirection = gMSetBase.m_sttMonsterSetBase[n].btDirection;
gObj[result].unk112 = gObj[result].sPosX;
gObj[result].unk113 = gObj[result].sPosY;
gObjSetMonster(result, btIndex);
gObj[result].iRegenTime = this->m_iRegenTime;
gObj[result].cBloodCastleBridgeIndex = btBridgeIndex;
gObj[result].btDirection = rand() % 8;
}
}
}

}

eddy
22-05-08, 01:25 PM
Àh...dùng source của Deathways và add thêm code class vào đúng hem ông bạn Quỷ Kiếm Sầu :d

bachcotsau
22-05-08, 01:36 PM
Ờ đúng nhưng không hiểu sao họ không add thêm code vào để fix .Vì thế cho nên cái vé blood 8 không có tác dụng .Trên chỉ là 1 nữa source thôi .

hoanganhquan10a11
22-05-08, 07:13 PM
cái này là chạy querry hay j vậy

assataka
22-05-08, 08:42 PM
Theo mình đc bít source viết bằng C# trong bộ Visual Studio 2k5 hoặc 2k8. Bạn đã shared thì shared cả project (gồm các file liên kết với nhau, file quản lý toàn bộ có đuôi .sln), chứ đơn lẻ thể này và kô có hướng dẫn thì thà đừng shared. (Nói thật lòng).

eddy
23-05-08, 06:47 AM
Deathways share sao thì lấy vậy thui chứ biết đâu mà chọn..... ^:)^

thienfind
23-05-08, 09:17 AM
để em cố gắng thử xem dc thông sơ nảy sinh ra lổi khác

eddy
24-05-08, 10:40 AM
Thì building 1 dll rùi hooking vào GS xem có work ko ^^..... Chắc SCF cũng update Blood 8 thui.........

bachcotsau
24-05-08, 11:48 AM
Thì building 1 dll rùi hooking vào GS xem có work ko ^^..... Chắc SCF cũng update Blood 8 thui.........

Vấn đề chỉ là thời gian và many cho SCF thì mới chịu update nhanh .:go: Tôi mà biết VB open source thì ...

eddy
24-05-08, 01:25 PM
=))... Money mới là động lực để SCFMT Update ;))

hoanganhquan10a11
26-05-08, 12:07 PM
Cái source này thì dùng ra sao

bachcotsau
26-05-08, 06:32 PM
Cái source này thì dùng ra sao

Dùng ra sao thì phải xem người đó có source của gameserver để open hay không hoặc gameserver không bị pack để add thêm dll vào mà fix .