Merge pull request 'encoding' (#20) from Tr0n/server:encoding into nightly
Reviewed-on: #20
This commit is contained in:
commit
042414a499
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"cmake.configureOnOpen": true
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -2,15 +2,15 @@
|
|||
#define __HEADER_VNUM_HELPER__
|
||||
|
||||
/**
|
||||
이미 존재하거나 앞으로 추가될 아이템, 몹 등을 소스에서 식별할 때 현재는 모두
|
||||
식별자(숫자=VNum)를 하드코딩하는 방식으로 되어있어서 가독성이 매우 떨어지는데
|
||||
이미 존재하거나 앞으로 추가될 아이템, 몹 등을 소스에서 식별할 때 현재는 모두
|
||||
식별자(숫자=VNum)를 하드코딩하는 방식으로 되어있어서 가독성이 매우 떨어지는데
|
||||
|
||||
앞으로는 소스만 봐도 어떤 아이템(혹은 몹)인지 알 수 있게 하자는 승철님의 제안으로 추가.
|
||||
앞으로는 소스만 봐도 어떤 아이템(혹은 몹)인지 알 수 있게 하자는 승철님의 제안으로 추가.
|
||||
|
||||
* 이 파일은 변경이 잦을것으로 예상되는데 PCH에 넣으면 바뀔 때마다 전체 컴파일 해야하니
|
||||
일단은 필요한 cpp파일에서 include 해서 쓰도록 했음.
|
||||
* 이 파일은 변경이 잦을것으로 예상되는데 PCH에 넣으면 바뀔 때마다 전체 컴파일 해야하니
|
||||
일단은 필요한 cpp파일에서 include 해서 쓰도록 했음.
|
||||
|
||||
* cpp에서 구현하면 컴파일 ~ 링크해야하니 그냥 common에 헤더만 넣었음. (game, db프로젝트 둘 다 사용 예정)
|
||||
* cpp에서 구현하면 컴파일 ~ 링크해야하니 그냥 common에 헤더만 넣었음. (game, db프로젝트 둘 다 사용 예정)
|
||||
|
||||
@date 2011. 8. 29.
|
||||
*/
|
||||
|
@ -19,35 +19,35 @@
|
|||
class CItemVnumHelper
|
||||
{
|
||||
public:
|
||||
/// 독일 DVD용 불사조 소환권
|
||||
static const bool IsPhoenix(DWORD vnum) { return 53001 == vnum; } // NOTE: 불사조 소환 아이템은 53001 이지만 mob-vnum은 34001 입니다.
|
||||
/// 독일 DVD용 불사조 소환권
|
||||
static const bool IsPhoenix(DWORD vnum) { return 53001 == vnum; } // NOTE: 불사조 소환 아이템은 53001 이지만 mob-vnum은 34001 입니다.
|
||||
|
||||
/// 라마단 이벤트 초승달의 반지 (원래는 라마단 이벤트용 특수 아이템이었으나 앞으로 여러 방향으로 재활용해서 계속 쓴다고 함)
|
||||
/// 라마단 이벤트 초승달의 반지 (원래는 라마단 이벤트용 특수 아이템이었으나 앞으로 여러 방향으로 재활용해서 계속 쓴다고 함)
|
||||
static const bool IsRamadanMoonRing(DWORD vnum) { return 71135 == vnum; }
|
||||
|
||||
/// 할로윈 사탕 (스펙은 초승달의 반지와 동일)
|
||||
/// 할로윈 사탕 (스펙은 초승달의 반지와 동일)
|
||||
static const bool IsHalloweenCandy(DWORD vnum) { return 71136 == vnum; }
|
||||
|
||||
/// 크리스마스 행복의 반지
|
||||
/// 크리스마스 행복의 반지
|
||||
static const bool IsHappinessRing(DWORD vnum) { return 71143 == vnum; }
|
||||
|
||||
/// 발렌타인 사랑의 팬던트
|
||||
/// 발렌타인 사랑의 팬던트
|
||||
static const bool IsLovePendant(DWORD vnum) { return 71145 == vnum; }
|
||||
};
|
||||
|
||||
class CMobVnumHelper
|
||||
{
|
||||
public:
|
||||
/// 독일 DVD용 불사조 몹 번호
|
||||
/// 독일 DVD용 불사조 몹 번호
|
||||
static bool IsPhoenix(DWORD vnum) { return 34001 == vnum; }
|
||||
static bool IsIcePhoenix(DWORD vnum) { return 34003 == vnum; }
|
||||
/// PetSystem이 관리하는 펫인가?
|
||||
/// PetSystem이 관리하는 펫인가?
|
||||
static bool IsPetUsingPetSystem(DWORD vnum) { return (IsPhoenix(vnum) || IsReindeerYoung(vnum)) || IsIcePhoenix(vnum); }
|
||||
|
||||
/// 2011년 크리스마스 이벤트용 펫 (아기 순록)
|
||||
/// 2011년 크리스마스 이벤트용 펫 (아기 순록)
|
||||
static bool IsReindeerYoung(DWORD vnum) { return 34002 == vnum; }
|
||||
|
||||
/// 라마단 이벤트 보상용 흑마(20119) .. 할로윈 이벤트용 라마단 흑마 클론(스펙은 같음, 20219)
|
||||
/// 라마단 이벤트 보상용 흑마(20119) .. 할로윈 이벤트용 라마단 흑마 클론(스펙은 같음, 20219)
|
||||
static bool IsRamadanBlackHorse(DWORD vnum) { return 20119 == vnum || 20219 == vnum || 22022 == vnum; }
|
||||
};
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
int get_price () { return offer_price; }
|
||||
} TAuctionSimpleItemInfo;
|
||||
|
||||
// 각 auction 정보들.
|
||||
// 각 auction 정보들.
|
||||
// primary key (item_id)
|
||||
typedef struct _auction : public _base_auction
|
||||
{
|
||||
|
@ -49,8 +49,8 @@ public:
|
|||
empire = _empire;
|
||||
}
|
||||
|
||||
// 이 메소드들은 어떤 변수가 auction에서 어떤 역할을 하는지 까먹을 까봐
|
||||
// 만들어놓았다.
|
||||
// 이 메소드들은 어떤 변수가 auction에서 어떤 역할을 하는지 까먹을 까봐
|
||||
// 만들어놓았다.
|
||||
// by rtsummit
|
||||
DWORD get_item_id () { return item_id; }
|
||||
DWORD get_bidder_id () { return bidder_id; }
|
||||
|
@ -89,7 +89,7 @@ typedef struct _sale : public _base_auction
|
|||
|
||||
} TSaleItemInfo;
|
||||
|
||||
// wish는 실제하는 아이템은 없다.
|
||||
// wish는 실제하는 아이템은 없다.
|
||||
// primary key (item_num, wisher_id)
|
||||
typedef struct _wish : public _base_auction
|
||||
{
|
||||
|
@ -118,9 +118,9 @@ enum AuctionCmd {OPEN_AUCTION, OPEN_WISH_AUCTION, OPEN_MY_AUCTION, OPEN_MY_WISH_
|
|||
AUCTION_REBID, AUCTION_BID_CANCEL,
|
||||
};
|
||||
|
||||
// 반드시 FAIL 앞에, 실패 류 들이 와야한다.
|
||||
// 왜냐, <= AUCTION_FAIL 이런 CHECK을 할 거거든
|
||||
// 반대로 SUCCESS 뒤에, 성공 류 들이 와야한다. 근데 성공류가 있긴 하려나...
|
||||
// 반드시 FAIL 앞에, 실패 류 들이 와야한다.
|
||||
// 왜냐, <= AUCTION_FAIL 이런 CHECK을 할 거거든
|
||||
// 반대로 SUCCESS 뒤에, 성공 류 들이 와야한다. 근데 성공류가 있긴 하려나...
|
||||
|
||||
enum AuctionResult { AUCTION_EXPIRED, AUCTION_NOT_EXPIRED, AUCTION_NOT_ENOUGH_MONEY,
|
||||
AUCTION_SOLD, AUCTION_CANCEL, AUCTION_ALREADY_IN, AUCTION_NOT_IN, AUCTION_FAIL, AUCTION_SUCCESS };
|
||||
|
@ -218,7 +218,7 @@ typedef struct command_auction
|
|||
cmd = AUCTION_CHANGING_MONEY;
|
||||
price1 = _money;
|
||||
}
|
||||
// bid랑 cmd만 다르다.
|
||||
// bid랑 cmd만 다르다.
|
||||
void rebid (DWORD _item_id, int _bidPrice)
|
||||
{
|
||||
cmd = AUCTION_REBID;
|
||||
|
@ -322,7 +322,7 @@ typedef struct auction_impur : public command_auction
|
|||
// auction_type;
|
||||
// start_idx;
|
||||
// size;
|
||||
// conditions; 정렬은 승철님께 조언을 구해보자.ㅇㅇ
|
||||
// conditions; 정렬은 승철님께 조언을 구해보자.ㅇㅇ
|
||||
//}
|
||||
//
|
||||
//get_auction_detail_item_info
|
||||
|
|
|
@ -41,8 +41,8 @@ namespace building
|
|||
int lNPCX;
|
||||
int lNPCY;
|
||||
|
||||
DWORD dwGroupVnum; // 같은 그룹은 하나만 건설가능
|
||||
DWORD dwDependOnGroupVnum; // 지어져 있어야하는 그룹
|
||||
DWORD dwGroupVnum; // 같은 그룹은 하나만 건설가능
|
||||
DWORD dwDependOnGroupVnum; // 지어져 있어야하는 그룹
|
||||
} TObjectProto;
|
||||
|
||||
typedef struct SObject
|
||||
|
|
|
@ -31,8 +31,8 @@ enum EItemDragonSoulSockets
|
|||
ITEM_SOCKET_DRAGON_SOUL_ACTIVE_IDX = 2,
|
||||
ITEM_SOCKET_CHARGING_AMOUNT_IDX = 2,
|
||||
};
|
||||
// 헐 이거 미친거 아니야?
|
||||
// 나중에 소켓 확장하면 어쩌려고 이지랄 -_-;;;
|
||||
// 헐 이거 미친거 아니야?
|
||||
// 나중에 소켓 확장하면 어쩌려고 이지랄 -_-;;;
|
||||
enum EItemUniqueSockets
|
||||
{
|
||||
ITEM_SOCKET_UNIQUE_SAVE_TIME = ITEM_SOCKET_MAX_NUM - 2,
|
||||
|
@ -42,18 +42,18 @@ enum EItemUniqueSockets
|
|||
enum EItemTypes
|
||||
{
|
||||
ITEM_NONE, //0
|
||||
ITEM_WEAPON, //1//무기
|
||||
ITEM_ARMOR, //2//갑옷
|
||||
ITEM_USE, //3//아이템 사용
|
||||
ITEM_WEAPON, //1//무기
|
||||
ITEM_ARMOR, //2//갑옷
|
||||
ITEM_USE, //3//아이템 사용
|
||||
ITEM_AUTOUSE, //4
|
||||
ITEM_MATERIAL, //5
|
||||
ITEM_SPECIAL, //6 //스페셜 아이템
|
||||
ITEM_SPECIAL, //6 //스페셜 아이템
|
||||
ITEM_TOOL, //7
|
||||
ITEM_LOTTERY, //8//복권
|
||||
ITEM_ELK, //9//돈
|
||||
ITEM_LOTTERY, //8//복권
|
||||
ITEM_ELK, //9//돈
|
||||
ITEM_METIN, //10
|
||||
ITEM_CONTAINER, //11
|
||||
ITEM_FISH, //12//낚시
|
||||
ITEM_FISH, //12//낚시
|
||||
ITEM_ROD, //13
|
||||
ITEM_RESOURCE, //14
|
||||
ITEM_CAMPFIRE, //15
|
||||
|
@ -61,21 +61,21 @@ enum EItemTypes
|
|||
ITEM_SKILLBOOK, //17
|
||||
ITEM_QUEST, //18
|
||||
ITEM_POLYMORPH, //19
|
||||
ITEM_TREASURE_BOX, //20//보물상자
|
||||
ITEM_TREASURE_KEY, //21//보물상자 열쇠
|
||||
ITEM_TREASURE_BOX, //20//보물상자
|
||||
ITEM_TREASURE_KEY, //21//보물상자 열쇠
|
||||
ITEM_SKILLFORGET, //22
|
||||
ITEM_GIFTBOX, //23
|
||||
ITEM_PICK, //24
|
||||
ITEM_HAIR, //25//머리
|
||||
ITEM_TOTEM, //26//토템
|
||||
ITEM_BLEND, //27//생성될때 랜덤하게 속성이 붙는 약물
|
||||
ITEM_COSTUME, //28//코스츔 아이템 (2011년 8월 추가된 코스츔 시스템용 아이템)
|
||||
ITEM_DS, //29 //용혼석
|
||||
ITEM_SPECIAL_DS, //30 // 특수한 용혼석 (DS_SLOT에 착용하는 UNIQUE 아이템이라 생각하면 됨)
|
||||
ITEM_EXTRACT, //31 추출도구.
|
||||
ITEM_SECONDARY_COIN, //32 ?? 명도전??
|
||||
ITEM_RING, //33 반지
|
||||
ITEM_BELT, //34 벨트
|
||||
ITEM_HAIR, //25//머리
|
||||
ITEM_TOTEM, //26//토템
|
||||
ITEM_BLEND, //27//생성될때 랜덤하게 속성이 붙는 약물
|
||||
ITEM_COSTUME, //28//코스츔 아이템 (2011년 8월 추가된 코스츔 시스템용 아이템)
|
||||
ITEM_DS, //29 //용혼석
|
||||
ITEM_SPECIAL_DS, //30 // 특수한 용혼석 (DS_SLOT에 착용하는 UNIQUE 아이템이라 생각하면 됨)
|
||||
ITEM_EXTRACT, //31 추출도구.
|
||||
ITEM_SECONDARY_COIN, //32 ?? 명도전??
|
||||
ITEM_RING, //33 반지
|
||||
ITEM_BELT, //34 벨트
|
||||
};
|
||||
|
||||
enum EMetinSubTypes
|
||||
|
@ -111,8 +111,8 @@ enum EArmorSubTypes
|
|||
|
||||
enum ECostumeSubTypes
|
||||
{
|
||||
COSTUME_BODY = ARMOR_BODY, // [중요!!] ECostumeSubTypes enum value는 종류별로 EArmorSubTypes의 그것과 같아야 함.
|
||||
COSTUME_HAIR = ARMOR_HEAD, // 이는 코스츔 아이템에 추가 속성을 붙이겠다는 사업부의 요청에 따라서 기존 로직을 활용하기 위함임.
|
||||
COSTUME_BODY = ARMOR_BODY, // [중요!!] ECostumeSubTypes enum value는 종류별로 EArmorSubTypes의 그것과 같아야 함.
|
||||
COSTUME_HAIR = ARMOR_HEAD, // 이는 코스츔 아이템에 추가 속성을 붙이겠다는 사업부의 요청에 따라서 기존 로직을 활용하기 위함임.
|
||||
COSTUME_NUM_TYPES,
|
||||
};
|
||||
|
||||
|
@ -215,8 +215,8 @@ enum EUseSubTypes
|
|||
USE_UNBIND,
|
||||
USE_TIME_CHARGE_PER,
|
||||
USE_TIME_CHARGE_FIX, // 28
|
||||
USE_PUT_INTO_BELT_SOCKET, // 29 벨트 소켓에 사용할 수 있는 아이템
|
||||
USE_PUT_INTO_RING_SOCKET, // 30 반지 소켓에 사용할 수 있는 아이템 (유니크 반지 말고, 새로 추가된 반지 슬롯)
|
||||
USE_PUT_INTO_BELT_SOCKET, // 29 벨트 소켓에 사용할 수 있는 아이템
|
||||
USE_PUT_INTO_RING_SOCKET, // 30 반지 소켓에 사용할 수 있는 아이템 (유니크 반지 말고, 새로 추가된 반지 슬롯)
|
||||
};
|
||||
|
||||
enum EExtractSubTypes
|
||||
|
@ -270,7 +270,7 @@ enum EItemFlag
|
|||
{
|
||||
ITEM_FLAG_REFINEABLE = (1 << 0),
|
||||
ITEM_FLAG_SAVE = (1 << 1),
|
||||
ITEM_FLAG_STACKABLE = (1 << 2), // 여러개 합칠 수 있음
|
||||
ITEM_FLAG_STACKABLE = (1 << 2), // 여러개 합칠 수 있음
|
||||
ITEM_FLAG_COUNT_PER_1GOLD = (1 << 3),
|
||||
ITEM_FLAG_SLOW_QUERY = (1 << 4),
|
||||
ITEM_FLAG_UNUSED01 = (1 << 5), // UNUSED
|
||||
|
@ -287,24 +287,24 @@ enum EItemFlag
|
|||
|
||||
enum EItemAntiFlag
|
||||
{
|
||||
ITEM_ANTIFLAG_FEMALE = (1 << 0), // 여성 사용 불가
|
||||
ITEM_ANTIFLAG_MALE = (1 << 1), // 남성 사용 불가
|
||||
ITEM_ANTIFLAG_WARRIOR = (1 << 2), // 무사 사용 불가
|
||||
ITEM_ANTIFLAG_ASSASSIN = (1 << 3), // 자객 사용 불가
|
||||
ITEM_ANTIFLAG_SURA = (1 << 4), // 수라 사용 불가
|
||||
ITEM_ANTIFLAG_SHAMAN = (1 << 5), // 무당 사용 불가
|
||||
ITEM_ANTIFLAG_GET = (1 << 6), // 집을 수 없음
|
||||
ITEM_ANTIFLAG_DROP = (1 << 7), // 버릴 수 없음
|
||||
ITEM_ANTIFLAG_SELL = (1 << 8), // 팔 수 없음
|
||||
ITEM_ANTIFLAG_EMPIRE_A = (1 << 9), // A 제국 사용 불가
|
||||
ITEM_ANTIFLAG_EMPIRE_B = (1 << 10), // B 제국 사용 불가
|
||||
ITEM_ANTIFLAG_EMPIRE_C = (1 << 11), // C 제국 사용 불가
|
||||
ITEM_ANTIFLAG_SAVE = (1 << 12), // 저장되지 않음
|
||||
ITEM_ANTIFLAG_GIVE = (1 << 13), // 거래 불가
|
||||
ITEM_ANTIFLAG_PKDROP = (1 << 14), // PK시 떨어지지 않음
|
||||
ITEM_ANTIFLAG_STACK = (1 << 15), // 합칠 수 없음
|
||||
ITEM_ANTIFLAG_MYSHOP = (1 << 16), // 개인 상점에 올릴 수 없음
|
||||
ITEM_ANTIFLAG_SAFEBOX = (1 << 17), // 창고에 넣을 수 없음
|
||||
ITEM_ANTIFLAG_FEMALE = (1 << 0), // 여성 사용 불가
|
||||
ITEM_ANTIFLAG_MALE = (1 << 1), // 남성 사용 불가
|
||||
ITEM_ANTIFLAG_WARRIOR = (1 << 2), // 무사 사용 불가
|
||||
ITEM_ANTIFLAG_ASSASSIN = (1 << 3), // 자객 사용 불가
|
||||
ITEM_ANTIFLAG_SURA = (1 << 4), // 수라 사용 불가
|
||||
ITEM_ANTIFLAG_SHAMAN = (1 << 5), // 무당 사용 불가
|
||||
ITEM_ANTIFLAG_GET = (1 << 6), // 집을 수 없음
|
||||
ITEM_ANTIFLAG_DROP = (1 << 7), // 버릴 수 없음
|
||||
ITEM_ANTIFLAG_SELL = (1 << 8), // 팔 수 없음
|
||||
ITEM_ANTIFLAG_EMPIRE_A = (1 << 9), // A 제국 사용 불가
|
||||
ITEM_ANTIFLAG_EMPIRE_B = (1 << 10), // B 제국 사용 불가
|
||||
ITEM_ANTIFLAG_EMPIRE_C = (1 << 11), // C 제국 사용 불가
|
||||
ITEM_ANTIFLAG_SAVE = (1 << 12), // 저장되지 않음
|
||||
ITEM_ANTIFLAG_GIVE = (1 << 13), // 거래 불가
|
||||
ITEM_ANTIFLAG_PKDROP = (1 << 14), // PK시 떨어지지 않음
|
||||
ITEM_ANTIFLAG_STACK = (1 << 15), // 합칠 수 없음
|
||||
ITEM_ANTIFLAG_MYSHOP = (1 << 16), // 개인 상점에 올릴 수 없음
|
||||
ITEM_ANTIFLAG_SAFEBOX = (1 << 17), // 창고에 넣을 수 없음
|
||||
};
|
||||
|
||||
enum EItemWearableFlag
|
||||
|
@ -337,16 +337,16 @@ enum ELimitTypes
|
|||
// TODO: Remove this and re-check the validity of item_proto afterwards
|
||||
LIMIT_PCBANG,
|
||||
|
||||
/// 착용 여부와 상관 없이 실시간으로 시간 차감 (socket0에 소멸 시간이 박힘: unix_timestamp 타입)
|
||||
/// 착용 여부와 상관 없이 실시간으로 시간 차감 (socket0에 소멸 시간이 박힘: unix_timestamp 타입)
|
||||
LIMIT_REAL_TIME,
|
||||
|
||||
/// 아이템을 맨 처음 사용(혹은 착용) 한 순간부터 리얼타임 타이머 시작
|
||||
/// 최초 사용 전에는 socket0에 사용가능시간(초단위, 0이면 프로토의 limit value값 사용) 값이 쓰여있다가
|
||||
/// 아이템 사용시 socket1에 사용 횟수가 박히고 socket0에 unix_timestamp 타입의 소멸시간이 박힘.
|
||||
/// 아이템을 맨 처음 사용(혹은 착용) 한 순간부터 리얼타임 타이머 시작
|
||||
/// 최초 사용 전에는 socket0에 사용가능시간(초단위, 0이면 프로토의 limit value값 사용) 값이 쓰여있다가
|
||||
/// 아이템 사용시 socket1에 사용 횟수가 박히고 socket0에 unix_timestamp 타입의 소멸시간이 박힘.
|
||||
LIMIT_REAL_TIME_START_FIRST_USE,
|
||||
|
||||
/// 아이템을 착용 중일 때만 사용 시간이 차감되는 아이템
|
||||
/// socket0에 남은 시간이 초단위로 박힘. (아이템 최초 사용시 해당 값이 0이면 프로토의 limit value값을 socket0에 복사)
|
||||
/// 아이템을 착용 중일 때만 사용 시간이 차감되는 아이템
|
||||
/// socket0에 남은 시간이 초단위로 박힘. (아이템 최초 사용시 해당 값이 0이면 프로토의 limit value값을 socket0에 복사)
|
||||
LIMIT_TIMER_BASED_ON_WEAR,
|
||||
|
||||
LIMIT_MAX_NUM
|
||||
|
|
|
@ -21,10 +21,10 @@ enum EMisc
|
|||
|
||||
GUILD_NAME_MAX_LEN = 12,
|
||||
|
||||
SHOP_HOST_ITEM_MAX_NUM = 40, /* 호스트의 최대 아이템 개수 */
|
||||
SHOP_GUEST_ITEM_MAX_NUM = 18, /* 게스트의 최대 아이템 개수 */
|
||||
SHOP_HOST_ITEM_MAX_NUM = 40, /* 호스트의 최대 아이템 개수 */
|
||||
SHOP_GUEST_ITEM_MAX_NUM = 18, /* 게스트의 최대 아이템 개수 */
|
||||
|
||||
SHOP_PRICELIST_MAX_NUM = 40, ///< 개인상점 가격정보 리스트에서 유지할 가격정보의 최대 갯수
|
||||
SHOP_PRICELIST_MAX_NUM = 40, ///< 개인상점 가격정보 리스트에서 유지할 가격정보의 최대 갯수
|
||||
|
||||
CHAT_MAX_LEN = 512,
|
||||
|
||||
|
@ -78,19 +78,19 @@ enum EMisc
|
|||
|
||||
|
||||
/**
|
||||
**** 현재까지 할당 된 아이템 영역 정리 (DB상 Item Position) ****
|
||||
**** 현재까지 할당 된 아이템 영역 정리 (DB상 Item Position) ****
|
||||
+------------------------------------------------------+ 0
|
||||
| 캐릭터 기본 인벤토리 (45칸 * 2페이지) 90칸 |
|
||||
| 캐릭터 기본 인벤토리 (45칸 * 2페이지) 90칸 |
|
||||
+------------------------------------------------------+ 90 = INVENTORY_MAX_NUM(90)
|
||||
| 캐릭터 장비 창 (착용중인 아이템) 32칸 |
|
||||
| 캐릭터 장비 창 (착용중인 아이템) 32칸 |
|
||||
+------------------------------------------------------+ 122 = INVENTORY_MAX_NUM(90) + WEAR_MAX_NUM(32)
|
||||
| 용혼석 장비 창 (착용중인 용혼석) 12칸 |
|
||||
| 용혼석 장비 창 (착용중인 용혼석) 12칸 |
|
||||
+------------------------------------------------------+ 134 = 122 + DS_SLOT_MAX(6) * DRAGON_SOUL_DECK_MAX_NUM(2)
|
||||
| 용혼석 장비 창 예약 (아직 미사용) 18칸 |
|
||||
| 용혼석 장비 창 예약 (아직 미사용) 18칸 |
|
||||
+------------------------------------------------------+ 152 = 134 + DS_SLOT_MAX(6) * DRAGON_SOUL_DECK_RESERVED_MAX_NUM(3)
|
||||
| 벨트 인벤토리 (벨트 착용시에만 벨트 레벨에 따라 활성)|
|
||||
| 벨트 인벤토리 (벨트 착용시에만 벨트 레벨에 따라 활성)|
|
||||
+------------------------------------------------------+ 168 = 152 + BELT_INVENTORY_SLOT_COUNT(16) = INVENTORY_AND_EQUIP_CELL_MAX
|
||||
| 미사용 |
|
||||
| 미사용 |
|
||||
+------------------------------------------------------+ ??
|
||||
*/
|
||||
};
|
||||
|
@ -125,10 +125,10 @@ enum EWearPositions
|
|||
WEAR_COSTUME_BODY, // 19
|
||||
WEAR_COSTUME_HAIR, // 20
|
||||
|
||||
WEAR_RING1, // 21 : 신규 반지슬롯1 (왼쪽)
|
||||
WEAR_RING2, // 22 : 신규 반지슬롯2 (오른쪽)
|
||||
WEAR_RING1, // 21 : 신규 반지슬롯1 (왼쪽)
|
||||
WEAR_RING2, // 22 : 신규 반지슬롯2 (오른쪽)
|
||||
|
||||
WEAR_BELT, // 23 : 신규 벨트슬롯
|
||||
WEAR_BELT, // 23 : 신규 벨트슬롯
|
||||
|
||||
WEAR_MAX = 32 //
|
||||
};
|
||||
|
@ -139,7 +139,7 @@ enum EDragonSoulDeckType
|
|||
DRAGON_SOUL_DECK_1,
|
||||
DRAGON_SOUL_DECK_MAX_NUM = 2,
|
||||
|
||||
DRAGON_SOUL_DECK_RESERVED_MAX_NUM = 3, // NOTE: 중요! 아직 사용중이진 않지만, 3페이지 분량을 예약 해 둠. DS DECK을 늘릴 경우 반드시 그 수만큼 RESERVED에서 차감해야 함!
|
||||
DRAGON_SOUL_DECK_RESERVED_MAX_NUM = 3, // NOTE: 중요! 아직 사용중이진 않지만, 3페이지 분량을 예약 해 둠. DS DECK을 늘릴 경우 반드시 그 수만큼 RESERVED에서 차감해야 함!
|
||||
};
|
||||
|
||||
enum ESex
|
||||
|
@ -161,7 +161,7 @@ enum EDirection
|
|||
DIR_MAX_NUM
|
||||
};
|
||||
|
||||
#define ABILITY_MAX_LEVEL 10 /* 기술 최대 레벨 */
|
||||
#define ABILITY_MAX_LEVEL 10 /* 기술 최대 레벨 */
|
||||
|
||||
enum EAbilityDifficulty
|
||||
{
|
||||
|
@ -174,9 +174,9 @@ enum EAbilityDifficulty
|
|||
|
||||
enum EAbilityCategory
|
||||
{
|
||||
CATEGORY_PHYSICAL, /* 신체적 어빌리티 */
|
||||
CATEGORY_MENTAL, /* 정신적 어빌리티 */
|
||||
CATEGORY_ATTRIBUTE, /* 능력 어빌리티 */
|
||||
CATEGORY_PHYSICAL, /* 신체적 어빌리티 */
|
||||
CATEGORY_MENTAL, /* 정신적 어빌리티 */
|
||||
CATEGORY_ATTRIBUTE, /* 능력 어빌리티 */
|
||||
CATEGORY_NUM_TYPES
|
||||
};
|
||||
|
||||
|
@ -246,13 +246,13 @@ enum EParts
|
|||
|
||||
enum EChatType
|
||||
{
|
||||
CHAT_TYPE_TALKING, /* 그냥 채팅 */
|
||||
CHAT_TYPE_INFO, /* 정보 (아이템을 집었다, 경험치를 얻었다. 등) */
|
||||
CHAT_TYPE_NOTICE, /* 공지사항 */
|
||||
CHAT_TYPE_PARTY, /* 파티말 */
|
||||
CHAT_TYPE_GUILD, /* 길드말 */
|
||||
CHAT_TYPE_COMMAND, /* 일반 명령 */
|
||||
CHAT_TYPE_SHOUT, /* 외치기 */
|
||||
CHAT_TYPE_TALKING, /* 그냥 채팅 */
|
||||
CHAT_TYPE_INFO, /* 정보 (아이템을 집었다, 경험치를 얻었다. 등) */
|
||||
CHAT_TYPE_NOTICE, /* 공지사항 */
|
||||
CHAT_TYPE_PARTY, /* 파티말 */
|
||||
CHAT_TYPE_GUILD, /* 길드말 */
|
||||
CHAT_TYPE_COMMAND, /* 일반 명령 */
|
||||
CHAT_TYPE_SHOUT, /* 외치기 */
|
||||
CHAT_TYPE_WHISPER,
|
||||
CHAT_TYPE_BIG_NOTICE,
|
||||
CHAT_TYPE_MONARCH_NOTICE,
|
||||
|
@ -395,38 +395,38 @@ enum EApplyTypes
|
|||
APPLY_ATTBONUS_SURA, // 61
|
||||
APPLY_ATTBONUS_SHAMAN, // 62
|
||||
APPLY_ATTBONUS_MONSTER, // 63
|
||||
APPLY_MALL_ATTBONUS, // 64 공격력 +x%
|
||||
APPLY_MALL_DEFBONUS, // 65 방어력 +x%
|
||||
APPLY_MALL_EXPBONUS, // 66 경험치 +x%
|
||||
APPLY_MALL_ITEMBONUS, // 67 아이템 드롭율 x/10배
|
||||
APPLY_MALL_GOLDBONUS, // 68 돈 드롭율 x/10배
|
||||
APPLY_MAX_HP_PCT, // 69 최대 생명력 +x%
|
||||
APPLY_MAX_SP_PCT, // 70 최대 정신력 +x%
|
||||
APPLY_SKILL_DAMAGE_BONUS, // 71 스킬 데미지 * (100+x)%
|
||||
APPLY_NORMAL_HIT_DAMAGE_BONUS, // 72 평타 데미지 * (100+x)%
|
||||
APPLY_SKILL_DEFEND_BONUS, // 73 스킬 데미지 방어 * (100-x)%
|
||||
APPLY_NORMAL_HIT_DEFEND_BONUS, // 74 평타 데미지 방어 * (100-x)%
|
||||
APPLY_PC_BANG_EXP_BONUS, // 75 PC방 아이템 EXP 보너스
|
||||
APPLY_PC_BANG_DROP_BONUS, // 76 PC방 아이템 드롭율 보너스
|
||||
APPLY_MALL_ATTBONUS, // 64 공격력 +x%
|
||||
APPLY_MALL_DEFBONUS, // 65 방어력 +x%
|
||||
APPLY_MALL_EXPBONUS, // 66 경험치 +x%
|
||||
APPLY_MALL_ITEMBONUS, // 67 아이템 드롭율 x/10배
|
||||
APPLY_MALL_GOLDBONUS, // 68 돈 드롭율 x/10배
|
||||
APPLY_MAX_HP_PCT, // 69 최대 생명력 +x%
|
||||
APPLY_MAX_SP_PCT, // 70 최대 정신력 +x%
|
||||
APPLY_SKILL_DAMAGE_BONUS, // 71 스킬 데미지 * (100+x)%
|
||||
APPLY_NORMAL_HIT_DAMAGE_BONUS, // 72 평타 데미지 * (100+x)%
|
||||
APPLY_SKILL_DEFEND_BONUS, // 73 스킬 데미지 방어 * (100-x)%
|
||||
APPLY_NORMAL_HIT_DEFEND_BONUS, // 74 평타 데미지 방어 * (100-x)%
|
||||
APPLY_PC_BANG_EXP_BONUS, // 75 PC방 아이템 EXP 보너스
|
||||
APPLY_PC_BANG_DROP_BONUS, // 76 PC방 아이템 드롭율 보너스
|
||||
|
||||
APPLY_EXTRACT_HP_PCT, // 77 사용시 HP 소모
|
||||
APPLY_EXTRACT_HP_PCT, // 77 사용시 HP 소모
|
||||
|
||||
APPLY_RESIST_WARRIOR, // 78 무사에게 저항
|
||||
APPLY_RESIST_ASSASSIN, // 79 자객에게 저항
|
||||
APPLY_RESIST_SURA, // 80 수라에게 저항
|
||||
APPLY_RESIST_SHAMAN, // 81 무당에게 저항
|
||||
APPLY_ENERGY, // 82 기력
|
||||
APPLY_DEF_GRADE, // 83 방어력. DEF_GRADE_BONUS는 클라에서 두배로 보여지는 의도된 버그(...)가 있다.
|
||||
APPLY_COSTUME_ATTR_BONUS, // 84 코스튬 아이템에 붙은 속성치 보너스
|
||||
APPLY_MAGIC_ATTBONUS_PER, // 85 마법 공격력 +x%
|
||||
APPLY_MELEE_MAGIC_ATTBONUS_PER, // 86 마법 + 밀리 공격력 +x%
|
||||
APPLY_RESIST_WARRIOR, // 78 무사에게 저항
|
||||
APPLY_RESIST_ASSASSIN, // 79 자객에게 저항
|
||||
APPLY_RESIST_SURA, // 80 수라에게 저항
|
||||
APPLY_RESIST_SHAMAN, // 81 무당에게 저항
|
||||
APPLY_ENERGY, // 82 기력
|
||||
APPLY_DEF_GRADE, // 83 방어력. DEF_GRADE_BONUS는 클라에서 두배로 보여지는 의도된 버그(...)가 있다.
|
||||
APPLY_COSTUME_ATTR_BONUS, // 84 코스튬 아이템에 붙은 속성치 보너스
|
||||
APPLY_MAGIC_ATTBONUS_PER, // 85 마법 공격력 +x%
|
||||
APPLY_MELEE_MAGIC_ATTBONUS_PER, // 86 마법 + 밀리 공격력 +x%
|
||||
|
||||
APPLY_RESIST_ICE, // 87 냉기 저항
|
||||
APPLY_RESIST_EARTH, // 88 대지 저항
|
||||
APPLY_RESIST_DARK, // 89 어둠 저항
|
||||
APPLY_RESIST_ICE, // 87 냉기 저항
|
||||
APPLY_RESIST_EARTH, // 88 대지 저항
|
||||
APPLY_RESIST_DARK, // 89 어둠 저항
|
||||
|
||||
APPLY_ANTI_CRITICAL_PCT, //90 크리티컬 저항
|
||||
APPLY_ANTI_PENETRATE_PCT, //91 관통타격 저항
|
||||
APPLY_ANTI_CRITICAL_PCT, //90 크리티컬 저항
|
||||
APPLY_ANTI_PENETRATE_PCT, //91 관통타격 저항
|
||||
|
||||
|
||||
MAX_APPLY_NUM, //
|
||||
|
@ -578,7 +578,7 @@ enum EGuildWarState
|
|||
GUILD_WAR_OVER,
|
||||
GUILD_WAR_RESERVE,
|
||||
|
||||
GUILD_WAR_DURATION = 30*60, // 1시간
|
||||
GUILD_WAR_DURATION = 30*60, // 1시간
|
||||
GUILD_WAR_WIN_POINT = 1000,
|
||||
GUILD_WAR_LADDER_HALF_PENALTY_TIME = 12*60*60,
|
||||
};
|
||||
|
@ -622,13 +622,13 @@ enum EMoneyLogType
|
|||
|
||||
enum EPremiumTypes
|
||||
{
|
||||
PREMIUM_EXP, // 경험치가 1.2배
|
||||
PREMIUM_ITEM, // 아이템 드롭율이 2배
|
||||
PREMIUM_SAFEBOX, // 창고가 1칸에서 3칸
|
||||
PREMIUM_AUTOLOOT, // 돈 자동 줍기
|
||||
PREMIUM_FISH_MIND, // 고급 물고기 낚일 확률 상승
|
||||
PREMIUM_MARRIAGE_FAST, // 금실 증가 양을 빠르게합니다.
|
||||
PREMIUM_GOLD, // 돈 드롭율이 1.5배
|
||||
PREMIUM_EXP, // 경험치가 1.2배
|
||||
PREMIUM_ITEM, // 아이템 드롭율이 2배
|
||||
PREMIUM_SAFEBOX, // 창고가 1칸에서 3칸
|
||||
PREMIUM_AUTOLOOT, // 돈 자동 줍기
|
||||
PREMIUM_FISH_MIND, // 고급 물고기 낚일 확률 상승
|
||||
PREMIUM_MARRIAGE_FAST, // 금실 증가 양을 빠르게합니다.
|
||||
PREMIUM_GOLD, // 돈 드롭율이 1.5배
|
||||
PREMIUM_MAX_NUM = 9
|
||||
};
|
||||
|
||||
|
@ -658,10 +658,10 @@ enum SPECIAL_EFFECT
|
|||
SE_AUTO_HPUP,
|
||||
SE_AUTO_SPUP,
|
||||
|
||||
SE_EQUIP_RAMADAN_RING, // 라마단 초승달의 반지(71135) 착용할 때 이펙트 (발동이펙트임, 지속이펙트 아님)
|
||||
SE_EQUIP_HALLOWEEN_CANDY, // 할로윈 사탕을 착용(-_-;)한 순간에 발동하는 이펙트
|
||||
SE_EQUIP_HAPPINESS_RING, // 크리스마스 행복의 반지(71143) 착용할 때 이펙트 (발동이펙트임, 지속이펙트 아님)
|
||||
SE_EQUIP_LOVE_PENDANT, // 발렌타인 사랑의 팬던트(71145) 착용할 때 이펙트 (발동이펙트임, 지속이펙트 아님)
|
||||
SE_EQUIP_RAMADAN_RING, // 라마단 초승달의 반지(71135) 착용할 때 이펙트 (발동이펙트임, 지속이펙트 아님)
|
||||
SE_EQUIP_HALLOWEEN_CANDY, // 할로윈 사탕을 착용(-_-;)한 순간에 발동하는 이펙트
|
||||
SE_EQUIP_HAPPINESS_RING, // 크리스마스 행복의 반지(71143) 착용할 때 이펙트 (발동이펙트임, 지속이펙트 아님)
|
||||
SE_EQUIP_LOVE_PENDANT, // 발렌타인 사랑의 팬던트(71145) 착용할 때 이펙트 (발동이펙트임, 지속이펙트 아님)
|
||||
} ;
|
||||
|
||||
enum ETeenFlags
|
||||
|
@ -676,10 +676,10 @@ enum ETeenFlags
|
|||
|
||||
#include "item_length.h"
|
||||
|
||||
// inventory의 position을 나타내는 구조체
|
||||
// int와의 암시적 형변환이 있는 이유는,
|
||||
// 인벤 관련된 모든 함수가 window_type은 받지 않고, cell 하나만 받았기 때문에,(기존에는 인벤이 하나 뿐이어서 inventory type이란게 필요없었기 때문에,)
|
||||
// 인벤 관련 모든 함수 호출부분을 수정하는 것이 난감하기 ??문이다.
|
||||
// inventory의 position을 나타내는 구조체
|
||||
// int와의 암시적 형변환이 있는 이유는,
|
||||
// 인벤 관련된 모든 함수가 window_type은 받지 않고, cell 하나만 받았기 때문에,(기존에는 인벤이 하나 뿐이어서 inventory type이란게 필요없었기 때문에,)
|
||||
// 인벤 관련 모든 함수 호출부분을 수정하는 것이 난감하기 ??문이다.
|
||||
|
||||
enum EDragonSoulRefineWindowSize
|
||||
{
|
||||
|
@ -728,7 +728,7 @@ typedef struct SItemPos
|
|||
return cell < INVENTORY_AND_EQUIP_SLOT_MAX;
|
||||
case DRAGON_SOUL_INVENTORY:
|
||||
return cell < (DRAGON_SOUL_INVENTORY_MAX_NUM);
|
||||
// 동적으로 크기가 정해지는 window는 valid 체크를 할 수가 없다.
|
||||
// 동적으로 크기가 정해지는 window는 valid 체크를 할 수가 없다.
|
||||
case SAFEBOX:
|
||||
case MALL:
|
||||
return false;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
typedef DWORD IDENT;
|
||||
|
||||
/**
|
||||
* @version 05/06/10 Bang2ni - Myshop Pricelist 관련 패킷 HEADER_XX_MYSHOP_PRICELIST_XXX 추가
|
||||
* @version 05/06/10 Bang2ni - Myshop Pricelist 관련 패킷 HEADER_XX_MYSHOP_PRICELIST_XXX 추가
|
||||
*/
|
||||
enum
|
||||
{
|
||||
|
@ -99,22 +99,22 @@ enum
|
|||
HEADER_GD_LOGIN_BY_KEY = 101,
|
||||
HEADER_GD_MALL_LOAD = 107,
|
||||
|
||||
HEADER_GD_MYSHOP_PRICELIST_UPDATE = 108, ///< 가격정보 갱신 요청
|
||||
HEADER_GD_MYSHOP_PRICELIST_REQ = 109, ///< 가격정보 리스트 요청
|
||||
HEADER_GD_MYSHOP_PRICELIST_UPDATE = 108, ///< 가격정보 갱신 요청
|
||||
HEADER_GD_MYSHOP_PRICELIST_REQ = 109, ///< 가격정보 리스트 요청
|
||||
|
||||
HEADER_GD_BLOCK_CHAT = 110,
|
||||
|
||||
HEADER_GD_HAMMER_OF_TOR = 114,
|
||||
HEADER_GD_RELOAD_ADMIN = 115, ///<운영자 정보 요청
|
||||
HEADER_GD_BREAK_MARRIAGE = 116, ///< 결혼 파기
|
||||
HEADER_GD_ELECT_MONARCH = 117, ///< 군주 투표
|
||||
HEADER_GD_CANDIDACY = 118, ///< 군주 등록
|
||||
HEADER_GD_ADD_MONARCH_MONEY = 119, ///< 군주 돈 증가
|
||||
HEADER_GD_TAKE_MONARCH_MONEY = 120, ///< 군주 돈 감소
|
||||
HEADER_GD_COME_TO_VOTE = 121, ///< 표결
|
||||
HEADER_GD_RMCANDIDACY = 122, ///< 후보 제거 (운영자)
|
||||
HEADER_GD_SETMONARCH = 123, ///<군주설정 (운영자)
|
||||
HEADER_GD_RMMONARCH = 124, ///<군주삭제
|
||||
HEADER_GD_RELOAD_ADMIN = 115, ///<운영자 정보 요청
|
||||
HEADER_GD_BREAK_MARRIAGE = 116, ///< 결혼 파기
|
||||
HEADER_GD_ELECT_MONARCH = 117, ///< 군주 투표
|
||||
HEADER_GD_CANDIDACY = 118, ///< 군주 등록
|
||||
HEADER_GD_ADD_MONARCH_MONEY = 119, ///< 군주 돈 증가
|
||||
HEADER_GD_TAKE_MONARCH_MONEY = 120, ///< 군주 돈 감소
|
||||
HEADER_GD_COME_TO_VOTE = 121, ///< 표결
|
||||
HEADER_GD_RMCANDIDACY = 122, ///< 후보 제거 (운영자)
|
||||
HEADER_GD_SETMONARCH = 123, ///<군주설정 (운영자)
|
||||
HEADER_GD_RMMONARCH = 124, ///<군주삭제
|
||||
HEADER_GD_DEC_MONARCH_MONEY = 125,
|
||||
|
||||
HEADER_GD_CHANGE_MONARCH_LORD = 126,
|
||||
|
@ -126,7 +126,7 @@ enum
|
|||
HEADER_GD_UPDATE_HORSE_NAME = 131,
|
||||
HEADER_GD_REQ_HORSE_NAME = 132,
|
||||
|
||||
HEADER_GD_DC = 133, // Login Key를 지움
|
||||
HEADER_GD_DC = 133, // Login Key를 지움
|
||||
|
||||
HEADER_GD_VALID_LOGOUT = 134,
|
||||
|
||||
|
@ -238,17 +238,17 @@ enum
|
|||
HEADER_DG_WEDDING_START = 155,
|
||||
HEADER_DG_WEDDING_END = 156,
|
||||
|
||||
HEADER_DG_MYSHOP_PRICELIST_RES = 157, ///< 가격정보 리스트 응답
|
||||
HEADER_DG_RELOAD_ADMIN = 158, ///< 운영자 정보 리로드
|
||||
HEADER_DG_BREAK_MARRIAGE = 159, ///< 결혼 파기
|
||||
HEADER_DG_ELECT_MONARCH = 160, ///< 군주 투표
|
||||
HEADER_DG_CANDIDACY = 161, ///< 군주 등록
|
||||
HEADER_DG_ADD_MONARCH_MONEY = 162, ///< 군주 돈 증가
|
||||
HEADER_DG_TAKE_MONARCH_MONEY = 163, ///< 군주 돈 감소
|
||||
HEADER_DG_COME_TO_VOTE = 164, ///< 표결
|
||||
HEADER_DG_RMCANDIDACY = 165, ///< 후보 제거 (운영자)
|
||||
HEADER_DG_SETMONARCH = 166, ///<군주설정 (운영자)
|
||||
HEADER_DG_RMMONARCH = 167, ///<군주삭제
|
||||
HEADER_DG_MYSHOP_PRICELIST_RES = 157, ///< 가격정보 리스트 응답
|
||||
HEADER_DG_RELOAD_ADMIN = 158, ///< 운영자 정보 리로드
|
||||
HEADER_DG_BREAK_MARRIAGE = 159, ///< 결혼 파기
|
||||
HEADER_DG_ELECT_MONARCH = 160, ///< 군주 투표
|
||||
HEADER_DG_CANDIDACY = 161, ///< 군주 등록
|
||||
HEADER_DG_ADD_MONARCH_MONEY = 162, ///< 군주 돈 증가
|
||||
HEADER_DG_TAKE_MONARCH_MONEY = 163, ///< 군주 돈 감소
|
||||
HEADER_DG_COME_TO_VOTE = 164, ///< 표결
|
||||
HEADER_DG_RMCANDIDACY = 165, ///< 후보 제거 (운영자)
|
||||
HEADER_DG_SETMONARCH = 166, ///<군주설정 (운영자)
|
||||
HEADER_DG_RMMONARCH = 167, ///<군주삭제
|
||||
HEADER_DG_DEC_MONARCH_MONEY = 168,
|
||||
|
||||
HEADER_DG_CHANGE_MONARCH_LORD_ACK = 169,
|
||||
|
@ -343,7 +343,7 @@ typedef struct SPlayerItem
|
|||
DWORD count;
|
||||
|
||||
DWORD vnum;
|
||||
LONG alSockets[ITEM_SOCKET_MAX_NUM]; // 소켓번호
|
||||
LONG alSockets[ITEM_SOCKET_MAX_NUM]; // 소켓번호
|
||||
|
||||
TPlayerItemAttribute aAttr[ITEM_ATTRIBUTE_MAX_NUM];
|
||||
|
||||
|
@ -550,9 +550,9 @@ typedef struct SShopItemTable
|
|||
DWORD vnum;
|
||||
BYTE count;
|
||||
|
||||
TItemPos pos; // PC 상점에만 이용
|
||||
DWORD price; // PC, shop_table_ex.txt 상점에만 이용
|
||||
BYTE display_pos; // PC, shop_table_ex.txt 상점에만 이용, 보일 위치.
|
||||
TItemPos pos; // PC 상점에만 이용
|
||||
DWORD price; // PC, shop_table_ex.txt 상점에만 이용
|
||||
BYTE display_pos; // PC, shop_table_ex.txt 상점에만 이용, 보일 위치.
|
||||
} TShopItemTable;
|
||||
|
||||
typedef struct SShopTable
|
||||
|
@ -616,12 +616,12 @@ typedef struct SItemTable : public SEntityTable
|
|||
BYTE bSpecular;
|
||||
BYTE bGainSocketPct;
|
||||
|
||||
WORD sAddonType; // 기본 속성
|
||||
WORD sAddonType; // 기본 속성
|
||||
|
||||
// 아래 limit flag들은 realtime에 체크 할 일이 많고, 아이템 VNUM당 고정된 값인데,
|
||||
// 현재 구조대로 매번 아이템마다 필요한 경우에 LIMIT_MAX_NUM까지 루프돌면서 체크하는 부하가 커서 미리 저장 해 둠.
|
||||
char cLimitRealTimeFirstUseIndex; // 아이템 limit 필드값 중에서 LIMIT_REAL_TIME_FIRST_USE 플래그의 위치 (없으면 -1)
|
||||
char cLimitTimerBasedOnWearIndex; // 아이템 limit 필드값 중에서 LIMIT_TIMER_BASED_ON_WEAR 플래그의 위치 (없으면 -1)
|
||||
// 아래 limit flag들은 realtime에 체크 할 일이 많고, 아이템 VNUM당 고정된 값인데,
|
||||
// 현재 구조대로 매번 아이템마다 필요한 경우에 LIMIT_MAX_NUM까지 루프돌면서 체크하는 부하가 커서 미리 저장 해 둠.
|
||||
char cLimitRealTimeFirstUseIndex; // 아이템 limit 필드값 중에서 LIMIT_REAL_TIME_FIRST_USE 플래그의 위치 (없으면 -1)
|
||||
char cLimitTimerBasedOnWearIndex; // 아이템 limit 필드값 중에서 LIMIT_TIMER_BASED_ON_WEAR 플래그의 위치 (없으면 -1)
|
||||
|
||||
} TItemTable;
|
||||
|
||||
|
@ -659,7 +659,7 @@ typedef struct SPlayerLoadPacket
|
|||
{
|
||||
DWORD account_id;
|
||||
DWORD player_id;
|
||||
BYTE account_index; /* account 에서의 위치 */
|
||||
BYTE account_index; /* account 에서의 위치 */
|
||||
} TPlayerLoadPacket;
|
||||
|
||||
typedef struct SPlayerCreatePacket
|
||||
|
@ -736,9 +736,9 @@ typedef struct SEmpireSelectPacket
|
|||
typedef struct SPacketGDSetup
|
||||
{
|
||||
char szPublicIP[16]; // Public IP which listen to users
|
||||
BYTE bChannel; // 채널
|
||||
WORD wListenPort; // 클라이언트가 접속하는 포트 번호
|
||||
WORD wP2PPort; // 서버끼리 연결 시키는 P2P 포트 번호
|
||||
BYTE bChannel; // 채널
|
||||
WORD wListenPort; // 클라이언트가 접속하는 포트 번호
|
||||
WORD wP2PPort; // 서버끼리 연결 시키는 P2P 포트 번호
|
||||
LONG alMaps[MAP_ALLOW_MAX_LEN];
|
||||
DWORD dwLoginCount;
|
||||
BYTE bAuthServer;
|
||||
|
@ -908,8 +908,8 @@ typedef struct SPacketGuildWar
|
|||
LONG lInitialScore;
|
||||
} TPacketGuildWar;
|
||||
|
||||
// Game -> DB : 상대적 변화값
|
||||
// DB -> Game : 토탈된 최종값
|
||||
// Game -> DB : 상대적 변화값
|
||||
// DB -> Game : 토탈된 최종값
|
||||
typedef struct SPacketGuildWarScore
|
||||
{
|
||||
DWORD dwGuildGainPoint;
|
||||
|
@ -930,8 +930,8 @@ typedef struct SRefineTable
|
|||
//DWORD result_vnum;
|
||||
DWORD id;
|
||||
BYTE material_count;
|
||||
DWORD cost; // 소요 비용
|
||||
DWORD prob; // 확률
|
||||
DWORD cost; // 소요 비용
|
||||
DWORD prob; // 확률
|
||||
TRefineMaterial materials[REFINE_MATERIAL_MAX_NUM];
|
||||
} TRefineTable;
|
||||
|
||||
|
@ -1006,14 +1006,14 @@ typedef struct SPacketGDLoginByKey
|
|||
} TPacketGDLoginByKey;
|
||||
|
||||
/**
|
||||
* @version 05/06/08 Bang2ni - 지속시간 추가
|
||||
* @version 05/06/08 Bang2ni - 지속시간 추가
|
||||
*/
|
||||
typedef struct SPacketGiveGuildPriv
|
||||
{
|
||||
BYTE type;
|
||||
DWORD value;
|
||||
DWORD guild_id;
|
||||
time_t duration_sec; ///< 지속시간
|
||||
time_t duration_sec; ///< 지속시간
|
||||
} TPacketGiveGuildPriv;
|
||||
typedef struct SPacketGiveEmpirePriv
|
||||
{
|
||||
|
@ -1048,7 +1048,7 @@ typedef struct SPacketDGChangeCharacterPriv
|
|||
} TPacketDGChangeCharacterPriv;
|
||||
|
||||
/**
|
||||
* @version 05/06/08 Bang2ni - 지속시간 추가
|
||||
* @version 05/06/08 Bang2ni - 지속시간 추가
|
||||
*/
|
||||
typedef struct SPacketDGChangeGuildPriv
|
||||
{
|
||||
|
@ -1056,7 +1056,7 @@ typedef struct SPacketDGChangeGuildPriv
|
|||
DWORD value;
|
||||
DWORD guild_id;
|
||||
BYTE bLog;
|
||||
time_t end_time_sec; ///< 지속시간
|
||||
time_t end_time_sec; ///< 지속시간
|
||||
} TPacketDGChangeGuildPriv;
|
||||
|
||||
typedef struct SPacketDGChangeEmpirePriv
|
||||
|
@ -1208,27 +1208,27 @@ typedef struct
|
|||
DWORD dwPID2;
|
||||
} TPacketWeddingEnd;
|
||||
|
||||
/// 개인상점 가격정보의 헤더. 가변 패킷으로 이 뒤에 byCount 만큼의 TItemPriceInfo 가 온다.
|
||||
/// 개인상점 가격정보의 헤더. 가변 패킷으로 이 뒤에 byCount 만큼의 TItemPriceInfo 가 온다.
|
||||
typedef struct SPacketMyshopPricelistHeader
|
||||
{
|
||||
DWORD dwOwnerID; ///< 가격정보를 가진 플레이어 ID
|
||||
BYTE byCount; ///< 가격정보 갯수
|
||||
DWORD dwOwnerID; ///< 가격정보를 가진 플레이어 ID
|
||||
BYTE byCount; ///< 가격정보 갯수
|
||||
} TPacketMyshopPricelistHeader;
|
||||
|
||||
/// 개인상점의 단일 아이템에 대한 가격정보
|
||||
/// 개인상점의 단일 아이템에 대한 가격정보
|
||||
typedef struct SItemPriceInfo
|
||||
{
|
||||
DWORD dwVnum; ///< 아이템 vnum
|
||||
DWORD dwPrice; ///< 가격
|
||||
DWORD dwVnum; ///< 아이템 vnum
|
||||
DWORD dwPrice; ///< 가격
|
||||
} TItemPriceInfo;
|
||||
|
||||
/// 개인상점 아이템 가격정보 리스트 테이블
|
||||
/// 개인상점 아이템 가격정보 리스트 테이블
|
||||
typedef struct SItemPriceListTable
|
||||
{
|
||||
DWORD dwOwnerID; ///< 가격정보를 가진 플레이어 ID
|
||||
BYTE byCount; ///< 가격정보 리스트의 갯수
|
||||
DWORD dwOwnerID; ///< 가격정보를 가진 플레이어 ID
|
||||
BYTE byCount; ///< 가격정보 리스트의 갯수
|
||||
|
||||
TItemPriceInfo aPriceInfo[SHOP_PRICELIST_MAX_NUM]; ///< 가격정보 리스트
|
||||
TItemPriceInfo aPriceInfo[SHOP_PRICELIST_MAX_NUM]; ///< 가격정보 리스트
|
||||
} TItemPriceListTable;
|
||||
|
||||
typedef struct
|
||||
|
@ -1240,12 +1240,12 @@ typedef struct
|
|||
//ADMIN_MANAGER
|
||||
typedef struct TAdminInfo
|
||||
{
|
||||
DWORD m_ID; //고유ID
|
||||
char m_szAccount[32]; //계정
|
||||
char m_szName[32]; //캐릭터이름
|
||||
char m_szContactIP[16]; //접근아이피
|
||||
char m_szServerIP[16]; //서버아이피
|
||||
DWORD m_Authority; //권한
|
||||
DWORD m_ID; //고유ID
|
||||
char m_szAccount[32]; //계정
|
||||
char m_szName[32]; //캐릭터이름
|
||||
char m_szContactIP[16]; //접근아이피
|
||||
char m_szServerIP[16]; //서버아이피
|
||||
DWORD m_Authority; //권한
|
||||
} tAdminInfo;
|
||||
//END_ADMIN_MANAGER
|
||||
|
||||
|
@ -1266,20 +1266,20 @@ typedef struct SPacketReloadAdmin
|
|||
|
||||
typedef struct TMonarchInfo
|
||||
{
|
||||
DWORD pid[4]; // 군주의 PID
|
||||
int64_t money[4]; // 군주의 별개 돈
|
||||
char name[4][32]; // 군주의 이름
|
||||
char date[4][32]; // 군주 등록 날짜
|
||||
DWORD pid[4]; // 군주의 PID
|
||||
int64_t money[4]; // 군주의 별개 돈
|
||||
char name[4][32]; // 군주의 이름
|
||||
char date[4][32]; // 군주 등록 날짜
|
||||
} MonarchInfo;
|
||||
|
||||
typedef struct TMonarchElectionInfo
|
||||
{
|
||||
DWORD pid; // 투표 한사람 PID
|
||||
DWORD selectedpid; // 투표 당한 PID ( 군주 참가자 )
|
||||
char date[32]; // 투표 날짜
|
||||
DWORD pid; // 투표 한사람 PID
|
||||
DWORD selectedpid; // 투표 당한 PID ( 군주 참가자 )
|
||||
char date[32]; // 투표 날짜
|
||||
} MonarchElectionInfo;
|
||||
|
||||
// 군주 출마자
|
||||
// 군주 출마자
|
||||
typedef struct tMonarchCandidacy
|
||||
{
|
||||
DWORD pid;
|
||||
|
@ -1331,14 +1331,14 @@ typedef struct tNeedLoginLogInfo
|
|||
DWORD dwPlayerID;
|
||||
} TPacketNeedLoginLogInfo;
|
||||
|
||||
//독일 선물 알림 기능 테스트용 패킷 정보
|
||||
//독일 선물 알림 기능 테스트용 패킷 정보
|
||||
typedef struct tItemAwardInformer
|
||||
{
|
||||
char login[LOGIN_MAX_LEN + 1];
|
||||
char command[20]; //명령어
|
||||
DWORD vnum; //아이템
|
||||
char command[20]; //명령어
|
||||
DWORD vnum; //아이템
|
||||
} TPacketItemAwardInfromer;
|
||||
// 선물 알림 기능 삭제용 패킷 정보
|
||||
// 선물 알림 기능 삭제용 패킷 정보
|
||||
typedef struct tDeleteAwardID
|
||||
{
|
||||
DWORD dwID;
|
||||
|
|
|
@ -135,7 +135,7 @@ void AuctionManager::LoadAuctionItem()
|
|||
}
|
||||
int rows;
|
||||
|
||||
if ((rows = mysql_num_rows(res)) <= 0) // 데이터 없음
|
||||
if ((rows = mysql_num_rows(res)) <= 0) // 데이터 없음
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ void AuctionManager::LoadAuctionInfo()
|
|||
}
|
||||
int rows;
|
||||
|
||||
if ((rows = mysql_num_rows(res)) <= 0) // 데이터 없음
|
||||
if ((rows = mysql_num_rows(res)) <= 0) // 데이터 없음
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ void AuctionManager::LoadSaleInfo()
|
|||
}
|
||||
int rows;
|
||||
|
||||
if ((rows = mysql_num_rows(res)) <= 0) // 데이터 없음
|
||||
if ((rows = mysql_num_rows(res)) <= 0) // 데이터 없음
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -269,7 +269,7 @@ void AuctionManager::LoadWishInfo()
|
|||
}
|
||||
int rows;
|
||||
|
||||
if ((rows = mysql_num_rows(res)) <= 0) // 데이터 없음
|
||||
if ((rows = mysql_num_rows(res)) <= 0) // 데이터 없음
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -311,7 +311,7 @@ void AuctionManager::LoadMyBidInfo ()
|
|||
}
|
||||
int rows;
|
||||
|
||||
if ((rows = mysql_num_rows(res)) <= 0) // 데이터 없음
|
||||
if ((rows = mysql_num_rows(res)) <= 0) // 데이터 없음
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -518,7 +518,7 @@ AuctionResult AuctionManager::Impur(DWORD purchaser_id, const char* purchaser_na
|
|||
return AUCTION_EXPIRED;
|
||||
}
|
||||
|
||||
// 즉구 해버렸으므로, 경매는 끝났다.
|
||||
// 즉구 해버렸으므로, 경매는 끝났다.
|
||||
item_info->expired_time = 0;
|
||||
item_info->bidder_id = purchaser_id;
|
||||
item_info->set_bidder_name (purchaser_name);
|
||||
|
|
|
@ -243,7 +243,7 @@ private:
|
|||
TItemInfoCacheMap item_cache_map;
|
||||
};
|
||||
|
||||
// pc가 입찰에 참여했던 경매를 관리.
|
||||
// pc가 입찰에 참여했던 경매를 관리.
|
||||
class MyBidBoard
|
||||
{
|
||||
public:
|
||||
|
@ -255,7 +255,7 @@ public:
|
|||
|
||||
int GetMoney (DWORD player_id, DWORD item_id);
|
||||
bool Delete (DWORD player_id, DWORD item_id);
|
||||
// 이미 있으면 덮어 씌운다.
|
||||
// 이미 있으면 덮어 씌운다.
|
||||
void Insert (DWORD player_id, DWORD item_id, int money);
|
||||
|
||||
private:
|
||||
|
@ -267,11 +267,11 @@ private:
|
|||
class AuctionManager : public singleton <AuctionManager>
|
||||
{
|
||||
private:
|
||||
// auction에 등록된 아이템들.
|
||||
// auction에 등록된 아이템들.
|
||||
typedef std::unordered_map<DWORD, CItemCache *> TItemCacheMap;
|
||||
TItemCacheMap auction_item_cache_map;
|
||||
|
||||
// auction에 등록된 정보 중 가격, 등등 아이템 테이블에 포함되지 않는 정보들을 관리하는 것들
|
||||
// auction에 등록된 정보 중 가격, 등등 아이템 테이블에 포함되지 않는 정보들을 관리하는 것들
|
||||
AuctionBoard Auction;
|
||||
SaleBoard Sale;
|
||||
WishBoard Wish;
|
||||
|
|
|
@ -29,12 +29,12 @@ CItemCache::~CItemCache()
|
|||
{
|
||||
}
|
||||
|
||||
// 이거 이상한데...
|
||||
// Delete를 했으면, Cache도 해제해야 하는것 아닌가???
|
||||
// 근데 Cache를 해제하는 부분이 없어.
|
||||
// 못 찾은 건가?
|
||||
// 이렇게 해놓으면, 계속 시간이 될 때마다 아이템을 계속 지워...
|
||||
// 이미 사라진 아이템인데... 확인사살??????
|
||||
// 이거 이상한데...
|
||||
// Delete를 했으면, Cache도 해제해야 하는것 아닌가???
|
||||
// 근데 Cache를 해제하는 부분이 없어.
|
||||
// 못 찾은 건가?
|
||||
// 이렇게 해놓으면, 계속 시간이 될 때마다 아이템을 계속 지워...
|
||||
// 이미 사라진 아이템인데... 확인사살??????
|
||||
// fixme
|
||||
// by rtsummit
|
||||
void CItemCache::Delete()
|
||||
|
@ -52,12 +52,12 @@ void CItemCache::Delete()
|
|||
OnFlush();
|
||||
|
||||
//m_bNeedQuery = false;
|
||||
//m_lastUpdateTime = time(0) - m_expireTime; // 바로 타임아웃 되도록 하자.
|
||||
//m_lastUpdateTime = time(0) - m_expireTime; // 바로 타임아웃 되도록 하자.
|
||||
}
|
||||
|
||||
void CItemCache::OnFlush()
|
||||
{
|
||||
if (m_data.vnum == 0) // vnum이 0이면 삭제하라고 표시된 것이다.
|
||||
if (m_data.vnum == 0) // vnum이 0이면 삭제하라고 표시된 것이다.
|
||||
{
|
||||
char szQuery[QUERY_MAX_LEN];
|
||||
snprintf(szQuery, sizeof(szQuery), "DELETE FROM item%s WHERE id=%u", GetTablePostfix(), m_data.id);
|
||||
|
@ -186,7 +186,7 @@ CItemPriceListTableCache::CItemPriceListTableCache()
|
|||
void CItemPriceListTableCache::UpdateList(const TItemPriceListTable* pUpdateList)
|
||||
{
|
||||
//
|
||||
// 이미 캐싱된 아이템과 중복된 아이템을 찾고 중복되지 않는 이전 정보는 tmpvec 에 넣는다.
|
||||
// 이미 캐싱된 아이템과 중복된 아이템을 찾고 중복되지 않는 이전 정보는 tmpvec 에 넣는다.
|
||||
//
|
||||
|
||||
std::vector<TItemPriceInfo> tmpvec;
|
||||
|
@ -202,7 +202,7 @@ void CItemPriceListTableCache::UpdateList(const TItemPriceListTable* pUpdateList
|
|||
}
|
||||
|
||||
//
|
||||
// pUpdateList 를 m_data 에 복사하고 남은 공간을 tmpvec 의 앞에서 부터 남은 만큼 복사한다.
|
||||
// pUpdateList 를 m_data 에 복사하고 남은 공간을 tmpvec 의 앞에서 부터 남은 만큼 복사한다.
|
||||
//
|
||||
|
||||
if (pUpdateList->byCount > SHOP_PRICELIST_MAX_NUM)
|
||||
|
@ -215,7 +215,7 @@ void CItemPriceListTableCache::UpdateList(const TItemPriceListTable* pUpdateList
|
|||
|
||||
memcpy(m_data.aPriceInfo, pUpdateList->aPriceInfo, sizeof(TItemPriceInfo) * pUpdateList->byCount);
|
||||
|
||||
int nDeletedNum; // 삭제된 가격정보의 갯수
|
||||
int nDeletedNum; // 삭제된 가격정보의 갯수
|
||||
|
||||
if (pUpdateList->byCount < SHOP_PRICELIST_MAX_NUM)
|
||||
{
|
||||
|
@ -244,14 +244,14 @@ void CItemPriceListTableCache::OnFlush()
|
|||
char szQuery[QUERY_MAX_LEN];
|
||||
|
||||
//
|
||||
// 이 캐시의 소유자에 대한 기존에 DB 에 저장된 아이템 가격정보를 모두 삭제한다.
|
||||
// 이 캐시의 소유자에 대한 기존에 DB 에 저장된 아이템 가격정보를 모두 삭제한다.
|
||||
//
|
||||
|
||||
snprintf(szQuery, sizeof(szQuery), "DELETE FROM myshop_pricelist%s WHERE owner_id = %u", GetTablePostfix(), m_data.dwOwnerID);
|
||||
CDBManager::instance().ReturnQuery(szQuery, QID_ITEMPRICE_DESTROY, 0, NULL);
|
||||
|
||||
//
|
||||
// 캐시의 내용을 모두 DB 에 쓴다.
|
||||
// 캐시의 내용을 모두 DB 에 쓴다.
|
||||
//
|
||||
|
||||
for (int idx = 0; idx < m_data.byCount; ++idx)
|
||||
|
|
|
@ -29,7 +29,7 @@ class CPlayerTableCache : public cache<TPlayerTable>
|
|||
// MYSHOP_PRICE_LIST
|
||||
/**
|
||||
* @class CItemPriceListTableCache
|
||||
* @brief 개인상점의 아이템 가격정보 리스트에 대한 캐시 class
|
||||
* @brief 개인상점의 아이템 가격정보 리스트에 대한 캐시 class
|
||||
* @version 05/06/10 Bang2ni - First release.
|
||||
*/
|
||||
class CItemPriceListTableCache : public cache< TItemPriceListTable >
|
||||
|
@ -38,20 +38,20 @@ class CItemPriceListTableCache : public cache< TItemPriceListTable >
|
|||
|
||||
/// Constructor
|
||||
/**
|
||||
* 캐시 만료 시간을 설정한다.
|
||||
* 캐시 만료 시간을 설정한다.
|
||||
*/
|
||||
CItemPriceListTableCache(void);
|
||||
|
||||
/// 리스트 갱신
|
||||
/// 리스트 갱신
|
||||
/**
|
||||
* @param [in] pUpdateList 갱신할 리스트
|
||||
* @param [in] pUpdateList 갱신할 리스트
|
||||
*
|
||||
* 캐시된 가격정보를 갱신한다.
|
||||
* 가격정보 리스트가 가득 찼을 경우 기존에 캐싱된 정보들을 뒤에서 부터 삭제한다.
|
||||
* 캐시된 가격정보를 갱신한다.
|
||||
* 가격정보 리스트가 가득 찼을 경우 기존에 캐싱된 정보들을 뒤에서 부터 삭제한다.
|
||||
*/
|
||||
void UpdateList(const TItemPriceListTable* pUpdateList);
|
||||
|
||||
/// 가격정보를 DB 에 기록한다.
|
||||
/// 가격정보를 DB 에 기록한다.
|
||||
virtual void OnFlush(void);
|
||||
|
||||
private:
|
||||
|
|
|
@ -246,7 +246,7 @@ bool CClientManager::Initialize()
|
|||
|
||||
LoadEventFlag();
|
||||
|
||||
// database character-set을 강제로 맞춤
|
||||
// database character-set을 강제로 맞춤
|
||||
if (g_stLocale == "big5" || g_stLocale == "sjis")
|
||||
CDBManager::instance().QueryLocaleSet();
|
||||
|
||||
|
@ -259,7 +259,7 @@ void CClientManager::MainLoop()
|
|||
|
||||
SPDLOG_DEBUG("ClientManager pointer is {}", (void*) this);
|
||||
|
||||
// 메인루프
|
||||
// 메인루프
|
||||
while (!m_bShutdowned)
|
||||
{
|
||||
while ((tmp = CDBManager::instance().PopResult()))
|
||||
|
@ -273,7 +273,7 @@ void CClientManager::MainLoop()
|
|||
}
|
||||
|
||||
//
|
||||
// 메인루프 종료처리
|
||||
// 메인루프 종료처리
|
||||
//
|
||||
SPDLOG_DEBUG("MainLoop exited, Starting cache flushing");
|
||||
|
||||
|
@ -281,7 +281,7 @@ void CClientManager::MainLoop()
|
|||
|
||||
itertype(m_map_playerCache) it = m_map_playerCache.begin();
|
||||
|
||||
//플레이어 테이블 캐쉬 플러쉬
|
||||
//플레이어 테이블 캐쉬 플러쉬
|
||||
while (it != m_map_playerCache.end())
|
||||
{
|
||||
CPlayerTableCache * c = (it++)->second;
|
||||
|
@ -293,7 +293,7 @@ void CClientManager::MainLoop()
|
|||
|
||||
|
||||
itertype(m_map_itemCache) it2 = m_map_itemCache.begin();
|
||||
//아이템 플러쉬
|
||||
//아이템 플러쉬
|
||||
while (it2 != m_map_itemCache.end())
|
||||
{
|
||||
CItemCache * c = (it2++)->second;
|
||||
|
@ -305,7 +305,7 @@ void CClientManager::MainLoop()
|
|||
|
||||
// MYSHOP_PRICE_LIST
|
||||
//
|
||||
// 개인상점 아이템 가격 리스트 Flush
|
||||
// 개인상점 아이템 가격 리스트 Flush
|
||||
//
|
||||
for (itertype(m_mapItemPriceListCache) itPriceList = m_mapItemPriceListCache.begin(); itPriceList != m_mapItemPriceListCache.end(); ++itPriceList)
|
||||
{
|
||||
|
@ -325,7 +325,7 @@ void CClientManager::Quit()
|
|||
|
||||
void CClientManager::QUERY_BOOT(CPeer* peer, TPacketGDBoot * p)
|
||||
{
|
||||
const BYTE bPacketVersion = 6; // BOOT 패킷이 바뀔때마다 번호를 올리도록 한다.
|
||||
const BYTE bPacketVersion = 6; // BOOT 패킷이 바뀔때마다 번호를 올리도록 한다.
|
||||
|
||||
std::vector<tAdminInfo> vAdmin;
|
||||
std::vector<std::string> vHost;
|
||||
|
@ -582,9 +582,9 @@ void CClientManager::RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg)
|
|||
ClientHandleInfo * pi = (ClientHandleInfo *) qi->pvData;
|
||||
DWORD dwHandle = pi->dwHandle;
|
||||
|
||||
// 여기에서 사용하는 account_index는 쿼리 순서를 말한다.
|
||||
// 첫번째 패스워드 알아내기 위해 하는 쿼리가 0
|
||||
// 두번째 실제 데이터를 얻어놓는 쿼리가 1
|
||||
// 여기에서 사용하는 account_index는 쿼리 순서를 말한다.
|
||||
// 첫번째 패스워드 알아내기 위해 하는 쿼리가 0
|
||||
// 두번째 실제 데이터를 얻어놓는 쿼리가 1
|
||||
|
||||
if (pi->account_index == 0)
|
||||
{
|
||||
|
@ -609,7 +609,7 @@ void CClientManager::RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg)
|
|||
{
|
||||
MYSQL_ROW row = mysql_fetch_row(res->pSQLResult);
|
||||
|
||||
// 비밀번호가 틀리면..
|
||||
// 비밀번호가 틀리면..
|
||||
if (((!row[2] || !*row[2]) && strcmp("000000", szSafeboxPassword)) ||
|
||||
((row[2] && *row[2]) && strcmp(row[2], szSafeboxPassword)))
|
||||
{
|
||||
|
@ -675,8 +675,8 @@ void CClientManager::RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg)
|
|||
}
|
||||
|
||||
|
||||
// 쿼리에 에러가 있었으므로 응답할 경우 창고가 비어있는 것 처럼
|
||||
// 보이기 때문에 창고가 아얘 안열리는게 나음
|
||||
// 쿼리에 에러가 있었으므로 응답할 경우 창고가 비어있는 것 처럼
|
||||
// 보이기 때문에 창고가 아얘 안열리는게 나음
|
||||
if (!msg->Get()->pSQLResult)
|
||||
{
|
||||
SPDLOG_ERROR("null safebox result");
|
||||
|
@ -785,8 +785,8 @@ void CClientManager::RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg)
|
|||
{
|
||||
case 72723: case 72724: case 72725: case 72726:
|
||||
case 72727: case 72728: case 72729: case 72730:
|
||||
// 무시무시하지만 이전에 하던 걸 고치기는 무섭고...
|
||||
// 그래서 그냥 하드 코딩. 선물 상자용 자동물약 아이템들.
|
||||
// 무시무시하지만 이전에 하던 걸 고치기는 무섭고...
|
||||
// 그래서 그냥 하드 코딩. 선물 상자용 자동물약 아이템들.
|
||||
case 76004: case 76005: case 76021: case 76022:
|
||||
case 79012: case 79013:
|
||||
if (pItemAward->dwSocket2 == 0)
|
||||
|
@ -898,7 +898,7 @@ void CClientManager::RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg)
|
|||
void CClientManager::QUERY_SAFEBOX_CHANGE_SIZE(CPeer * pkPeer, DWORD dwHandle, TSafeboxChangeSizePacket * p)
|
||||
{
|
||||
ClientHandleInfo * pi = new ClientHandleInfo(dwHandle);
|
||||
pi->account_index = p->bSize; // account_index를 사이즈로 임시로 사용
|
||||
pi->account_index = p->bSize; // account_index를 사이즈로 임시로 사용
|
||||
|
||||
char szQuery[QUERY_MAX_LEN];
|
||||
|
||||
|
@ -986,7 +986,7 @@ void CClientManager::RESULT_PRICELIST_LOAD(CPeer* peer, SQLMsg* pMsg)
|
|||
TItemPricelistReqInfo* pReqInfo = (TItemPricelistReqInfo*)static_cast<CQueryInfo*>(pMsg->pvUserData)->pvData;
|
||||
|
||||
//
|
||||
// DB 에서 로드한 정보를 Cache 에 저장
|
||||
// DB 에서 로드한 정보를 Cache 에 저장
|
||||
//
|
||||
|
||||
TItemPriceListTable table;
|
||||
|
@ -1005,7 +1005,7 @@ void CClientManager::RESULT_PRICELIST_LOAD(CPeer* peer, SQLMsg* pMsg)
|
|||
PutItemPriceListCache(&table);
|
||||
|
||||
//
|
||||
// 로드한 데이터를 Game server 에 전송
|
||||
// 로드한 데이터를 Game server 에 전송
|
||||
//
|
||||
|
||||
TPacketMyshopPricelistHeader header;
|
||||
|
@ -1029,7 +1029,7 @@ void CClientManager::RESULT_PRICELIST_LOAD_FOR_UPDATE(SQLMsg* pMsg)
|
|||
TItemPriceListTable* pUpdateTable = (TItemPriceListTable*)static_cast<CQueryInfo*>(pMsg->pvUserData)->pvData;
|
||||
|
||||
//
|
||||
// DB 에서 로드한 정보를 Cache 에 저장
|
||||
// DB 에서 로드한 정보를 Cache 에 저장
|
||||
//
|
||||
|
||||
TItemPriceListTable table;
|
||||
|
@ -1091,18 +1091,18 @@ void CClientManager::QUERY_EMPIRE_SELECT(CPeer * pkPeer, DWORD dwHandle, TEmpire
|
|||
UINT g_start_map[4] =
|
||||
{
|
||||
0, // reserved
|
||||
1, // 신수국
|
||||
21, // 천조국
|
||||
41 // 진노국
|
||||
1, // 신수국
|
||||
21, // 천조국
|
||||
41 // 진노국
|
||||
};
|
||||
|
||||
// FIXME share with game
|
||||
DWORD g_start_position[4][2]=
|
||||
{
|
||||
{ 0, 0 },
|
||||
{ 469300, 964200 }, // 신수국
|
||||
{ 55700, 157900 }, // 천조국
|
||||
{ 969600, 278400 } // 진노국
|
||||
{ 469300, 964200 }, // 신수국
|
||||
{ 55700, 157900 }, // 천조국
|
||||
{ 969600, 278400 } // 진노국
|
||||
};
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
|
@ -1152,7 +1152,7 @@ void CClientManager::QUERY_SETUP(CPeer * peer, DWORD dwHandle, const char * c_pD
|
|||
peer->SetMaps(p->alMaps);
|
||||
|
||||
//
|
||||
// 어떤 맵이 어떤 서버에 있는지 보내기
|
||||
// 어떤 맵이 어떤 서버에 있는지 보내기
|
||||
//
|
||||
TMapLocation kMapLocations;
|
||||
|
||||
|
@ -1259,7 +1259,7 @@ void CClientManager::QUERY_SETUP(CPeer * peer, DWORD dwHandle, const char * c_pD
|
|||
peer->Encode(&vec_kMapLocations[0], sizeof(TMapLocation) * vec_kMapLocations.size());
|
||||
|
||||
//
|
||||
// 셋업 : 접속한 피어에 다른 피어들이 접속하게 만든다. (P2P 컨넥션 생성)
|
||||
// 셋업 : 접속한 피어에 다른 피어들이 접속하게 만든다. (P2P 컨넥션 생성)
|
||||
//
|
||||
SPDLOG_DEBUG("SETUP: channel {} listen {} p2p {} count {}", peer->GetChannel(), p->wListenPort, p->wP2PPort, bMapCount);
|
||||
|
||||
|
@ -1275,7 +1275,7 @@ void CClientManager::QUERY_SETUP(CPeer * peer, DWORD dwHandle, const char * c_pD
|
|||
if (tmp == peer)
|
||||
continue;
|
||||
|
||||
// 채널이 0이라면 아직 SETUP 패킷이 오지 않은 피어 또는 auth라고 간주할 수 있음
|
||||
// 채널이 0이라면 아직 SETUP 패킷이 오지 않은 피어 또는 auth라고 간주할 수 있음
|
||||
if (0 == tmp->GetChannel())
|
||||
continue;
|
||||
|
||||
|
@ -1337,8 +1337,8 @@ void CClientManager::QUERY_ITEM_SAVE(CPeer * pkPeer, const char * c_pData)
|
|||
{
|
||||
TPlayerItem * p = (TPlayerItem *) c_pData;
|
||||
|
||||
// 창고면 캐쉬하지 않고, 캐쉬에 있던 것도 빼버려야 한다.
|
||||
// auction은 이 루트를 타지 않아야 한다. EnrollInAuction을 타야한다.
|
||||
// 창고면 캐쉬하지 않고, 캐쉬에 있던 것도 빼버려야 한다.
|
||||
// auction은 이 루트를 타지 않아야 한다. EnrollInAuction을 타야한다.
|
||||
|
||||
if (p->window == SAFEBOX || p->window == MALL)
|
||||
{
|
||||
|
@ -1473,7 +1473,7 @@ void CClientManager::PutItemCache(TPlayerItem * pNew, bool bSkipQuery)
|
|||
|
||||
c = GetItemCache(pNew->id);
|
||||
|
||||
// 아이템 새로 생성
|
||||
// 아이템 새로 생성
|
||||
if (!c)
|
||||
{
|
||||
SPDLOG_TRACE("ITEM_CACHE: PutItemCache ==> New CItemCache id{} vnum{} new owner{}", pNew->id, pNew->vnum, pNew->owner);
|
||||
|
@ -1481,15 +1481,15 @@ void CClientManager::PutItemCache(TPlayerItem * pNew, bool bSkipQuery)
|
|||
c = new CItemCache;
|
||||
m_map_itemCache.insert(TItemCacheMap::value_type(pNew->id, c));
|
||||
}
|
||||
// 있을시
|
||||
// 있을시
|
||||
else
|
||||
{
|
||||
SPDLOG_TRACE("ITEM_CACHE: PutItemCache ==> Have Cache");
|
||||
|
||||
// 소유자가 틀리면
|
||||
// 소유자가 틀리면
|
||||
if (pNew->owner != c->Get()->owner)
|
||||
{
|
||||
// 이미 이 아이템을 가지고 있었던 유저로 부터 아이템을 삭제한다.
|
||||
// 이미 이 아이템을 가지고 있었던 유저로 부터 아이템을 삭제한다.
|
||||
TItemCacheSetPtrMap::iterator it = m_map_pkItemCacheSetPtr.find(c->Get()->owner);
|
||||
|
||||
if (it != m_map_pkItemCacheSetPtr.end())
|
||||
|
@ -1500,7 +1500,7 @@ void CClientManager::PutItemCache(TPlayerItem * pNew, bool bSkipQuery)
|
|||
}
|
||||
}
|
||||
|
||||
// 새로운 정보 업데이트
|
||||
// 새로운 정보 업데이트
|
||||
c->Put(pNew, bSkipQuery);
|
||||
|
||||
TItemCacheSetPtrMap::iterator it = m_map_pkItemCacheSetPtr.find(c->Get()->owner);
|
||||
|
@ -1512,8 +1512,8 @@ void CClientManager::PutItemCache(TPlayerItem * pNew, bool bSkipQuery)
|
|||
}
|
||||
else
|
||||
{
|
||||
// 현재 소유자가 없으므로 바로 저장해야 다음 접속이 올 때 SQL에 쿼리하여
|
||||
// 받을 수 있으므로 바로 저장한다.
|
||||
// 현재 소유자가 없으므로 바로 저장해야 다음 접속이 올 때 SQL에 쿼리하여
|
||||
// 받을 수 있으므로 바로 저장한다.
|
||||
SPDLOG_TRACE("ITEM_CACHE: direct save {} id {}", c->Get()->owner, c->Get()->id);
|
||||
|
||||
c->OnFlush();
|
||||
|
@ -1569,7 +1569,7 @@ void CClientManager::UpdatePlayerCache()
|
|||
|
||||
c->Flush();
|
||||
|
||||
// Item Cache도 업데이트
|
||||
// Item Cache도 업데이트
|
||||
UpdateItemCacheSet(c->Get()->id);
|
||||
}
|
||||
else if (c->CheckFlushTimeout())
|
||||
|
@ -1595,7 +1595,7 @@ void CClientManager::UpdateItemCache()
|
|||
{
|
||||
CItemCache * c = (it++)->second;
|
||||
|
||||
// 아이템은 Flush만 한다.
|
||||
// 아이템은 Flush만 한다.
|
||||
if (c->CheckFlushTimeout())
|
||||
{
|
||||
SPDLOG_TRACE("UpdateItemCache ==> Flush() vnum {} id owner {}", c->Get()->vnum, c->Get()->id, c->Get()->owner);
|
||||
|
@ -1640,7 +1640,7 @@ void CClientManager::QUERY_ITEM_DESTROY(CPeer * pkPeer, const char * c_pData)
|
|||
|
||||
SPDLOG_TRACE("HEADER_GD_ITEM_DESTROY: PID {} ID {}", dwPID, dwID);
|
||||
|
||||
if (dwPID == 0) // 아무도 가진 사람이 없었다면, 비동기 쿼리
|
||||
if (dwPID == 0) // 아무도 가진 사람이 없었다면, 비동기 쿼리
|
||||
CDBManager::instance().AsyncQuery(szQuery);
|
||||
else
|
||||
CDBManager::instance().ReturnQuery(szQuery, QID_ITEM_DESTROY, pkPeer->GetHandle(), NULL);
|
||||
|
@ -1702,7 +1702,7 @@ void CClientManager::QUERY_RELOAD_PROTO()
|
|||
|
||||
// ADD_GUILD_PRIV_TIME
|
||||
/**
|
||||
* @version 05/06/08 Bang2ni - 지속시간 추가
|
||||
* @version 05/06/08 Bang2ni - 지속시간 추가
|
||||
*/
|
||||
void CClientManager::AddGuildPriv(TPacketGiveGuildPriv* p)
|
||||
{
|
||||
|
@ -2010,8 +2010,8 @@ void CClientManager::WeddingEnd(TPacketWeddingEnd * p)
|
|||
}
|
||||
|
||||
//
|
||||
// 캐시에 가격정보가 있으면 캐시를 업데이트 하고 캐시에 가격정보가 없다면
|
||||
// 우선 기존의 데이터를 로드한 뒤에 기존의 정보로 캐시를 만들고 새로 받은 가격정보를 업데이트 한다.
|
||||
// 캐시에 가격정보가 있으면 캐시를 업데이트 하고 캐시에 가격정보가 없다면
|
||||
// 우선 기존의 데이터를 로드한 뒤에 기존의 정보로 캐시를 만들고 새로 받은 가격정보를 업데이트 한다.
|
||||
//
|
||||
void CClientManager::MyshopPricelistUpdate(const TPacketMyshopPricelistHeader* pPacket)
|
||||
{
|
||||
|
@ -2052,7 +2052,7 @@ void CClientManager::MyshopPricelistUpdate(const TPacketMyshopPricelistHeader* p
|
|||
}
|
||||
|
||||
// MYSHOP_PRICE_LIST
|
||||
// 캐시된 가격정보가 있으면 캐시를 읽어 바로 전송하고 캐시에 정보가 없으면 DB 에 쿼리를 한다.
|
||||
// 캐시된 가격정보가 있으면 캐시를 읽어 바로 전송하고 캐시에 정보가 없으면 DB 에 쿼리를 한다.
|
||||
//
|
||||
void CClientManager::MyshopPricelistRequest(CPeer* peer, DWORD dwHandle, DWORD dwPlayerID)
|
||||
{
|
||||
|
@ -2425,15 +2425,15 @@ void CClientManager::ProcessPackets(CPeer * peer)
|
|||
ComeToVote(peer, dwHandle, data);
|
||||
break;
|
||||
|
||||
case HEADER_GD_RMCANDIDACY: //< 후보 제거 (운영자)
|
||||
case HEADER_GD_RMCANDIDACY: //< 후보 제거 (운영자)
|
||||
RMCandidacy(peer, dwHandle, data);
|
||||
break;
|
||||
|
||||
case HEADER_GD_SETMONARCH: ///<군주설정 (운영자)
|
||||
case HEADER_GD_SETMONARCH: ///<군주설정 (운영자)
|
||||
SetMonarch(peer, dwHandle, data);
|
||||
break;
|
||||
|
||||
case HEADER_GD_RMMONARCH: ///<군주삭제
|
||||
case HEADER_GD_RMMONARCH: ///<군주삭제
|
||||
RMMonarch(peer, dwHandle, data);
|
||||
break;
|
||||
//END_MONARCH
|
||||
|
@ -2622,9 +2622,9 @@ CPeer * CClientManager::GetAnyPeer()
|
|||
return m_peerList.front();
|
||||
}
|
||||
|
||||
// DB 매니저로 부터 받은 결과를 처리한다.
|
||||
// DB 매니저로 부터 받은 결과를 처리한다.
|
||||
//
|
||||
// @version 05/06/10 Bang2ni - 가격정보 관련 쿼리(QID_ITEMPRICE_XXX) 추가
|
||||
// @version 05/06/10 Bang2ni - 가격정보 관련 쿼리(QID_ITEMPRICE_XXX) 추가
|
||||
int CClientManager::AnalyzeQueryResult(SQLMsg * msg)
|
||||
{
|
||||
CQueryInfo * qi = (CQueryInfo *) msg->pvUserData;
|
||||
|
@ -2737,7 +2737,7 @@ void UsageLog()
|
|||
char *time_s;
|
||||
struct tm lt;
|
||||
|
||||
int avg = g_dwUsageAvg / 3600; // 60 초 * 60 분
|
||||
int avg = g_dwUsageAvg / 3600; // 60 초 * 60 분
|
||||
|
||||
fp = fopen("usage.txt", "a+");
|
||||
|
||||
|
@ -2770,7 +2770,7 @@ int CClientManager::Process()
|
|||
++thecore_heart->pulse;
|
||||
|
||||
/*
|
||||
//30분마다 변경
|
||||
//30분마다 변경
|
||||
if (((thecore_pulse() % (60 * 30 * 10)) == 0))
|
||||
{
|
||||
g_iPlayerCacheFlushSeconds = std::max(60, rand() % 180);
|
||||
|
@ -2848,11 +2848,11 @@ int CClientManager::Process()
|
|||
m_iCacheFlushCount = 0;
|
||||
|
||||
|
||||
//플레이어 플러쉬
|
||||
//플레이어 플러쉬
|
||||
UpdatePlayerCache();
|
||||
//아이템 플러쉬
|
||||
//아이템 플러쉬
|
||||
UpdateItemCache();
|
||||
//로그아웃시 처리- 캐쉬셋 플러쉬
|
||||
//로그아웃시 처리- 캐쉬셋 플러쉬
|
||||
UpdateLogoutPlayer();
|
||||
|
||||
// MYSHOP_PRICE_LIST
|
||||
|
@ -2922,13 +2922,13 @@ int CClientManager::Process()
|
|||
/////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
if (!(thecore_heart->pulse % (thecore_heart->passes_per_sec * 60))) // 60초에 한번
|
||||
if (!(thecore_heart->pulse % (thecore_heart->passes_per_sec * 60))) // 60초에 한번
|
||||
{
|
||||
// 유니크 아이템을 위한 시간을 보낸다.
|
||||
// 유니크 아이템을 위한 시간을 보낸다.
|
||||
CClientManager::instance().SendTime();
|
||||
}
|
||||
|
||||
if (!(thecore_heart->pulse % (thecore_heart->passes_per_sec * 3600))) // 한시간에 한번
|
||||
if (!(thecore_heart->pulse % (thecore_heart->passes_per_sec * 3600))) // 한시간에 한번
|
||||
{
|
||||
CMoneyLog::instance().Save();
|
||||
}
|
||||
|
@ -2942,7 +2942,7 @@ int CClientManager::Process()
|
|||
|
||||
DWORD CClientManager::GetUserCount()
|
||||
{
|
||||
// 단순히 로그인 카운트를 센다.. --;
|
||||
// 단순히 로그인 카운트를 센다.. --;
|
||||
return m_map_kLogonAccount.size();
|
||||
}
|
||||
|
||||
|
@ -3002,7 +3002,7 @@ bool CClientManager::InitializeNowItemID()
|
|||
{
|
||||
DWORD dwMin, dwMax;
|
||||
|
||||
//아이템 ID를 초기화 한다.
|
||||
//아이템 ID를 초기화 한다.
|
||||
if (!CConfig::instance().GetTwoValue("ITEM_ID_RANGE", &dwMin, &dwMax))
|
||||
{
|
||||
SPDLOG_ERROR("conf.txt: Cannot find ITEM_ID_RANGE [start_item_id] [end_item_id]");
|
||||
|
@ -3432,7 +3432,7 @@ bool CClientManager::InitializeLocalization()
|
|||
|
||||
bool CClientManager::__GetAdminInfo(const char *szIP, std::vector<tAdminInfo> & rAdminVec)
|
||||
{
|
||||
//szIP == NULL 일경우 모든서버에 운영자 권한을 갖는다.
|
||||
//szIP == NULL 일경우 모든서버에 운영자 권한을 갖는다.
|
||||
char szQuery[512];
|
||||
snprintf(szQuery, sizeof(szQuery),
|
||||
"SELECT mID,mAccount,mName,mContactIP,mServerIP,mAuthority FROM gmlist WHERE mServerIP='ALL' or mServerIP='%s'",
|
||||
|
@ -3948,7 +3948,7 @@ void CClientManager::SendSpareItemIDRange(CPeer* peer)
|
|||
}
|
||||
|
||||
//
|
||||
// Login Key만 맵에서 지운다.
|
||||
// Login Key만 맵에서 지운다.
|
||||
//
|
||||
void CClientManager::DeleteLoginKey(TPacketDC *data)
|
||||
{
|
||||
|
@ -4061,7 +4061,7 @@ void CClientManager::EnrollInAuction (CPeer * peer, DWORD owner_id, AuctionEnrol
|
|||
SPDLOG_ERROR("Player id {} doesn't have item {}.", owner_id, data->get_item_id());
|
||||
return;
|
||||
}
|
||||
// 현재 시각 + 24시간 후.
|
||||
// 현재 시각 + 24시간 후.
|
||||
time_t expired_time = time(0) + 24 * 60 * 60;
|
||||
TAuctionItemInfo auctioned_item_info (item->vnum, data->get_bid_price(),
|
||||
data->get_impur_price(), owner_id, "", expired_time, data->get_item_id(), 0, data->get_empire());
|
||||
|
@ -4080,7 +4080,7 @@ void CClientManager::EnrollInAuction (CPeer * peer, DWORD owner_id, AuctionEnrol
|
|||
}
|
||||
else
|
||||
{
|
||||
// 아이템 케시를 Auction에 등록 했으니 ClientManager에서는 뺀다.
|
||||
// 아이템 케시를 Auction에 등록 했으니 ClientManager에서는 뺀다.
|
||||
TItemCacheSetPtrMap::iterator it = m_map_pkItemCacheSetPtr.find(item->owner);
|
||||
|
||||
if (it != m_map_pkItemCacheSetPtr.end())
|
||||
|
@ -4133,7 +4133,7 @@ void CClientManager::EnrollInSale (CPeer * peer, DWORD owner_id, AuctionEnrollSa
|
|||
SPDLOG_ERROR("Player id {} doesn't have item {}.", owner_id, data->get_item_id());
|
||||
return;
|
||||
}
|
||||
// 현재 시각 + 24시간 후.
|
||||
// 현재 시각 + 24시간 후.
|
||||
time_t expired_time = time(0) + 24 * 60 * 60;
|
||||
TSaleItemInfo sold_item_info (item->vnum, data->get_sale_price(),
|
||||
owner_id, player->name, data->get_item_id(), data->get_wisher_id());
|
||||
|
@ -4152,7 +4152,7 @@ void CClientManager::EnrollInSale (CPeer * peer, DWORD owner_id, AuctionEnrollSa
|
|||
}
|
||||
else
|
||||
{
|
||||
// 아이템 케시를 Auction에 등록 했으니 ClientManager에서는 뺀다.
|
||||
// 아이템 케시를 Auction에 등록 했으니 ClientManager에서는 뺀다.
|
||||
TItemCacheSetPtrMap::iterator it = m_map_pkItemCacheSetPtr.find(item->owner);
|
||||
|
||||
if (it != m_map_pkItemCacheSetPtr.end())
|
||||
|
@ -4192,7 +4192,7 @@ void CClientManager::EnrollInWish (CPeer * peer, DWORD wisher_id, AuctionEnrollW
|
|||
CPlayerTableCache* player_cache = it->second;
|
||||
TPlayerTable* player = player_cache->Get(false);
|
||||
|
||||
// 현재 시각 + 24시간 후.
|
||||
// 현재 시각 + 24시간 후.
|
||||
time_t expired_time = time(0) + 24 * 60 * 60;
|
||||
TWishItemInfo wished_item_info (data->get_item_num(), data->get_wish_price(), wisher_id, player->name, expired_time, data->get_empire());
|
||||
|
||||
|
@ -4559,11 +4559,11 @@ void CClientManager::AuctionDeleteSaleItem (CPeer * peer, DWORD actor_id, DWORD
|
|||
AuctionManager::instance().DeleteSaleItem (actor_id, item_id);
|
||||
}
|
||||
|
||||
// ReBid는 이전 입찰금액에 더해서 입찰한다.
|
||||
// ReBid에선 data->bid_price가 이전 입찰가에 더해져서
|
||||
// 그 금액으로 rebid하는 것.
|
||||
// 이렇게 한 이유는 rebid에 실패 했을 때,
|
||||
// 유저의 호주머니에서 뺀 돈을 돌려주기 편하게 하기 위함이다.
|
||||
// ReBid는 이전 입찰금액에 더해서 입찰한다.
|
||||
// ReBid에선 data->bid_price가 이전 입찰가에 더해져서
|
||||
// 그 금액으로 rebid하는 것.
|
||||
// 이렇게 한 이유는 rebid에 실패 했을 때,
|
||||
// 유저의 호주머니에서 뺀 돈을 돌려주기 편하게 하기 위함이다.
|
||||
|
||||
void CClientManager::AuctionReBid (CPeer * peer, DWORD bidder_id, AuctionBidInfo* data)
|
||||
{
|
||||
|
@ -4588,14 +4588,14 @@ void CClientManager::AuctionReBid (CPeer * peer, DWORD bidder_id, AuctionBidInfo
|
|||
{
|
||||
SPDLOG_DEBUG("ReBid Success. bidder_id item_id {} {}", bidder_id, data->get_item_id());
|
||||
}
|
||||
// 이건 FAIL이 떠서는 안돼.
|
||||
// FAIL이 뜰 수가 없는게, MyBid에 있는 bidder_id에 대한 컨텐츠는 bidder_id만이 접근 할 수 있거든?
|
||||
// 그러므로 다른 것이 다 정상적으로 작동한다고 가정 한다면
|
||||
// 한 게임 서버 내에서 bidder_id로 MyBid를 수정한다 할 지라도, 그건 동기화 문제가 없어.
|
||||
// 다른 게임 서버에 똑같은 bidder_id를 가진 놈이 있을 수가 없으니까.
|
||||
// 그러므로 그 게임 서버에서 BidCancel 명령을 db에 날렸다는 것은,
|
||||
// 이미 그 부분에 대해서는 검사가 완벽하다는 것이야.
|
||||
// 그래도 혹시나 싶어서, 디버깅을 위해 fail 코드를 남겨둔다.
|
||||
// 이건 FAIL이 떠서는 안돼.
|
||||
// FAIL이 뜰 수가 없는게, MyBid에 있는 bidder_id에 대한 컨텐츠는 bidder_id만이 접근 할 수 있거든?
|
||||
// 그러므로 다른 것이 다 정상적으로 작동한다고 가정 한다면
|
||||
// 한 게임 서버 내에서 bidder_id로 MyBid를 수정한다 할 지라도, 그건 동기화 문제가 없어.
|
||||
// 다른 게임 서버에 똑같은 bidder_id를 가진 놈이 있을 수가 없으니까.
|
||||
// 그러므로 그 게임 서버에서 BidCancel 명령을 db에 날렸다는 것은,
|
||||
// 이미 그 부분에 대해서는 검사가 완벽하다는 것이야.
|
||||
// 그래도 혹시나 싶어서, 디버깅을 위해 fail 코드를 남겨둔다.
|
||||
if (result <= AUCTION_FAIL)
|
||||
{
|
||||
TPacketDGResultAuction enroll_result;
|
||||
|
@ -4630,14 +4630,14 @@ void CClientManager::AuctionBidCancel (CPeer * peer, DWORD bidder_id, DWORD item
|
|||
{
|
||||
AuctionResult result = AuctionManager::instance().BidCancel (bidder_id, item_id);
|
||||
|
||||
// 이건 FAIL이 떠서는 안돼.
|
||||
// FAIL이 뜰 수가 없는게, MyBid에 있는 bidder_id에 대한 컨텐츠는 bidder_id만이 접근 할 수 있거든?
|
||||
// 그러므로 다른 것이 다 정상적으로 작동한다고 가정 한다면
|
||||
// 한 게임 서버 내에서 bidder_id로 MyBid를 수정한다 할 지라도, 그건 동기화 문제가 없어.
|
||||
// 다른 게임 서버에 똑같은 bidder_id를 가진 놈이 있을 수가 없으니까.
|
||||
// 그러므로 그 게임 서버에서 BidCancel 명령을 db에 날렸다는 것은,
|
||||
// 이미 그 부분에 대해서는 검사가 완벽하다는 것이야.
|
||||
// 그래도 혹시나 싶어서, 디버깅을 위해 fail 코드를 남겨둔다.
|
||||
// 이건 FAIL이 떠서는 안돼.
|
||||
// FAIL이 뜰 수가 없는게, MyBid에 있는 bidder_id에 대한 컨텐츠는 bidder_id만이 접근 할 수 있거든?
|
||||
// 그러므로 다른 것이 다 정상적으로 작동한다고 가정 한다면
|
||||
// 한 게임 서버 내에서 bidder_id로 MyBid를 수정한다 할 지라도, 그건 동기화 문제가 없어.
|
||||
// 다른 게임 서버에 똑같은 bidder_id를 가진 놈이 있을 수가 없으니까.
|
||||
// 그러므로 그 게임 서버에서 BidCancel 명령을 db에 날렸다는 것은,
|
||||
// 이미 그 부분에 대해서는 검사가 완벽하다는 것이야.
|
||||
// 그래도 혹시나 싶어서, 디버깅을 위해 fail 코드를 남겨둔다.
|
||||
if (result <= AUCTION_FAIL)
|
||||
{
|
||||
TPacketDGResultAuction enroll_result;
|
||||
|
|
|
@ -48,10 +48,10 @@ class CClientManager : public singleton<CClientManager>
|
|||
typedef std::unordered_map<short, BYTE> TChannelStatusMap;
|
||||
|
||||
// MYSHOP_PRICE_LIST
|
||||
/// 아이템 가격정보 리스트 요청 정보
|
||||
/// 아이템 가격정보 리스트 요청 정보
|
||||
/**
|
||||
* first: Peer handle
|
||||
* second: 요청한 플레이어의 ID
|
||||
* second: 요청한 플레이어의 ID
|
||||
*/
|
||||
typedef std::pair< DWORD, DWORD > TItemPricelistReqInfo;
|
||||
// END_OF_MYSHOP_PRICE_LIST
|
||||
|
@ -77,7 +77,7 @@ class CClientManager : public singleton<CClientManager>
|
|||
pAccountTable = NULL;
|
||||
player_id = dwPID;
|
||||
};
|
||||
//독일선물기능용 생성자
|
||||
//독일선물기능용 생성자
|
||||
ClientHandleInfo(DWORD argHandle, DWORD dwPID, DWORD accountId)
|
||||
{
|
||||
dwHandle = argHandle;
|
||||
|
@ -116,7 +116,7 @@ class CClientManager : public singleton<CClientManager>
|
|||
void SetChinaEventServer(bool flag) { m_bChinaEventServer = flag; }
|
||||
bool IsChinaEventServer() { return m_bChinaEventServer; }
|
||||
|
||||
DWORD GetUserCount(); // 접속된 사용자 수를 리턴 한다.
|
||||
DWORD GetUserCount(); // 접속된 사용자 수를 리턴 한다.
|
||||
|
||||
void SendAllGuildSkillRechargePacket();
|
||||
void SendTime();
|
||||
|
@ -136,23 +136,23 @@ class CClientManager : public singleton<CClientManager>
|
|||
void UpdateItemCache();
|
||||
|
||||
// MYSHOP_PRICE_LIST
|
||||
/// 가격정보 리스트 캐시를 가져온다.
|
||||
/// 가격정보 리스트 캐시를 가져온다.
|
||||
/**
|
||||
* @param [in] dwID 가격정보 리스트의 소유자.(플레이어 ID)
|
||||
* @return 가격정보 리스트 캐시의 포인터
|
||||
* @param [in] dwID 가격정보 리스트의 소유자.(플레이어 ID)
|
||||
* @return 가격정보 리스트 캐시의 포인터
|
||||
*/
|
||||
CItemPriceListTableCache* GetItemPriceListCache(DWORD dwID);
|
||||
|
||||
/// 가격정보 리스트 캐시를 넣는다.
|
||||
/// 가격정보 리스트 캐시를 넣는다.
|
||||
/**
|
||||
* @param [in] pItemPriceList 캐시에 넣을 아이템 가격정보 리스트
|
||||
* @param [in] pItemPriceList 캐시에 넣을 아이템 가격정보 리스트
|
||||
*
|
||||
* 캐시가 이미 있으면 Update 가 아닌 replace 한다.
|
||||
* 캐시가 이미 있으면 Update 가 아닌 replace 한다.
|
||||
*/
|
||||
void PutItemPriceListCache(const TItemPriceListTable* pItemPriceList);
|
||||
|
||||
|
||||
/// Flush 시간이 만료된 아이템 가격정보 리스트 캐시를 Flush 해주고 캐시에서 삭제한다.
|
||||
/// Flush 시간이 만료된 아이템 가격정보 리스트 캐시를 Flush 해주고 캐시에서 삭제한다.
|
||||
void UpdateItemPriceListCache(void);
|
||||
// END_OF_MYSHOP_PRICE_LIST
|
||||
|
||||
|
@ -170,8 +170,8 @@ class CClientManager : public singleton<CClientManager>
|
|||
|
||||
void SendNotice(const char * c_pszFormat, ...);
|
||||
|
||||
std::string GetCommand(char* str); //독일선물기능에서 명령어 얻는 함수
|
||||
void ItemAward(CPeer * peer, char* login); //독일 선물 기능
|
||||
std::string GetCommand(char* str); //독일선물기능에서 명령어 얻는 함수
|
||||
void ItemAward(CPeer * peer, char* login); //독일 선물 기능
|
||||
|
||||
CPeer * AddPeer(bufferevent* bufev, sockaddr* addr);
|
||||
void RemovePeer(CPeer * pPeer);
|
||||
|
@ -199,9 +199,9 @@ class CClientManager : public singleton<CClientManager>
|
|||
bool InitializeObjectTable();
|
||||
bool InitializeMonarch();
|
||||
|
||||
// mob_proto.txt, item_proto.txt에서 읽은 mob_proto, item_proto를 real db에 반영.
|
||||
// item_proto, mob_proto를 db에 반영하지 않아도, 게임 돌아가는데는 문제가 없지만,
|
||||
// 운영툴 등에서 db의 item_proto, mob_proto를 읽어 쓰기 때문에 문제가 발생한다.
|
||||
// mob_proto.txt, item_proto.txt에서 읽은 mob_proto, item_proto를 real db에 반영.
|
||||
// item_proto, mob_proto를 db에 반영하지 않아도, 게임 돌아가는데는 문제가 없지만,
|
||||
// 운영툴 등에서 db의 item_proto, mob_proto를 읽어 쓰기 때문에 문제가 발생한다.
|
||||
bool MirrorMobTableIntoDB();
|
||||
bool MirrorItemTableIntoDB();
|
||||
|
||||
|
@ -260,20 +260,20 @@ class CClientManager : public singleton<CClientManager>
|
|||
// END_PLAYER_INDEX_CREATE_BUG_FIX
|
||||
|
||||
// MYSHOP_PRICE_LIST
|
||||
/// 가격정보 로드 쿼리에 대한 Result 처리
|
||||
/// 가격정보 로드 쿼리에 대한 Result 처리
|
||||
/**
|
||||
* @param peer 가격정보를 요청한 Game server 의 peer 객체 포인터
|
||||
* @param pMsg 쿼리의 Result 로 받은 객체의 포인터
|
||||
* @param peer 가격정보를 요청한 Game server 의 peer 객체 포인터
|
||||
* @param pMsg 쿼리의 Result 로 받은 객체의 포인터
|
||||
*
|
||||
* 로드된 가격정보 리스트를 캐시에 저장하고 peer 에게 리스트를 보내준다.
|
||||
* 로드된 가격정보 리스트를 캐시에 저장하고 peer 에게 리스트를 보내준다.
|
||||
*/
|
||||
void RESULT_PRICELIST_LOAD(CPeer* peer, SQLMsg* pMsg);
|
||||
|
||||
/// 가격정보 업데이트를 위한 로드 쿼리에 대한 Result 처리
|
||||
/// 가격정보 업데이트를 위한 로드 쿼리에 대한 Result 처리
|
||||
/**
|
||||
* @param pMsg 쿼리의 Result 로 받은 객체의 포인터
|
||||
* @param pMsg 쿼리의 Result 로 받은 객체의 포인터
|
||||
*
|
||||
* 로드된 정보로 가격정보 리스트 캐시를 만들고 업데이트 받은 가격정보로 업데이트 한다.
|
||||
* 로드된 정보로 가격정보 리스트 캐시를 만들고 업데이트 받은 가격정보로 업데이트 한다.
|
||||
*/
|
||||
void RESULT_PRICELIST_LOAD_FOR_UPDATE(SQLMsg* pMsg);
|
||||
// END_OF_MYSHOP_PRICE_LIST
|
||||
|
@ -343,7 +343,7 @@ class CClientManager : public singleton<CClientManager>
|
|||
void SetEventFlag(TPacketSetEventFlag* p);
|
||||
void SendEventFlagsOnSetup(CPeer* peer);
|
||||
|
||||
// 결혼
|
||||
// 결혼
|
||||
void MarriageAdd(TPacketMarriageAdd * p);
|
||||
void MarriageUpdate(TPacketMarriageUpdate * p);
|
||||
void MarriageRemove(TPacketMarriageRemove * p);
|
||||
|
@ -353,19 +353,19 @@ class CClientManager : public singleton<CClientManager>
|
|||
void WeddingEnd(TPacketWeddingEnd * p);
|
||||
|
||||
// MYSHOP_PRICE_LIST
|
||||
// 개인상점 가격정보
|
||||
// 개인상점 가격정보
|
||||
|
||||
/// 아이템 가격정보 리스트 업데이트 패킷(HEADER_GD_MYSHOP_PRICELIST_UPDATE) 처리함수
|
||||
/// 아이템 가격정보 리스트 업데이트 패킷(HEADER_GD_MYSHOP_PRICELIST_UPDATE) 처리함수
|
||||
/**
|
||||
* @param [in] pPacket 패킷 데이터의 포인터
|
||||
* @param [in] pPacket 패킷 데이터의 포인터
|
||||
*/
|
||||
void MyshopPricelistUpdate(const TPacketMyshopPricelistHeader* pPacket);
|
||||
|
||||
/// 아이템 가격정보 리스트 요청 패킷(HEADER_GD_MYSHOP_PRICELIST_REQ) 처리함수
|
||||
/// 아이템 가격정보 리스트 요청 패킷(HEADER_GD_MYSHOP_PRICELIST_REQ) 처리함수
|
||||
/**
|
||||
* @param peer 패킷을 보낸 Game server 의 peer 객체의 포인터
|
||||
* @param [in] dwHandle 가격정보를 요청한 peer 의 핸들
|
||||
* @param [in] dwPlayerID 가격정보 리스트를 요청한 플레이어의 ID
|
||||
* @param peer 패킷을 보낸 Game server 의 peer 객체의 포인터
|
||||
* @param [in] dwHandle 가격정보를 요청한 peer 의 핸들
|
||||
* @param [in] dwPlayerID 가격정보 리스트를 요청한 플레이어의 ID
|
||||
*/
|
||||
void MyshopPricelistRequest(CPeer* peer, DWORD dwHandle, DWORD dwPlayerID);
|
||||
// END_OF_MYSHOP_PRICE_LIST
|
||||
|
@ -399,7 +399,7 @@ class CClientManager : public singleton<CClientManager>
|
|||
typedef std::unordered_map<DWORD, CLoginData *> TLoginDataByAID;
|
||||
TLoginDataByAID m_map_pkLoginDataByAID;
|
||||
|
||||
// Login LoginData pair (실제 로그인 되어있는 계정)
|
||||
// Login LoginData pair (실제 로그인 되어있는 계정)
|
||||
typedef std::unordered_map<std::string, CLoginData *> TLogonAccountMap;
|
||||
TLogonAccountMap m_map_kLogonAccount;
|
||||
|
||||
|
@ -429,14 +429,14 @@ class CClientManager : public singleton<CClientManager>
|
|||
|
||||
bool m_bShutdowned;
|
||||
|
||||
TPlayerTableCacheMap m_map_playerCache; // 플레이어 id가 key
|
||||
TPlayerTableCacheMap m_map_playerCache; // 플레이어 id가 key
|
||||
|
||||
TItemCacheMap m_map_itemCache; // 아이템 id가 key
|
||||
TItemCacheSetPtrMap m_map_pkItemCacheSetPtr; // 플레이어 id가 key, 이 플레이어가 어떤 아이템 캐쉬를 가지고 있나?
|
||||
TItemCacheMap m_map_itemCache; // 아이템 id가 key
|
||||
TItemCacheSetPtrMap m_map_pkItemCacheSetPtr; // 플레이어 id가 key, 이 플레이어가 어떤 아이템 캐쉬를 가지고 있나?
|
||||
|
||||
// MYSHOP_PRICE_LIST
|
||||
/// 플레이어별 아이템 가격정보 리스트 map. key: 플레이어 ID, value: 가격정보 리스트 캐시
|
||||
TItemPriceListCacheMap m_mapItemPriceListCache; ///< 플레이어별 아이템 가격정보 리스트
|
||||
/// 플레이어별 아이템 가격정보 리스트 map. key: 플레이어 ID, value: 가격정보 리스트 캐시
|
||||
TItemPriceListCacheMap m_mapItemPriceListCache; ///< 플레이어별 아이템 가격정보 리스트
|
||||
// END_OF_MYSHOP_PRICE_LIST
|
||||
|
||||
TChannelStatusMap m_mChannelStatus;
|
||||
|
@ -474,7 +474,7 @@ class CClientManager : public singleton<CClientManager>
|
|||
|
||||
//BOOT_LOCALIZATION
|
||||
public:
|
||||
/* 로컬 정보 초기화
|
||||
/* 로컬 정보 초기화
|
||||
**/
|
||||
bool InitializeLocalization();
|
||||
|
||||
|
|
|
@ -171,42 +171,42 @@ class FCompareVnum
|
|||
|
||||
bool CClientManager::InitializeMobTable()
|
||||
{
|
||||
//================== 함수 설명 ==================//
|
||||
//1. 요약 : 'mob_proto.txt', 'mob_proto_test.txt', 'mob_names.txt' 파일을 읽고,
|
||||
// (!)[mob_table] 테이블 오브젝트를 생성한다. (타입 : TMobTable)
|
||||
//2. 순서
|
||||
// 1) 'mob_names.txt' 파일을 읽어서 (a)[localMap](vnum:name) 맵을 만든다.
|
||||
// 2) 'mob_proto_test.txt'파일과 (a)[localMap] 맵으로
|
||||
// (b)[test_map_mobTableByVnum](vnum:TMobTable) 맵을 생성한다.
|
||||
// 3) 'mob_proto.txt' 파일과 (a)[localMap] 맵으로
|
||||
// (!)[mob_table] 테이블을 만든다.
|
||||
// <참고>
|
||||
// 각 row 들 중,
|
||||
// (b)[test_map_mobTableByVnum],(!)[mob_table] 모두에 있는 row는
|
||||
// (b)[test_map_mobTableByVnum]의 것을 사용한다.
|
||||
// 4) (b)[test_map_mobTableByVnum]의 row중, (!)[mob_table]에 없는 것을 추가한다.
|
||||
//3. 테스트
|
||||
// 1)'mob_proto.txt' 정보가 mob_table에 잘 들어갔는지. -> 완료
|
||||
// 2)'mob_names.txt' 정보가 mob_table에 잘 들어갔는지.
|
||||
// 3)'mob_proto_test.txt' 에서 [겹치는] 정보가 mob_table 에 잘 들어갔는지.
|
||||
// 4)'mob_proto_test.txt' 에서 [새로운] 정보가 mob_table 에 잘 들어갔는지.
|
||||
// 5) (최종) 게임 클라이언트에서 제대로 작동 하는지.
|
||||
//================== 함수 설명 ==================//
|
||||
//1. 요약 : 'mob_proto.txt', 'mob_proto_test.txt', 'mob_names.txt' 파일을 읽고,
|
||||
// (!)[mob_table] 테이블 오브젝트를 생성한다. (타입 : TMobTable)
|
||||
//2. 순서
|
||||
// 1) 'mob_names.txt' 파일을 읽어서 (a)[localMap](vnum:name) 맵을 만든다.
|
||||
// 2) 'mob_proto_test.txt'파일과 (a)[localMap] 맵으로
|
||||
// (b)[test_map_mobTableByVnum](vnum:TMobTable) 맵을 생성한다.
|
||||
// 3) 'mob_proto.txt' 파일과 (a)[localMap] 맵으로
|
||||
// (!)[mob_table] 테이블을 만든다.
|
||||
// <참고>
|
||||
// 각 row 들 중,
|
||||
// (b)[test_map_mobTableByVnum],(!)[mob_table] 모두에 있는 row는
|
||||
// (b)[test_map_mobTableByVnum]의 것을 사용한다.
|
||||
// 4) (b)[test_map_mobTableByVnum]의 row중, (!)[mob_table]에 없는 것을 추가한다.
|
||||
//3. 테스트
|
||||
// 1)'mob_proto.txt' 정보가 mob_table에 잘 들어갔는지. -> 완료
|
||||
// 2)'mob_names.txt' 정보가 mob_table에 잘 들어갔는지.
|
||||
// 3)'mob_proto_test.txt' 에서 [겹치는] 정보가 mob_table 에 잘 들어갔는지.
|
||||
// 4)'mob_proto_test.txt' 에서 [새로운] 정보가 mob_table 에 잘 들어갔는지.
|
||||
// 5) (최종) 게임 클라이언트에서 제대로 작동 하는지.
|
||||
//_______________________________________________//
|
||||
|
||||
|
||||
//===============================================//
|
||||
// 1) 'mob_names.txt' 파일을 읽어서 (a)[localMap] 맵을 만든다.
|
||||
//<(a)localMap 맵 생성>
|
||||
// 1) 'mob_names.txt' 파일을 읽어서 (a)[localMap] 맵을 만든다.
|
||||
//<(a)localMap 맵 생성>
|
||||
map<int,const char*> localMap;
|
||||
bool isNameFile = true;
|
||||
//<파일 읽기>
|
||||
//<파일 읽기>
|
||||
cCsvTable nameData;
|
||||
if(!nameData.Load("mob_names.txt",'\t'))
|
||||
{
|
||||
SPDLOG_ERROR("mob_names.txt 파일을 읽어오지 못했습니다");
|
||||
SPDLOG_ERROR("mob_names.txt Failed to read the file");
|
||||
isNameFile = false;
|
||||
} else {
|
||||
nameData.Next(); //설명row 생략.
|
||||
nameData.Next(); //설명row 생략.
|
||||
while(nameData.Next()) {
|
||||
localMap[atoi(nameData.AsStringByIndex(0))] = nameData.AsStringByIndex(1);
|
||||
}
|
||||
|
@ -215,35 +215,35 @@ bool CClientManager::InitializeMobTable()
|
|||
|
||||
|
||||
//===============================================//
|
||||
// 2) 'mob_proto_test.txt'파일과 (a)localMap 맵으로
|
||||
// (b)[test_map_mobTableByVnum](vnum:TMobTable) 맵을 생성한다.
|
||||
// 2) 'mob_proto_test.txt'파일과 (a)localMap 맵으로
|
||||
// (b)[test_map_mobTableByVnum](vnum:TMobTable) 맵을 생성한다.
|
||||
//0.
|
||||
set<int> vnumSet; //테스트용 파일 데이터중, 신규여부 확인에 사용.
|
||||
//1. 파일 읽어오기
|
||||
set<int> vnumSet; //테스트용 파일 데이터중, 신규여부 확인에 사용.
|
||||
//1. 파일 읽어오기
|
||||
bool isTestFile = true;
|
||||
cCsvTable test_data;
|
||||
if(!test_data.Load("mob_proto_test.txt",'\t'))
|
||||
{
|
||||
SPDLOG_ERROR("테스트 파일이 없습니다. 그대로 진행합니다.");
|
||||
SPDLOG_ERROR("No test file exists, proceed as is.");
|
||||
isTestFile = false;
|
||||
}
|
||||
//2. (c)[test_map_mobTableByVnum](vnum:TMobTable) 맵 생성.
|
||||
//2. (c)[test_map_mobTableByVnum](vnum:TMobTable) 맵 생성.
|
||||
map<DWORD, TMobTable *> test_map_mobTableByVnum;
|
||||
if (isTestFile) {
|
||||
test_data.Next(); //설명 로우 넘어가기.
|
||||
test_data.Next(); //설명 로우 넘어가기.
|
||||
|
||||
//ㄱ. 테스트 몬스터 테이블 생성.
|
||||
//ㄱ. 테스트 몬스터 테이블 생성.
|
||||
TMobTable * test_mob_table = NULL;
|
||||
int test_MobTableSize = test_data.m_File.GetRowCount()-1;
|
||||
test_mob_table = new TMobTable[test_MobTableSize];
|
||||
memset(test_mob_table, 0, sizeof(TMobTable) * test_MobTableSize);
|
||||
|
||||
//ㄴ. 테스트 몬스터 테이블에 값을 넣고, 맵에까지 넣기.
|
||||
//ㄴ. 테스트 몬스터 테이블에 값을 넣고, 맵에까지 넣기.
|
||||
while(test_data.Next()) {
|
||||
|
||||
if (!Set_Proto_Mob_Table(test_mob_table, test_data, localMap))
|
||||
{
|
||||
SPDLOG_ERROR("몹 프로토 테이블 셋팅 실패.");
|
||||
SPDLOG_ERROR("Mob proto table setup failed.");
|
||||
}
|
||||
|
||||
test_map_mobTableByVnum.insert(std::map<DWORD, TMobTable *>::value_type(test_mob_table->dwVnum, test_mob_table));
|
||||
|
@ -254,22 +254,22 @@ bool CClientManager::InitializeMobTable()
|
|||
|
||||
}
|
||||
|
||||
// 3) 'mob_proto.txt' 파일과 (a)[localMap] 맵으로
|
||||
// (!)[mob_table] 테이블을 만든다.
|
||||
// <참고>
|
||||
// 각 row 들 중,
|
||||
// (b)[test_map_mobTableByVnum],(!)[mob_table] 모두에 있는 row는
|
||||
// (b)[test_map_mobTableByVnum]의 것을 사용한다.
|
||||
// 3) 'mob_proto.txt' 파일과 (a)[localMap] 맵으로
|
||||
// (!)[mob_table] 테이블을 만든다.
|
||||
// <참고>
|
||||
// 각 row 들 중,
|
||||
// (b)[test_map_mobTableByVnum],(!)[mob_table] 모두에 있는 row는
|
||||
// (b)[test_map_mobTableByVnum]의 것을 사용한다.
|
||||
|
||||
//1. 파일 읽기.
|
||||
//1. 파일 읽기.
|
||||
cCsvTable data;
|
||||
if(!data.Load("mob_proto.txt",'\t')) {
|
||||
SPDLOG_ERROR("mob_proto.txt 파일을 읽어오지 못했습니다");
|
||||
SPDLOG_ERROR("mob_proto.txt Failed to read the file");
|
||||
return false;
|
||||
}
|
||||
data.Next(); //설명 row 넘어가기
|
||||
//2. (!)[mob_table] 생성하기
|
||||
//2.1 새로 추가되는 갯수를 파악
|
||||
data.Next(); //설명 row 넘어가기
|
||||
//2. (!)[mob_table] 생성하기
|
||||
//2.1 새로 추가되는 갯수를 파악
|
||||
int addNumber = 0;
|
||||
while(data.Next()) {
|
||||
int vnum = atoi(data.AsStringByIndex(0));
|
||||
|
@ -279,15 +279,15 @@ bool CClientManager::InitializeMobTable()
|
|||
addNumber++;
|
||||
}
|
||||
}
|
||||
//data를 다시 첫줄로 옮긴다.(다시 읽어온다;;)
|
||||
//data를 다시 첫줄로 옮긴다.(다시 읽어온다;;)
|
||||
data.Destroy();
|
||||
if(!data.Load("mob_proto.txt",'\t'))
|
||||
{
|
||||
SPDLOG_ERROR("mob_proto.txt 파일을 읽어오지 못했습니다");
|
||||
SPDLOG_ERROR("mob_proto.txt Failed to read the file");
|
||||
return false;
|
||||
}
|
||||
data.Next(); //맨 윗줄 제외 (아이템 칼럼을 설명하는 부분)
|
||||
//2.2 크기에 맞게 mob_table 생성
|
||||
data.Next(); //맨 윗줄 제외 (아이템 칼럼을 설명하는 부분)
|
||||
//2.2 크기에 맞게 mob_table 생성
|
||||
if (!m_vec_mobTable.empty())
|
||||
{
|
||||
SPDLOG_DEBUG("RELOAD: mob_proto");
|
||||
|
@ -296,18 +296,18 @@ bool CClientManager::InitializeMobTable()
|
|||
m_vec_mobTable.resize(data.m_File.GetRowCount()-1 + addNumber);
|
||||
memset(&m_vec_mobTable[0], 0, sizeof(TMobTable) * m_vec_mobTable.size());
|
||||
TMobTable * mob_table = &m_vec_mobTable[0];
|
||||
//2.3 데이터 채우기
|
||||
//2.3 데이터 채우기
|
||||
while (data.Next())
|
||||
{
|
||||
int col = 0;
|
||||
//(b)[test_map_mobTableByVnum]에 같은 row가 있는지 조사.
|
||||
//(b)[test_map_mobTableByVnum]에 같은 row가 있는지 조사.
|
||||
bool isSameRow = true;
|
||||
std::map<DWORD, TMobTable *>::iterator it_map_mobTable;
|
||||
it_map_mobTable = test_map_mobTableByVnum.find(atoi(data.AsStringByIndex(col)));
|
||||
if(it_map_mobTable == test_map_mobTableByVnum.end()) {
|
||||
isSameRow = false;
|
||||
}
|
||||
//같은 row 가 있으면 (b)에서 읽어온다.
|
||||
//같은 row 가 있으면 (b)에서 읽어온다.
|
||||
if(isSameRow) {
|
||||
TMobTable *tempTable = it_map_mobTable->second;
|
||||
|
||||
|
@ -378,13 +378,13 @@ bool CClientManager::InitializeMobTable()
|
|||
|
||||
if (!Set_Proto_Mob_Table(mob_table, data, localMap))
|
||||
{
|
||||
SPDLOG_ERROR("몹 프로토 테이블 셋팅 실패.");
|
||||
SPDLOG_ERROR("Mob proto table setup failed.");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//셋에 vnum 추가
|
||||
//셋에 vnum 추가
|
||||
vnumSet.insert(mob_table->dwVnum);
|
||||
|
||||
|
||||
|
@ -395,22 +395,22 @@ bool CClientManager::InitializeMobTable()
|
|||
//_____________________________________________________//
|
||||
|
||||
|
||||
// 4) (b)[test_map_mobTableByVnum]의 row중, (!)[mob_table]에 없는 것을 추가한다.
|
||||
//파일 다시 읽어오기.
|
||||
// 4) (b)[test_map_mobTableByVnum]의 row중, (!)[mob_table]에 없는 것을 추가한다.
|
||||
//파일 다시 읽어오기.
|
||||
test_data.Destroy();
|
||||
isTestFile = true;
|
||||
test_data;
|
||||
if(!test_data.Load("mob_proto_test.txt",'\t'))
|
||||
{
|
||||
SPDLOG_ERROR("테스트 파일이 없습니다. 그대로 진행합니다.");
|
||||
SPDLOG_ERROR("No test file exists, proceed as is.");
|
||||
isTestFile = false;
|
||||
}
|
||||
if(isTestFile) {
|
||||
test_data.Next(); //설명 로우 넘어가기.
|
||||
test_data.Next(); //설명 로우 넘어가기.
|
||||
|
||||
while (test_data.Next()) //테스트 데이터 각각을 훑어나가며,새로운 것을 추가한다.
|
||||
while (test_data.Next()) //테스트 데이터 각각을 훑어나가며,새로운 것을 추가한다.
|
||||
{
|
||||
//중복되는 부분이면 넘어간다.
|
||||
//중복되는 부분이면 넘어간다.
|
||||
set<int>::iterator itVnum;
|
||||
itVnum=vnumSet.find(atoi(test_data.AsStringByIndex(0)));
|
||||
if (itVnum != vnumSet.end()) {
|
||||
|
@ -419,7 +419,7 @@ bool CClientManager::InitializeMobTable()
|
|||
|
||||
if (!Set_Proto_Mob_Table(mob_table, test_data, localMap))
|
||||
{
|
||||
SPDLOG_ERROR("몹 프로토 테이블 셋팅 실패.");
|
||||
SPDLOG_ERROR("Mob proto table setup failed.");
|
||||
}
|
||||
|
||||
SPDLOG_DEBUG("MOB #{:<5} {:24} {:24} level: {:<3} rank: {} empire: {}", mob_table->dwVnum, mob_table->szName, mob_table->szLocaleName, mob_table->bLevel, mob_table->bRank, mob_table->bEmpire);
|
||||
|
@ -447,8 +447,8 @@ bool CClientManager::InitializeShopTable()
|
|||
|
||||
std::unique_ptr<SQLMsg> pkMsg2(CDBManager::instance().DirectQuery(s_szQuery));
|
||||
|
||||
// shop의 vnum은 있는데 shop_item 이 없을경우... 실패로 처리되니 주의 요망.
|
||||
// 고처야할부분
|
||||
// shop의 vnum은 있는데 shop_item 이 없을경우... 실패로 처리되니 주의 요망.
|
||||
// 고처야할부분
|
||||
SQLResult * pRes2 = pkMsg2->Get();
|
||||
|
||||
if (!pRes2->uiNumRows)
|
||||
|
@ -487,7 +487,7 @@ bool CClientManager::InitializeShopTable()
|
|||
|
||||
str_to_number(shop_table->dwNPCVnum, data[col++]);
|
||||
|
||||
if (!data[col]) // 아이템이 하나도 없으면 NULL이 리턴 되므로..
|
||||
if (!data[col]) // 아이템이 하나도 없으면 NULL이 리턴 되므로..
|
||||
continue;
|
||||
|
||||
TShopItemTable * pItem = &shop_table->items[shop_table->byItemCount];
|
||||
|
@ -560,7 +560,7 @@ bool CClientManager::InitializeQuestItemTable()
|
|||
continue;
|
||||
}
|
||||
|
||||
tbl.bType = ITEM_QUEST; // quest_item_proto 테이블에 있는 것들은 모두 ITEM_QUEST 유형
|
||||
tbl.bType = ITEM_QUEST; // quest_item_proto 테이블에 있는 것들은 모두 ITEM_QUEST 유형
|
||||
tbl.bSize = 1;
|
||||
|
||||
m_vec_itemTable.push_back(tbl);
|
||||
|
@ -571,39 +571,39 @@ bool CClientManager::InitializeQuestItemTable()
|
|||
|
||||
bool CClientManager::InitializeItemTable()
|
||||
{
|
||||
//================== 함수 설명 ==================//
|
||||
//1. 요약 : 'item_proto.txt', 'item_proto_test.txt', 'item_names.txt' 파일을 읽고,
|
||||
// <item_table>(TItemTable), <m_map_itemTableByVnum> 오브젝트를 생성한다.
|
||||
//2. 순서
|
||||
// 1) 'item_names.txt' 파일을 읽어서 (a)[localMap](vnum:name) 맵을 만든다.
|
||||
// 2) 'item_proto_text.txt'파일과 (a)[localMap] 맵으로
|
||||
// (b)[test_map_itemTableByVnum](vnum:TItemTable) 맵을 생성한다.
|
||||
// 3) 'item_proto.txt' 파일과 (a)[localMap] 맵으로
|
||||
// (!)[item_table], <m_map_itemTableByVnum>을 만든다.
|
||||
// <참고>
|
||||
// 각 row 들 중,
|
||||
// (b)[test_map_itemTableByVnum],(!)[mob_table] 모두에 있는 row는
|
||||
// (b)[test_map_itemTableByVnum]의 것을 사용한다.
|
||||
// 4) (b)[test_map_itemTableByVnum]의 row중, (!)[item_table]에 없는 것을 추가한다.
|
||||
//3. 테스트
|
||||
// 1)'item_proto.txt' 정보가 item_table에 잘 들어갔는지. -> 완료
|
||||
// 2)'item_names.txt' 정보가 item_table에 잘 들어갔는지.
|
||||
// 3)'item_proto_test.txt' 에서 [겹치는] 정보가 item_table 에 잘 들어갔는지.
|
||||
// 4)'item_proto_test.txt' 에서 [새로운] 정보가 item_table 에 잘 들어갔는지.
|
||||
// 5) (최종) 게임 클라이언트에서 제대로 작동 하는지.
|
||||
//================== 함수 설명 ==================//
|
||||
//1. 요약 : 'item_proto.txt', 'item_proto_test.txt', 'item_names.txt' 파일을 읽고,
|
||||
// <item_table>(TItemTable), <m_map_itemTableByVnum> 오브젝트를 생성한다.
|
||||
//2. 순서
|
||||
// 1) 'item_names.txt' 파일을 읽어서 (a)[localMap](vnum:name) 맵을 만든다.
|
||||
// 2) 'item_proto_text.txt'파일과 (a)[localMap] 맵으로
|
||||
// (b)[test_map_itemTableByVnum](vnum:TItemTable) 맵을 생성한다.
|
||||
// 3) 'item_proto.txt' 파일과 (a)[localMap] 맵으로
|
||||
// (!)[item_table], <m_map_itemTableByVnum>을 만든다.
|
||||
// <참고>
|
||||
// 각 row 들 중,
|
||||
// (b)[test_map_itemTableByVnum],(!)[mob_table] 모두에 있는 row는
|
||||
// (b)[test_map_itemTableByVnum]의 것을 사용한다.
|
||||
// 4) (b)[test_map_itemTableByVnum]의 row중, (!)[item_table]에 없는 것을 추가한다.
|
||||
//3. 테스트
|
||||
// 1)'item_proto.txt' 정보가 item_table에 잘 들어갔는지. -> 완료
|
||||
// 2)'item_names.txt' 정보가 item_table에 잘 들어갔는지.
|
||||
// 3)'item_proto_test.txt' 에서 [겹치는] 정보가 item_table 에 잘 들어갔는지.
|
||||
// 4)'item_proto_test.txt' 에서 [새로운] 정보가 item_table 에 잘 들어갔는지.
|
||||
// 5) (최종) 게임 클라이언트에서 제대로 작동 하는지.
|
||||
//_______________________________________________//
|
||||
|
||||
|
||||
|
||||
//=================================================================================//
|
||||
// 1) 'item_names.txt' 파일을 읽어서 (a)[localMap](vnum:name) 맵을 만든다.
|
||||
// 1) 'item_names.txt' 파일을 읽어서 (a)[localMap](vnum:name) 맵을 만든다.
|
||||
//=================================================================================//
|
||||
bool isNameFile = true;
|
||||
map<int,const char*> localMap;
|
||||
cCsvTable nameData;
|
||||
if(!nameData.Load("item_names.txt",'\t'))
|
||||
{
|
||||
SPDLOG_ERROR("item_names.txt 파일을 읽어오지 못했습니다");
|
||||
SPDLOG_ERROR("item_names.txt Failed to read the file");
|
||||
isNameFile = false;
|
||||
} else {
|
||||
nameData.Next();
|
||||
|
@ -614,32 +614,32 @@ bool CClientManager::InitializeItemTable()
|
|||
//_________________________________________________________________//
|
||||
|
||||
//=================================================================//
|
||||
// 2) 'item_proto_text.txt'파일과 (a)[localMap] 맵으로
|
||||
// (b)[test_map_itemTableByVnum](vnum:TItemTable) 맵을 생성한다.
|
||||
// 2) 'item_proto_text.txt'파일과 (a)[localMap] 맵으로
|
||||
// (b)[test_map_itemTableByVnum](vnum:TItemTable) 맵을 생성한다.
|
||||
//=================================================================//
|
||||
map<DWORD, TItemTable *> test_map_itemTableByVnum;
|
||||
//1. 파일 읽어오기.
|
||||
//1. 파일 읽어오기.
|
||||
cCsvTable test_data;
|
||||
if(!test_data.Load("item_proto_test.txt",'\t'))
|
||||
{
|
||||
SPDLOG_ERROR("item_proto_test.txt 파일을 읽어오지 못했습니다");
|
||||
SPDLOG_ERROR("item_proto_test.txt Failed to read the file");
|
||||
//return false;
|
||||
} else {
|
||||
test_data.Next(); //설명 로우 넘어가기.
|
||||
test_data.Next(); //설명 로우 넘어가기.
|
||||
|
||||
//2. 테스트 아이템 테이블 생성.
|
||||
//2. 테스트 아이템 테이블 생성.
|
||||
TItemTable * test_item_table = NULL;
|
||||
int test_itemTableSize = test_data.m_File.GetRowCount()-1;
|
||||
test_item_table = new TItemTable[test_itemTableSize];
|
||||
memset(test_item_table, 0, sizeof(TItemTable) * test_itemTableSize);
|
||||
|
||||
//3. 테스트 아이템 테이블에 값을 넣고, 맵에까지 넣기.
|
||||
//3. 테스트 아이템 테이블에 값을 넣고, 맵에까지 넣기.
|
||||
while(test_data.Next()) {
|
||||
|
||||
|
||||
if (!Set_Proto_Item_Table(test_item_table, test_data, localMap))
|
||||
{
|
||||
SPDLOG_ERROR("아이템 프로토 테이블 셋팅 실패.");
|
||||
SPDLOG_ERROR("Item proto table setup failed.");
|
||||
}
|
||||
|
||||
test_map_itemTableByVnum.insert(std::map<DWORD, TItemTable *>::value_type(test_item_table->dwVnum, test_item_table));
|
||||
|
@ -651,25 +651,25 @@ bool CClientManager::InitializeItemTable()
|
|||
|
||||
|
||||
//========================================================================//
|
||||
// 3) 'item_proto.txt' 파일과 (a)[localMap] 맵으로
|
||||
// (!)[item_table], <m_map_itemTableByVnum>을 만든다.
|
||||
// <참고>
|
||||
// 각 row 들 중,
|
||||
// (b)[test_map_itemTableByVnum],(!)[mob_table] 모두에 있는 row는
|
||||
// (b)[test_map_itemTableByVnum]의 것을 사용한다.
|
||||
// 3) 'item_proto.txt' 파일과 (a)[localMap] 맵으로
|
||||
// (!)[item_table], <m_map_itemTableByVnum>을 만든다.
|
||||
// <참고>
|
||||
// 각 row 들 중,
|
||||
// (b)[test_map_itemTableByVnum],(!)[mob_table] 모두에 있는 row는
|
||||
// (b)[test_map_itemTableByVnum]의 것을 사용한다.
|
||||
//========================================================================//
|
||||
|
||||
//vnum들을 저장할 셋. 새로운 테스트 아이템을 판별할때 사용된다.
|
||||
//vnum들을 저장할 셋. 새로운 테스트 아이템을 판별할때 사용된다.
|
||||
set<int> vnumSet;
|
||||
|
||||
//파일 읽어오기.
|
||||
//파일 읽어오기.
|
||||
cCsvTable data;
|
||||
if(!data.Load("item_proto.txt",'\t'))
|
||||
{
|
||||
SPDLOG_ERROR("item_proto.txt 파일을 읽어오지 못했습니다");
|
||||
SPDLOG_ERROR("item_proto.txt Failed to read the file");
|
||||
return false;
|
||||
}
|
||||
data.Next(); //맨 윗줄 제외 (아이템 칼럼을 설명하는 부분)
|
||||
data.Next(); //맨 윗줄 제외 (아이템 칼럼을 설명하는 부분)
|
||||
|
||||
if (!m_vec_itemTable.empty())
|
||||
{
|
||||
|
@ -678,8 +678,8 @@ bool CClientManager::InitializeItemTable()
|
|||
m_map_itemTableByVnum.clear();
|
||||
}
|
||||
|
||||
//===== 아이템 테이블 생성 =====//
|
||||
//새로 추가되는 갯수를 파악한다.
|
||||
//===== 아이템 테이블 생성 =====//
|
||||
//새로 추가되는 갯수를 파악한다.
|
||||
int addNumber = 0;
|
||||
while(data.Next()) {
|
||||
int vnum = atoi(data.AsStringByIndex(0));
|
||||
|
@ -689,14 +689,14 @@ bool CClientManager::InitializeItemTable()
|
|||
addNumber++;
|
||||
}
|
||||
}
|
||||
//data를 다시 첫줄로 옮긴다.(다시 읽어온다;;)
|
||||
//data를 다시 첫줄로 옮긴다.(다시 읽어온다;;)
|
||||
data.Destroy();
|
||||
if(!data.Load("item_proto.txt",'\t'))
|
||||
{
|
||||
SPDLOG_ERROR("item_proto.txt 파일을 읽어오지 못했습니다");
|
||||
SPDLOG_ERROR("item_proto.txt Failed to read the file");
|
||||
return false;
|
||||
}
|
||||
data.Next(); //맨 윗줄 제외 (아이템 칼럼을 설명하는 부분)
|
||||
data.Next(); //맨 윗줄 제외 (아이템 칼럼을 설명하는 부분)
|
||||
|
||||
m_vec_itemTable.resize(data.m_File.GetRowCount() - 1 + addNumber);
|
||||
memset(&m_vec_itemTable[0], 0, sizeof(TItemTable) * m_vec_itemTable.size());
|
||||
|
@ -711,16 +711,16 @@ bool CClientManager::InitializeItemTable()
|
|||
std::map<DWORD, TItemTable *>::iterator it_map_itemTable;
|
||||
it_map_itemTable = test_map_itemTableByVnum.find(atoi(data.AsStringByIndex(col)));
|
||||
if(it_map_itemTable == test_map_itemTableByVnum.end()) {
|
||||
//각 칼럼 데이터 저장
|
||||
//각 칼럼 데이터 저장
|
||||
|
||||
if (!Set_Proto_Item_Table(item_table, data, localMap))
|
||||
{
|
||||
SPDLOG_ERROR("아이템 프로토 테이블 셋팅 실패.");
|
||||
SPDLOG_ERROR("Item proto table setup failed.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
} else { //$$$$$$$$$$$$$$$$$$$$$$$ 테스트 아이템 정보가 있다!
|
||||
} else { //$$$$$$$$$$$$$$$$$$$$$$$ 테스트 아이템 정보가 있다!
|
||||
TItemTable *tempTable = it_map_itemTable->second;
|
||||
|
||||
item_table->dwVnum = tempTable->dwVnum;
|
||||
|
@ -777,19 +777,19 @@ bool CClientManager::InitializeItemTable()
|
|||
//_______________________________________________________________________//
|
||||
|
||||
//========================================================================//
|
||||
// 4) (b)[test_map_itemTableByVnum]의 row중, (!)[item_table]에 없는 것을 추가한다.
|
||||
// 4) (b)[test_map_itemTableByVnum]의 row중, (!)[item_table]에 없는 것을 추가한다.
|
||||
//========================================================================//
|
||||
test_data.Destroy();
|
||||
if(!test_data.Load("item_proto_test.txt",'\t'))
|
||||
{
|
||||
SPDLOG_ERROR("item_proto_test.txt 파일을 읽어오지 못했습니다");
|
||||
SPDLOG_ERROR("item_proto_test.txt Failed to read the file");
|
||||
//return false;
|
||||
} else {
|
||||
test_data.Next(); //설명 로우 넘어가기.
|
||||
test_data.Next(); //설명 로우 넘어가기.
|
||||
|
||||
while (test_data.Next()) //테스트 데이터 각각을 훑어나가며,새로운 것을 추가한다.
|
||||
while (test_data.Next()) //테스트 데이터 각각을 훑어나가며,새로운 것을 추가한다.
|
||||
{
|
||||
//중복되는 부분이면 넘어간다.
|
||||
//중복되는 부분이면 넘어간다.
|
||||
set<int>::iterator itVnum;
|
||||
itVnum=vnumSet.find(atoi(test_data.AsStringByIndex(0)));
|
||||
if (itVnum != vnumSet.end()) {
|
||||
|
@ -798,7 +798,7 @@ bool CClientManager::InitializeItemTable()
|
|||
|
||||
if (!Set_Proto_Item_Table(item_table, test_data, localMap))
|
||||
{
|
||||
SPDLOG_ERROR("아이템 프로토 테이블 셋팅 실패.");
|
||||
SPDLOG_ERROR("Item proto table setup failed.");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -126,13 +126,13 @@ const char* __GetWarType(int n)
|
|||
switch (n)
|
||||
{
|
||||
case 0 :
|
||||
return "패왕";
|
||||
return "\xEF\xBF\xBD\xD0\xBF\xEF\xBF\xBD"; // 패왕
|
||||
case 1 :
|
||||
return "맹장";
|
||||
return "\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD"; // 맹장
|
||||
case 2 :
|
||||
return "수호";
|
||||
return "\xEF\xBF\xBD\xEF\xBF\xBD\xC8\xA3"; // 수호
|
||||
default :
|
||||
return "없는 번호";
|
||||
return "\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD\x20\xEF\xBF\xBD\xEF\xBF\xBD\xC8\xA3"; // 없는 번호
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ void CClientManager::GuildWar(CPeer* peer, TPacketGuildWar* p)
|
|||
|
||||
case GUILD_WAR_WAIT_START:
|
||||
SPDLOG_DEBUG("GuildWar: GUILD_WAR_WAIT_START type({}) guild({} - {})", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
|
||||
case GUILD_WAR_RESERVE: // 길드전 예약
|
||||
case GUILD_WAR_RESERVE: // 길드전 예약
|
||||
if (p->bWar != GUILD_WAR_WAIT_START)
|
||||
SPDLOG_DEBUG("GuildWar: GUILD_WAR_RESERVE type({}) guild({} - {})", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
|
||||
CGuildManager::instance().RemoveDeclare(p->dwGuildFrom, p->dwGuildTo);
|
||||
|
@ -173,21 +173,21 @@ void CClientManager::GuildWar(CPeer* peer, TPacketGuildWar* p)
|
|||
|
||||
break;
|
||||
|
||||
case GUILD_WAR_ON_WAR: // 길드전을 시작 시킨다. (필드전은 바로 시작 됨)
|
||||
case GUILD_WAR_ON_WAR: // 길드전을 시작 시킨다. (필드전은 바로 시작 됨)
|
||||
SPDLOG_DEBUG("GuildWar: GUILD_WAR_ON_WAR type({}) guild({} - {})", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
|
||||
CGuildManager::instance().RemoveDeclare(p->dwGuildFrom, p->dwGuildTo);
|
||||
CGuildManager::instance().StartWar(p->bType, p->dwGuildFrom, p->dwGuildTo);
|
||||
break;
|
||||
|
||||
case GUILD_WAR_OVER: // 길드전 정상 종료
|
||||
case GUILD_WAR_OVER: // 길드전 정상 종료
|
||||
SPDLOG_DEBUG("GuildWar: GUILD_WAR_OVER type({}) guild({} - {})", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
|
||||
CGuildManager::instance().RecvWarOver(p->dwGuildFrom, p->dwGuildTo, p->bType, p->lWarPrice);
|
||||
break;
|
||||
|
||||
case GUILD_WAR_END: // 길드전 비정상 종료
|
||||
case GUILD_WAR_END: // 길드전 비정상 종료
|
||||
SPDLOG_DEBUG("GuildWar: GUILD_WAR_END type({}) guild({} - {})", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
|
||||
CGuildManager::instance().RecvWarEnd(p->dwGuildFrom, p->dwGuildTo);
|
||||
return; // NOTE: RecvWarEnd에서 패킷을 보내므로 따로 브로드캐스팅 하지 않는다.
|
||||
return; // NOTE: RecvWarEnd에서 패킷을 보내므로 따로 브로드캐스팅 하지 않는다.
|
||||
|
||||
case GUILD_WAR_CANCEL :
|
||||
SPDLOG_DEBUG("GuildWar: GUILD_WAR_CANCEL type({}) guild({} - {})", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
|
||||
|
|
|
@ -229,7 +229,7 @@ TAccountTable * CreateAccountTableFromRes(MYSQL_RES * res)
|
|||
TAccountTable * pkTab = new TAccountTable;
|
||||
memset(pkTab, 0, sizeof(TAccountTable));
|
||||
|
||||
// 첫번째 컬럼 것만 참고 한다 (JOIN QUERY를 위한 것 임)
|
||||
// 첫번째 컬럼 것만 참고 한다 (JOIN QUERY를 위한 것 임)
|
||||
strlcpy(input_pwd, row[col++], sizeof(input_pwd));
|
||||
str_to_number(pkTab->id, row[col++]);
|
||||
strlcpy(pkTab->login, row[col++], sizeof(pkTab->login));
|
||||
|
@ -353,7 +353,7 @@ void CClientManager::RESULT_LOGIN(CPeer * peer, SQLMsg * msg)
|
|||
|
||||
if (info->account_index == 0)
|
||||
{
|
||||
// 계정이 없네?
|
||||
// 계정이 없네?
|
||||
if (msg->Get()->uiNumRows == 0)
|
||||
{
|
||||
SPDLOG_DEBUG("RESULT_LOGIN: no account");
|
||||
|
@ -395,14 +395,14 @@ void CClientManager::RESULT_LOGIN(CPeer * peer, SQLMsg * msg)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!info->pAccountTable) // 이럴리는 없겠지만;;
|
||||
if (!info->pAccountTable) // 이럴리는 없겠지만;;
|
||||
{
|
||||
peer->EncodeReturn(HEADER_DG_LOGIN_WRONG_PASSWD, info->dwHandle);
|
||||
delete info;
|
||||
return;
|
||||
}
|
||||
|
||||
// 다른 컨넥션이 이미 로그인 해버렸다면.. 이미 접속했다고 보내야 한다.
|
||||
// 다른 컨넥션이 이미 로그인 해버렸다면.. 이미 접속했다고 보내야 한다.
|
||||
if (!InsertLogonAccount(info->pAccountTable->login, peer->GetHandle(), info->ip))
|
||||
{
|
||||
SPDLOG_DEBUG("RESULT_LOGIN: already logon {}", info->pAccountTable->login);
|
||||
|
|
|
@ -28,7 +28,7 @@ bool CreateItemTableFromRes(MYSQL_RES * res, std::vector<TPlayerItem> * pVec, DW
|
|||
|
||||
int rows;
|
||||
|
||||
if ((rows = mysql_num_rows(res)) <= 0) // 데이터 없음
|
||||
if ((rows = mysql_num_rows(res)) <= 0) // 데이터 없음
|
||||
{
|
||||
pVec->clear();
|
||||
return true;
|
||||
|
@ -155,7 +155,7 @@ size_t CreatePlayerSaveQuery(char * pszQuery, size_t querySize, TPlayerTable * p
|
|||
pkTab->horse.sStamina,
|
||||
pkTab->horse_skill_point);
|
||||
|
||||
// Binary 로 바꾸기 위한 임시 공간
|
||||
// Binary 로 바꾸기 위한 임시 공간
|
||||
char text[8192 + 1];
|
||||
|
||||
CDBManager::instance().EscapeString(text, pkTab->skills, sizeof(pkTab->skills));
|
||||
|
@ -204,7 +204,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
|
|||
TPlayerTable * pTab;
|
||||
|
||||
//
|
||||
// 한 계정에 속한 모든 캐릭터들 캐쉬처리
|
||||
// 한 계정에 속한 모든 캐릭터들 캐쉬처리
|
||||
//
|
||||
CLoginData * pLoginData = GetLoginDataByAID(packet->account_id);
|
||||
|
||||
|
@ -216,12 +216,12 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
|
|||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// 1. 유저정보가 DBCache 에 존재 : DBCache에서
|
||||
// 2. 유저정보가 DBCache 에 없음 : DB에서
|
||||
// 1. 유저정보가 DBCache 에 존재 : DBCache에서
|
||||
// 2. 유저정보가 DBCache 에 없음 : DB에서
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
//----------------------------------
|
||||
// 1. 유저정보가 DBCache 에 존재 : DBCache에서
|
||||
// 1. 유저정보가 DBCache 에 존재 : DBCache에서
|
||||
//----------------------------------
|
||||
if ((c = GetPlayerCache(packet->player_id)))
|
||||
{
|
||||
|
@ -260,13 +260,13 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
|
|||
SPDLOG_DEBUG("[PLAYER_LOAD] ID {} pid {} gold {} ", pTab->name, pTab->id, pTab->gold);
|
||||
|
||||
//--------------------------------------------
|
||||
// 아이템 & AFFECT & QUEST 로딩 :
|
||||
// 아이템 & AFFECT & QUEST 로딩 :
|
||||
//--------------------------------------------
|
||||
// 1) 아이템이 DBCache 에 존재 : DBCache 에서 가져옴
|
||||
// 2) 아이템이 DBCache 에 없음 : DB 에서 가져옴
|
||||
// 1) 아이템이 DBCache 에 존재 : DBCache 에서 가져옴
|
||||
// 2) 아이템이 DBCache 에 없음 : DB 에서 가져옴
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// 1) 아이템이 DBCache 에 존재 : DBCache 에서 가져옴
|
||||
// 1) 아이템이 DBCache 에 존재 : DBCache 에서 가져옴
|
||||
/////////////////////////////////////////////
|
||||
if (pSet)
|
||||
{
|
||||
|
@ -281,7 +281,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
|
|||
CItemCache * c = *it++;
|
||||
TPlayerItem * p = c->Get();
|
||||
|
||||
if (p->vnum) // vnum이 없으면 삭제된 아이템이다.
|
||||
if (p->vnum) // vnum이 없으면 삭제된 아이템이다.
|
||||
memcpy(&s_items[dwCount++], p, sizeof(TPlayerItem));
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
|
|||
CDBManager::instance().ReturnQuery(szQuery, QID_AFFECT, peer->GetHandle(), new ClientHandleInfo(dwHandle));
|
||||
}
|
||||
/////////////////////////////////////////////
|
||||
// 2) 아이템이 DBCache 에 없음 : DB 에서 가져옴
|
||||
// 2) 아이템이 DBCache 에 없음 : DB 에서 가져옴
|
||||
/////////////////////////////////////////////
|
||||
else
|
||||
{
|
||||
|
@ -341,7 +341,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
|
|||
//return;
|
||||
}
|
||||
//----------------------------------
|
||||
// 2. 유저정보가 DBCache 에 없음 : DB에서
|
||||
// 2. 유저정보가 DBCache 에 없음 : DB에서
|
||||
//----------------------------------
|
||||
else
|
||||
{
|
||||
|
@ -350,7 +350,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
|
|||
char queryStr[QUERY_MAX_LEN];
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// 캐릭터 정보 얻어오기 : 무조건 DB에서
|
||||
// 캐릭터 정보 얻어오기 : 무조건 DB에서
|
||||
//--------------------------------------------------------------
|
||||
snprintf(queryStr, sizeof(queryStr),
|
||||
"SELECT "
|
||||
|
@ -366,7 +366,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
|
|||
CDBManager::instance().ReturnQuery(queryStr, QID_PLAYER, peer->GetHandle(), pkInfo);
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// 아이템 가져오기
|
||||
// 아이템 가져오기
|
||||
//--------------------------------------------------------------
|
||||
snprintf(queryStr, sizeof(queryStr),
|
||||
"SELECT id,window+0,pos,count,vnum,socket0,socket1,socket2,attrtype0,attrvalue0,attrtype1,attrvalue1,attrtype2,attrvalue2,attrtype3,attrvalue3,attrtype4,attrvalue4,attrtype5,attrvalue5,attrtype6,attrvalue6 "
|
||||
|
@ -375,15 +375,15 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
|
|||
CDBManager::instance().ReturnQuery(queryStr, QID_ITEM, peer->GetHandle(), new ClientHandleInfo(dwHandle, packet->player_id));
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// QUEST 가져오기
|
||||
// QUEST 가져오기
|
||||
//--------------------------------------------------------------
|
||||
snprintf(queryStr, sizeof(queryStr),
|
||||
"SELECT dwPID,szName,szState,lValue FROM quest%s WHERE dwPID=%d",
|
||||
GetTablePostfix(), packet->player_id);
|
||||
CDBManager::instance().ReturnQuery(queryStr, QID_QUEST, peer->GetHandle(), new ClientHandleInfo(dwHandle, packet->player_id,packet->account_id));
|
||||
//독일 선물 기능에서 item_award테이블에서 login 정보를 얻기위해 account id도 넘겨준다
|
||||
//독일 선물 기능에서 item_award테이블에서 login 정보를 얻기위해 account id도 넘겨준다
|
||||
//--------------------------------------------------------------
|
||||
// AFFECT 가져오기
|
||||
// AFFECT 가져오기
|
||||
//--------------------------------------------------------------
|
||||
snprintf(queryStr, sizeof(queryStr),
|
||||
"SELECT dwPID,bType,bApplyOn,lApplyValue,dwFlag,lDuration,lSPCost FROM affect%s WHERE dwPID=%d",
|
||||
|
@ -400,21 +400,21 @@ void CClientManager::ItemAward(CPeer * peer,char* login)
|
|||
std::set<TItemAward *> * pSet = ItemAwardManager::instance().GetByLogin(login_t);
|
||||
if(pSet == NULL)
|
||||
return;
|
||||
typeof(pSet->begin()) it = pSet->begin(); //taken_time이 NULL인것들 읽어옴
|
||||
typeof(pSet->begin()) it = pSet->begin(); //taken_time이 NULL인것들 읽어옴
|
||||
while(it != pSet->end() )
|
||||
{
|
||||
TItemAward * pItemAward = *(it++);
|
||||
char* whyStr = pItemAward->szWhy; //why 콜룸 읽기
|
||||
char cmdStr[100] = ""; //why콜룸에서 읽은 값을 임시 문자열에 복사해둠
|
||||
strcpy(cmdStr,whyStr); //명령어 얻는 과정에서 토큰쓰면 원본도 토큰화 되기 때문
|
||||
char* whyStr = pItemAward->szWhy; //why 콜룸 읽기
|
||||
char cmdStr[100] = ""; //why콜룸에서 읽은 값을 임시 문자열에 복사해둠
|
||||
strcpy(cmdStr,whyStr); //명령어 얻는 과정에서 토큰쓰면 원본도 토큰화 되기 때문
|
||||
char command[20] = "";
|
||||
strcpy(command,GetCommand(cmdStr).c_str()); // command 얻기
|
||||
if( !(strcmp(command,"GIFT") )) // command 가 GIFT이면
|
||||
strcpy(command,GetCommand(cmdStr).c_str()); // command 얻기
|
||||
if( !(strcmp(command,"GIFT") )) // command 가 GIFT이면
|
||||
{
|
||||
TPacketItemAwardInfromer giftData;
|
||||
strcpy(giftData.login, pItemAward->szLogin); //로그인 아이디 복사
|
||||
strcpy(giftData.command, command); //명령어 복사
|
||||
giftData.vnum = pItemAward->dwVnum; //아이템 vnum도 복사
|
||||
strcpy(giftData.login, pItemAward->szLogin); //로그인 아이디 복사
|
||||
strcpy(giftData.command, command); //명령어 복사
|
||||
giftData.vnum = pItemAward->dwVnum; //아이템 vnum도 복사
|
||||
ForwardPacket(HEADER_DG_ITEMAWARD_INFORMER,&giftData,sizeof(TPacketItemAwardInfromer));
|
||||
}
|
||||
}
|
||||
|
@ -435,7 +435,7 @@ std::string CClientManager::GetCommand(char* str)
|
|||
|
||||
bool CreatePlayerTableFromRes(MYSQL_RES * res, TPlayerTable * pkTab)
|
||||
{
|
||||
if (mysql_num_rows(res) == 0) // 데이터 없음
|
||||
if (mysql_num_rows(res) == 0) // 데이터 없음
|
||||
return false;
|
||||
|
||||
memset(pkTab, 0, sizeof(TPlayerTable));
|
||||
|
@ -515,11 +515,11 @@ bool CreatePlayerTableFromRes(MYSQL_RES * res, TPlayerTable * pkTab)
|
|||
int max_point = pkTab->level - 9;
|
||||
|
||||
int skill_point =
|
||||
std::min<int>(20, pkTab->skills[121].bLevel) + // SKILL_LEADERSHIP 통솔력
|
||||
std::min<int>(20, pkTab->skills[124].bLevel) + // SKILL_MINING 채광
|
||||
std::min<int>(10, pkTab->skills[131].bLevel) + // SKILL_HORSE_SUMMON 말소환
|
||||
std::min<int>(20, pkTab->skills[141].bLevel) + // SKILL_ADD_HP HP보강
|
||||
std::min<int>(20, pkTab->skills[142].bLevel); // SKILL_RESIST_PENETRATE 관통저항
|
||||
std::min<int>(20, pkTab->skills[121].bLevel) + // SKILL_LEADERSHIP 통솔력
|
||||
std::min<int>(20, pkTab->skills[124].bLevel) + // SKILL_MINING 채광
|
||||
std::min<int>(10, pkTab->skills[131].bLevel) + // SKILL_HORSE_SUMMON 말소환
|
||||
std::min<int>(20, pkTab->skills[141].bLevel) + // SKILL_ADD_HP HP보강
|
||||
std::min<int>(20, pkTab->skills[142].bLevel); // SKILL_RESIST_PENETRATE 관통저항
|
||||
|
||||
pkTab->sub_skill_point = max_point - skill_point;
|
||||
}
|
||||
|
@ -559,13 +559,13 @@ void CClientManager::RESULT_COMPOSITE_PLAYER(CPeer * peer, SQLMsg * pMsg, DWORD
|
|||
{
|
||||
SPDLOG_DEBUG("QID_QUEST {}", info->dwHandle);
|
||||
RESULT_QUEST_LOAD(peer, pSQLResult, info->dwHandle, info->player_id);
|
||||
//aid얻기
|
||||
//aid얻기
|
||||
ClientHandleInfo* temp1 = info.get();
|
||||
if (temp1 == NULL)
|
||||
break;
|
||||
|
||||
CLoginData* pLoginData1 = GetLoginDataByAID(temp1->account_id); //
|
||||
//독일 선물 기능
|
||||
//독일 선물 기능
|
||||
if( pLoginData1->GetAccountRef().login == NULL)
|
||||
break;
|
||||
if( pLoginData1 == NULL )
|
||||
|
@ -655,14 +655,14 @@ void CClientManager::RESULT_PLAYER_LOAD(CPeer * peer, MYSQL_RES * pRes, ClientHa
|
|||
void CClientManager::RESULT_ITEM_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwHandle, DWORD dwPID)
|
||||
{
|
||||
static std::vector<TPlayerItem> s_items;
|
||||
//DB에서 아이템 정보를 읽어온다.
|
||||
//DB에서 아이템 정보를 읽어온다.
|
||||
CreateItemTableFromRes(pRes, &s_items, dwPID);
|
||||
DWORD dwCount = s_items.size();
|
||||
|
||||
peer->EncodeHeader(HEADER_DG_ITEM_LOAD, dwHandle, sizeof(DWORD) + sizeof(TPlayerItem) * dwCount);
|
||||
peer->EncodeDWORD(dwCount);
|
||||
|
||||
//CacheSet을 만든다
|
||||
//CacheSet을 만든다
|
||||
CreateItemCacheSet(dwPID);
|
||||
|
||||
// ITEM_LOAD_LOG_ATTACH_PID
|
||||
|
@ -674,7 +674,7 @@ void CClientManager::RESULT_ITEM_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwHa
|
|||
peer->Encode(&s_items[0], sizeof(TPlayerItem) * dwCount);
|
||||
|
||||
for (DWORD i = 0; i < dwCount; ++i)
|
||||
PutItemCache(&s_items[i], true); // 로드한 것은 따로 저장할 필요 없으므로, 인자 bSkipQuery에 true를 넣는다.
|
||||
PutItemCache(&s_items[i], true); // 로드한 것은 따로 저장할 필요 없으므로, 인자 bSkipQuery에 true를 넣는다.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -682,7 +682,7 @@ void CClientManager::RESULT_AFFECT_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dw
|
|||
{
|
||||
int iNumRows;
|
||||
|
||||
if ((iNumRows = mysql_num_rows(pRes)) == 0) // 데이터 없음
|
||||
if ((iNumRows = mysql_num_rows(pRes)) == 0) // 데이터 없음
|
||||
return;
|
||||
|
||||
static std::vector<TPacketAffectElement> s_elements;
|
||||
|
@ -778,7 +778,7 @@ void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerC
|
|||
int queryLen;
|
||||
DWORD player_id;
|
||||
|
||||
// 한 계정에 X초 내로 캐릭터 생성을 할 수 없다.
|
||||
// 한 계정에 X초 내로 캐릭터 생성을 할 수 없다.
|
||||
auto it = s_createTimeByAccountID.find(packet->account_id);
|
||||
|
||||
if (it != s_createTimeByAccountID.end())
|
||||
|
@ -1007,7 +1007,7 @@ void CClientManager::__QUERY_PLAYER_DELETE(CPeer* peer, DWORD dwHandle, TPlayerD
|
|||
}
|
||||
|
||||
//
|
||||
// @version 05/06/10 Bang2ni - 플레이어 삭제시 가격정보 리스트 삭제 추가.
|
||||
// @version 05/06/10 Bang2ni - 플레이어 삭제시 가격정보 리스트 삭제 추가.
|
||||
//
|
||||
void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
|
||||
{
|
||||
|
@ -1058,14 +1058,14 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
|
|||
return;
|
||||
}
|
||||
|
||||
// 삭제 성공
|
||||
// 삭제 성공
|
||||
SPDLOG_DEBUG("PLAYER_DELETE SUCCESS {}", dwPID);
|
||||
|
||||
char account_index_string[16];
|
||||
|
||||
snprintf(account_index_string, sizeof(account_index_string), "player_id%d", m_iPlayerIDStart + pi->account_index);
|
||||
|
||||
// 플레이어 테이블을 캐쉬에서 삭제한다.
|
||||
// 플레이어 테이블을 캐쉬에서 삭제한다.
|
||||
CPlayerTableCache * pkPlayerCache = GetPlayerCache(pi->player_id);
|
||||
|
||||
if (pkPlayerCache)
|
||||
|
@ -1074,7 +1074,7 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
|
|||
delete pkPlayerCache;
|
||||
}
|
||||
|
||||
// 아이템들을 캐쉬에서 삭제한다.
|
||||
// 아이템들을 캐쉬에서 삭제한다.
|
||||
TItemCacheSet * pSet = GetItemCacheSet(pi->player_id);
|
||||
|
||||
if (pSet)
|
||||
|
@ -1137,7 +1137,7 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
|
|||
}
|
||||
else
|
||||
{
|
||||
// 삭제 실패
|
||||
// 삭제 실패
|
||||
SPDLOG_DEBUG("PLAYER_DELETE FAIL NO ROW");
|
||||
peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
|
||||
peer->EncodeBYTE(pi->account_index);
|
||||
|
@ -1195,10 +1195,10 @@ void CClientManager::InsertLogoutPlayer(DWORD pid)
|
|||
{
|
||||
TLogoutPlayerMap::iterator it = m_map_logout.find(pid);
|
||||
|
||||
// 존재하지 않을경우 추가
|
||||
// 존재하지 않을경우 추가
|
||||
if (it != m_map_logout.end())
|
||||
{
|
||||
// 존재할경우 시간만 갱신
|
||||
// 존재할경우 시간만 갱신
|
||||
SPDLOG_TRACE("LOGOUT: Update player time pid({})", pid);
|
||||
|
||||
it->second->time = time(0);
|
||||
|
|
|
@ -67,7 +67,7 @@ bool CConfig::GetWord(FILE *fp, char *tar)
|
|||
|
||||
if ((c == ' ' || c == '\t' || c == '\n'))
|
||||
{
|
||||
// 텝.
|
||||
// 텝.
|
||||
tar[i] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ bool CConfig::LoadFile(const char* filename)
|
|||
}
|
||||
|
||||
|
||||
// 파일 닫는 부분.
|
||||
// 파일 닫는 부분.
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -11,14 +11,14 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
/// 파싱용 state 열거값
|
||||
/// 파싱용 state 열거값
|
||||
enum ParseState
|
||||
{
|
||||
STATE_NORMAL = 0, ///< 일반 상태
|
||||
STATE_QUOTE ///< 따옴표 뒤의 상태
|
||||
STATE_NORMAL = 0, ///< 일반 상태
|
||||
STATE_QUOTE ///< 따옴표 뒤의 상태
|
||||
};
|
||||
|
||||
/// 문자열 좌우의 공백을 제거해서 반환한다.
|
||||
/// 문자열 좌우의 공백을 제거해서 반환한다.
|
||||
std::string Trim(std::string str)
|
||||
{
|
||||
str = str.erase(str.find_last_not_of(" \t\r\n") + 1);
|
||||
|
@ -26,7 +26,7 @@ namespace
|
|||
return str;
|
||||
}
|
||||
|
||||
/// \brief 주어진 문장에 있는 알파벳을 모두 소문자로 바꾼다.
|
||||
/// \brief 주어진 문장에 있는 알파벳을 모두 소문자로 바꾼다.
|
||||
std::string Lower(std::string original)
|
||||
{
|
||||
std::transform(original.begin(), original.end(), original.begin(), tolower);
|
||||
|
@ -35,9 +35,9 @@ namespace
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 셀을 액세스할 때, 숫자 대신 사용할 이름을 등록한다.
|
||||
/// \param name 셀 이름
|
||||
/// \param index 셀 인덱스
|
||||
/// \brief 셀을 액세스할 때, 숫자 대신 사용할 이름을 등록한다.
|
||||
/// \param name 셀 이름
|
||||
/// \param index 셀 인덱스
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void cCsvAlias::AddAlias(const char* name, size_t index)
|
||||
{
|
||||
|
@ -51,7 +51,7 @@ void cCsvAlias::AddAlias(const char* name, size_t index)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 모든 데이터를 삭제한다.
|
||||
/// \brief 모든 데이터를 삭제한다.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void cCsvAlias::Destroy()
|
||||
{
|
||||
|
@ -60,9 +60,9 @@ void cCsvAlias::Destroy()
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 숫자 인덱스를 이름으로 변환한다.
|
||||
/// \param index 숫자 인덱스
|
||||
/// \return const char* 이름
|
||||
/// \brief 숫자 인덱스를 이름으로 변환한다.
|
||||
/// \param index 숫자 인덱스
|
||||
/// \return const char* 이름
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const char* cCsvAlias::operator [] (size_t index) const
|
||||
{
|
||||
|
@ -78,9 +78,9 @@ const char* cCsvAlias::operator [] (size_t index) const
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 이름을 숫자 인덱스로 변환한다.
|
||||
/// \param name 이름
|
||||
/// \return size_t 숫자 인덱스
|
||||
/// \brief 이름을 숫자 인덱스로 변환한다.
|
||||
/// \param name 이름
|
||||
/// \return size_t 숫자 인덱스
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
size_t cCsvAlias::operator [] (const char* name) const
|
||||
{
|
||||
|
@ -96,11 +96,11 @@ size_t cCsvAlias::operator [] (const char* name) const
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 지정된 이름의 CSV 파일을 로드한다.
|
||||
/// \param fileName CSV 파일 이름
|
||||
/// \param seperator 필드 분리자로 사용할 글자. 기본값은 ','이다.
|
||||
/// \param quote 따옴표로 사용할 글자. 기본값은 '"'이다.
|
||||
/// \return bool 무사히 로드했다면 true, 아니라면 false
|
||||
/// \brief 지정된 이름의 CSV 파일을 로드한다.
|
||||
/// \param fileName CSV 파일 이름
|
||||
/// \param seperator 필드 분리자로 사용할 글자. 기본값은 ','이다.
|
||||
/// \param quote 따옴표로 사용할 글자. 기본값은 '"'이다.
|
||||
/// \return bool 무사히 로드했다면 true, 아니라면 false
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool cCsvFile::Load(const char* fileName, const char seperator, const char quote)
|
||||
{
|
||||
|
@ -109,7 +109,7 @@ bool cCsvFile::Load(const char* fileName, const char seperator, const char quote
|
|||
std::ifstream file(fileName, std::ios::in);
|
||||
if (!file) return false;
|
||||
|
||||
Destroy(); // 기존의 데이터를 삭제
|
||||
Destroy(); // 기존의 데이터를 삭제
|
||||
|
||||
cCsvRow* row = NULL;
|
||||
ParseState state = STATE_NORMAL;
|
||||
|
@ -124,33 +124,33 @@ bool cCsvFile::Load(const char* fileName, const char seperator, const char quote
|
|||
std::string line(Trim(buf));
|
||||
if (line.empty() || (state == STATE_NORMAL && line[0] == '#')) continue;
|
||||
|
||||
std::string text = std::string(line) + " "; // 파싱 lookahead 때문에 붙여준다.
|
||||
std::string text = std::string(line) + " "; // 파싱 lookahead 때문에 붙여준다.
|
||||
size_t cur = 0;
|
||||
|
||||
while (cur < text.size())
|
||||
{
|
||||
// 현재 모드가 QUOTE 모드일 때,
|
||||
// 현재 모드가 QUOTE 모드일 때,
|
||||
if (state == STATE_QUOTE)
|
||||
{
|
||||
// '"' 문자의 종류는 두 가지이다.
|
||||
// 1. 셀 내부에 특수 문자가 있을 경우 이를 알리는 셀 좌우의 것
|
||||
// 2. 셀 내부의 '"' 문자가 '"' 2개로 치환된 것
|
||||
// 이 중 첫번째 경우의 좌측에 있는 것은 CSV 파일이 정상적이라면,
|
||||
// 무조건 STATE_NORMAL에 걸리게 되어있다.
|
||||
// 그러므로 여기서 걸리는 것은 1번의 우측 경우나, 2번 경우 뿐이다.
|
||||
// 2번의 경우에는 무조건 '"' 문자가 2개씩 나타난다. 하지만 1번의
|
||||
// 우측 경우에는 아니다. 이를 바탕으로 해서 코드를 짜면...
|
||||
// '"' 문자의 종류는 두 가지이다.
|
||||
// 1. 셀 내부에 특수 문자가 있을 경우 이를 알리는 셀 좌우의 것
|
||||
// 2. 셀 내부의 '"' 문자가 '"' 2개로 치환된 것
|
||||
// 이 중 첫번째 경우의 좌측에 있는 것은 CSV 파일이 정상적이라면,
|
||||
// 무조건 STATE_NORMAL에 걸리게 되어있다.
|
||||
// 그러므로 여기서 걸리는 것은 1번의 우측 경우나, 2번 경우 뿐이다.
|
||||
// 2번의 경우에는 무조건 '"' 문자가 2개씩 나타난다. 하지만 1번의
|
||||
// 우측 경우에는 아니다. 이를 바탕으로 해서 코드를 짜면...
|
||||
if (text[cur] == quote)
|
||||
{
|
||||
// 다음 문자가 '"' 문자라면, 즉 연속된 '"' 문자라면
|
||||
// 이는 셀 내부의 '"' 문자가 치환된 것이다.
|
||||
// 다음 문자가 '"' 문자라면, 즉 연속된 '"' 문자라면
|
||||
// 이는 셀 내부의 '"' 문자가 치환된 것이다.
|
||||
if (text[cur+1] == quote)
|
||||
{
|
||||
token += quote;
|
||||
++cur;
|
||||
}
|
||||
// 다음 문자가 '"' 문자가 아니라면
|
||||
// 현재의 '"'문자는 셀의 끝을 알리는 문자라고 할 수 있다.
|
||||
// 다음 문자가 '"' 문자가 아니라면
|
||||
// 현재의 '"'문자는 셀의 끝을 알리는 문자라고 할 수 있다.
|
||||
else
|
||||
{
|
||||
state = STATE_NORMAL;
|
||||
|
@ -161,25 +161,25 @@ bool cCsvFile::Load(const char* fileName, const char seperator, const char quote
|
|||
token += text[cur];
|
||||
}
|
||||
}
|
||||
// 현재 모드가 NORMAL 모드일 때,
|
||||
// 현재 모드가 NORMAL 모드일 때,
|
||||
else if (state == STATE_NORMAL)
|
||||
{
|
||||
if (row == NULL)
|
||||
row = new cCsvRow();
|
||||
|
||||
// ',' 문자를 만났다면 셀의 끝의 의미한다.
|
||||
// 토큰으로서 셀 리스트에다가 집어넣고, 토큰을 초기화한다.
|
||||
// ',' 문자를 만났다면 셀의 끝의 의미한다.
|
||||
// 토큰으로서 셀 리스트에다가 집어넣고, 토큰을 초기화한다.
|
||||
if (text[cur] == seperator)
|
||||
{
|
||||
row->push_back(token);
|
||||
token.clear();
|
||||
}
|
||||
// '"' 문자를 만났다면, QUOTE 모드로 전환한다.
|
||||
// '"' 문자를 만났다면, QUOTE 모드로 전환한다.
|
||||
else if (text[cur] == quote)
|
||||
{
|
||||
state = STATE_QUOTE;
|
||||
}
|
||||
// 다른 일반 문자라면 현재 토큰에다가 덧붙인다.
|
||||
// 다른 일반 문자라면 현재 토큰에다가 덧붙인다.
|
||||
else
|
||||
{
|
||||
token += text[cur];
|
||||
|
@ -189,8 +189,8 @@ bool cCsvFile::Load(const char* fileName, const char seperator, const char quote
|
|||
++cur;
|
||||
}
|
||||
|
||||
// 마지막 셀은 끝에 ',' 문자가 없기 때문에 여기서 추가해줘야한다.
|
||||
// 단, 처음에 파싱 lookahead 때문에 붙인 스페이스 문자 두 개를 뗀다.
|
||||
// 마지막 셀은 끝에 ',' 문자가 없기 때문에 여기서 추가해줘야한다.
|
||||
// 단, 처음에 파싱 lookahead 때문에 붙인 스페이스 문자 두 개를 뗀다.
|
||||
if (state == STATE_NORMAL)
|
||||
{
|
||||
Assert(row != NULL);
|
||||
|
@ -209,49 +209,49 @@ bool cCsvFile::Load(const char* fileName, const char seperator, const char quote
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 가지고 있는 내용을 CSV 파일에다 저장한다.
|
||||
/// \param fileName CSV 파일 이름
|
||||
/// \param append true일 경우, 기존의 파일에다 덧붙인다. false인 경우에는
|
||||
/// 기존의 파일 내용을 삭제하고, 새로 쓴다.
|
||||
/// \param seperator 필드 분리자로 사용할 글자. 기본값은 ','이다.
|
||||
/// \param quote 따옴표로 사용할 글자. 기본값은 '"'이다.
|
||||
/// \return bool 무사히 저장했다면 true, 에러가 생긴 경우에는 false
|
||||
/// \brief 가지고 있는 내용을 CSV 파일에다 저장한다.
|
||||
/// \param fileName CSV 파일 이름
|
||||
/// \param append true일 경우, 기존의 파일에다 덧붙인다. false인 경우에는
|
||||
/// 기존의 파일 내용을 삭제하고, 새로 쓴다.
|
||||
/// \param seperator 필드 분리자로 사용할 글자. 기본값은 ','이다.
|
||||
/// \param quote 따옴표로 사용할 글자. 기본값은 '"'이다.
|
||||
/// \return bool 무사히 저장했다면 true, 에러가 생긴 경우에는 false
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool cCsvFile::Save(const char* fileName, bool append, char seperator, char quote) const
|
||||
{
|
||||
Assert(seperator != quote);
|
||||
|
||||
// 출력 모드에 따라 파일을 적당한 플래그로 생성한다.
|
||||
// 출력 모드에 따라 파일을 적당한 플래그로 생성한다.
|
||||
std::ofstream file;
|
||||
if (append) { file.open(fileName, std::ios::out | std::ios::app); }
|
||||
else { file.open(fileName, std::ios::out | std::ios::trunc); }
|
||||
|
||||
// 파일을 열지 못했다면, false를 리턴한다.
|
||||
// 파일을 열지 못했다면, false를 리턴한다.
|
||||
if (!file) return false;
|
||||
|
||||
char special_chars[5] = { seperator, quote, '\r', '\n', 0 };
|
||||
char quote_escape_string[3] = { quote, quote, 0 };
|
||||
|
||||
// 모든 행을 횡단하면서...
|
||||
// 모든 행을 횡단하면서...
|
||||
for (size_t i=0; i<m_Rows.size(); i++)
|
||||
{
|
||||
const cCsvRow& row = *((*this)[i]);
|
||||
|
||||
std::string line;
|
||||
|
||||
// 행 안의 모든 토큰을 횡단하면서...
|
||||
// 행 안의 모든 토큰을 횡단하면서...
|
||||
for (size_t j=0; j<row.size(); j++)
|
||||
{
|
||||
const std::string& token = row[j];
|
||||
|
||||
// 일반적인('"' 또는 ','를 포함하지 않은)
|
||||
// 토큰이라면 그냥 저장하면 된다.
|
||||
// 일반적인('"' 또는 ','를 포함하지 않은)
|
||||
// 토큰이라면 그냥 저장하면 된다.
|
||||
if (token.find_first_of(special_chars) == std::string::npos)
|
||||
{
|
||||
line += token;
|
||||
}
|
||||
// 특수문자를 포함한 토큰이라면 문자열 좌우에 '"'를 붙여주고,
|
||||
// 문자열 내부의 '"'를 두 개로 만들어줘야한다.
|
||||
// 특수문자를 포함한 토큰이라면 문자열 좌우에 '"'를 붙여주고,
|
||||
// 문자열 내부의 '"'를 두 개로 만들어줘야한다.
|
||||
else
|
||||
{
|
||||
line += quote;
|
||||
|
@ -265,11 +265,11 @@ bool cCsvFile::Save(const char* fileName, bool append, char seperator, char quot
|
|||
line += quote;
|
||||
}
|
||||
|
||||
// 마지막 셀이 아니라면 ','를 토큰의 뒤에다 붙여줘야한다.
|
||||
// 마지막 셀이 아니라면 ','를 토큰의 뒤에다 붙여줘야한다.
|
||||
if (j != row.size() - 1) { line += seperator; }
|
||||
}
|
||||
|
||||
// 라인을 출력한다.
|
||||
// 라인을 출력한다.
|
||||
file << line << std::endl;
|
||||
}
|
||||
|
||||
|
@ -277,7 +277,7 @@ bool cCsvFile::Save(const char* fileName, bool append, char seperator, char quot
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 모든 데이터를 메모리에서 삭제한다.
|
||||
/// \brief 모든 데이터를 메모리에서 삭제한다.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void cCsvFile::Destroy()
|
||||
{
|
||||
|
@ -288,9 +288,9 @@ void cCsvFile::Destroy()
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 해당하는 인덱스의 행을 반환한다.
|
||||
/// \param index 인덱스
|
||||
/// \return cCsvRow* 해당 행
|
||||
/// \brief 해당하는 인덱스의 행을 반환한다.
|
||||
/// \param index 인덱스
|
||||
/// \return cCsvRow* 해당 행
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
cCsvRow* cCsvFile::operator [] (size_t index)
|
||||
{
|
||||
|
@ -299,9 +299,9 @@ cCsvRow* cCsvFile::operator [] (size_t index)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 해당하는 인덱스의 행을 반환한다.
|
||||
/// \param index 인덱스
|
||||
/// \return const cCsvRow* 해당 행
|
||||
/// \brief 해당하는 인덱스의 행을 반환한다.
|
||||
/// \param index 인덱스
|
||||
/// \return const cCsvRow* 해당 행
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const cCsvRow* cCsvFile::operator [] (size_t index) const
|
||||
{
|
||||
|
@ -310,7 +310,7 @@ const cCsvRow* cCsvFile::operator [] (size_t index) const
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 생성자
|
||||
/// \brief 생성자
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
cCsvTable::cCsvTable()
|
||||
: m_CurRow(-1)
|
||||
|
@ -318,18 +318,18 @@ cCsvTable::cCsvTable()
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 소멸자
|
||||
/// \brief 소멸자
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
cCsvTable::~cCsvTable()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 지정된 이름의 CSV 파일을 로드한다.
|
||||
/// \param fileName CSV 파일 이름
|
||||
/// \param seperator 필드 분리자로 사용할 글자. 기본값은 ','이다.
|
||||
/// \param quote 따옴표로 사용할 글자. 기본값은 '"'이다.
|
||||
/// \return bool 무사히 로드했다면 true, 아니라면 false
|
||||
/// \brief 지정된 이름의 CSV 파일을 로드한다.
|
||||
/// \param fileName CSV 파일 이름
|
||||
/// \param seperator 필드 분리자로 사용할 글자. 기본값은 ','이다.
|
||||
/// \param quote 따옴표로 사용할 글자. 기본값은 '"'이다.
|
||||
/// \return bool 무사히 로드했다면 true, 아니라면 false
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool cCsvTable::Load(const char* fileName, const char seperator, const char quote)
|
||||
{
|
||||
|
@ -338,19 +338,19 @@ bool cCsvTable::Load(const char* fileName, const char seperator, const char quot
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 다음 행으로 넘어간다.
|
||||
/// \return bool 다음 행으로 무사히 넘어간 경우 true를 반환하고, 더 이상
|
||||
/// 넘어갈 행이 존재하지 않는 경우에는 false를 반환한다.
|
||||
/// \brief 다음 행으로 넘어간다.
|
||||
/// \return bool 다음 행으로 무사히 넘어간 경우 true를 반환하고, 더 이상
|
||||
/// 넘어갈 행이 존재하지 않는 경우에는 false를 반환한다.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool cCsvTable::Next()
|
||||
{
|
||||
// 20억번 정도 호출하면 오버플로가 일어날텐데...괜찮겠지?
|
||||
// 20억번 정도 호출하면 오버플로가 일어날텐데...괜찮겠지?
|
||||
return ++m_CurRow < (int)m_File.GetRowCount() ? true : false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 현재 행의 셀 숫자를 반환한다.
|
||||
/// \return size_t 현재 행의 셀 숫자
|
||||
/// \brief 현재 행의 셀 숫자를 반환한다.
|
||||
/// \return size_t 현재 행의 셀 숫자
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
size_t cCsvTable::ColCount() const
|
||||
{
|
||||
|
@ -358,9 +358,9 @@ size_t cCsvTable::ColCount() const
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 인덱스를 이용해 int 형으로 셀 값을 반환한다.
|
||||
/// \param index 셀 인덱스
|
||||
/// \return int 셀 값
|
||||
/// \brief 인덱스를 이용해 int 형으로 셀 값을 반환한다.
|
||||
/// \param index 셀 인덱스
|
||||
/// \return int 셀 값
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int cCsvTable::AsInt(size_t index) const
|
||||
{
|
||||
|
@ -371,9 +371,9 @@ int cCsvTable::AsInt(size_t index) const
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 인덱스를 이용해 double 형으로 셀 값을 반환한다.
|
||||
/// \param index 셀 인덱스
|
||||
/// \return double 셀 값
|
||||
/// \brief 인덱스를 이용해 double 형으로 셀 값을 반환한다.
|
||||
/// \param index 셀 인덱스
|
||||
/// \return double 셀 값
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
double cCsvTable::AsDouble(size_t index) const
|
||||
{
|
||||
|
@ -384,9 +384,9 @@ double cCsvTable::AsDouble(size_t index) const
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 인덱스를 이용해 std::string 형으로 셀 값을 반환한다.
|
||||
/// \param index 셀 인덱스
|
||||
/// \return const char* 셀 값
|
||||
/// \brief 인덱스를 이용해 std::string 형으로 셀 값을 반환한다.
|
||||
/// \param index 셀 인덱스
|
||||
/// \return const char* 셀 값
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const char* cCsvTable::AsStringByIndex(size_t index) const
|
||||
{
|
||||
|
@ -397,7 +397,7 @@ const char* cCsvTable::AsStringByIndex(size_t index) const
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief alias를 포함해 모든 데이터를 삭제한다.
|
||||
/// \brief alias를 포함해 모든 데이터를 삭제한다.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void cCsvTable::Destroy()
|
||||
{
|
||||
|
@ -407,10 +407,10 @@ void cCsvTable::Destroy()
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief 현재 행을 반환한다.
|
||||
/// \return const cCsvRow* 액세스가 가능한 현재 행이 존재하는 경우에는 그 행의
|
||||
/// 포인터를 반환하고, 더 이상 액세스 가능한 행이 없는 경우에는 NULL을
|
||||
/// 반환한다.
|
||||
/// \brief 현재 행을 반환한다.
|
||||
/// \return const cCsvRow* 액세스가 가능한 현재 행이 존재하는 경우에는 그 행의
|
||||
/// 포인터를 반환하고, 더 이상 액세스 가능한 행이 없는 경우에는 NULL을
|
||||
/// 반환한다.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const cCsvRow* const cCsvTable::CurRow() const
|
||||
{
|
||||
|
|
|
@ -12,28 +12,28 @@
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \class cCsvAlias
|
||||
/// \brief CSV 파일을 수정했을 때 발생하는 인덱스 문제를 줄이기 위한
|
||||
/// 별명 객체.
|
||||
/// \brief CSV 파일을 수정했을 때 발생하는 인덱스 문제를 줄이기 위한
|
||||
/// 별명 객체.
|
||||
///
|
||||
/// 예를 들어 0번 컬럼이 A에 관한 내용을 포함하고, 1번 컬럼이 B에 관한 내용을
|
||||
/// 포함하고 있었는데...
|
||||
/// 예를 들어 0번 컬럼이 A에 관한 내용을 포함하고, 1번 컬럼이 B에 관한 내용을
|
||||
/// 포함하고 있었는데...
|
||||
///
|
||||
/// <pre>
|
||||
/// int a = row.AsInt(0);
|
||||
/// int b = row.AsInt(1);
|
||||
/// </pre>
|
||||
///
|
||||
/// 그 사이에 C에 관한 내용을 포함하는 컬럼이 끼어든 경우, 하드코딩되어 있는
|
||||
/// 1번을 찾아서 고쳐야 하는데, 상당히 에러가 발생하기 쉬운 작업이다.
|
||||
/// 그 사이에 C에 관한 내용을 포함하는 컬럼이 끼어든 경우, 하드코딩되어 있는
|
||||
/// 1번을 찾아서 고쳐야 하는데, 상당히 에러가 발생하기 쉬운 작업이다.
|
||||
///
|
||||
/// <pre>
|
||||
/// int a = row.AsInt(0);
|
||||
/// int c = row.AsInt(1);
|
||||
/// int b = row.AsInt(2); <-- 이 부분을 일일이 신경써야 한다.
|
||||
/// int b = row.AsInt(2); <-- 이 부분을 일일이 신경써야 한다.
|
||||
/// </pre>
|
||||
///
|
||||
/// 이 부분을 문자열로 처리하면 유지보수에 들어가는 수고를 약간이나마 줄일 수
|
||||
/// 있다.
|
||||
/// 이 부분을 문자열로 처리하면 유지보수에 들어가는 수고를 약간이나마 줄일 수
|
||||
/// 있다.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class cCsvAlias
|
||||
|
@ -47,51 +47,51 @@ private:
|
|||
typedef std::map<size_t, std::string> INDEX2NAME_MAP;
|
||||
#endif
|
||||
|
||||
NAME2INDEX_MAP m_Name2Index; ///< 셀 인덱스 대신으로 사용하기 위한 이름들
|
||||
INDEX2NAME_MAP m_Index2Name; ///< 잘못된 alias를 검사하기 위한 추가적인 맵
|
||||
NAME2INDEX_MAP m_Name2Index; ///< 셀 인덱스 대신으로 사용하기 위한 이름들
|
||||
INDEX2NAME_MAP m_Index2Name; ///< 잘못된 alias를 검사하기 위한 추가적인 맵
|
||||
|
||||
|
||||
public:
|
||||
/// \brief 생성자
|
||||
/// \brief 생성자
|
||||
cCsvAlias() {}
|
||||
|
||||
/// \brief 소멸자
|
||||
/// \brief 소멸자
|
||||
virtual ~cCsvAlias() {}
|
||||
|
||||
|
||||
public:
|
||||
/// \brief 셀을 액세스할 때, 숫자 대신 사용할 이름을 등록한다.
|
||||
/// \brief 셀을 액세스할 때, 숫자 대신 사용할 이름을 등록한다.
|
||||
void AddAlias(const char* name, size_t index);
|
||||
|
||||
/// \brief 모든 데이터를 삭제한다.
|
||||
/// \brief 모든 데이터를 삭제한다.
|
||||
void Destroy();
|
||||
|
||||
/// \brief 숫자 인덱스를 이름으로 변환한다.
|
||||
/// \brief 숫자 인덱스를 이름으로 변환한다.
|
||||
const char* operator [] (size_t index) const;
|
||||
|
||||
/// \brief 이름을 숫자 인덱스로 변환한다.
|
||||
/// \brief 이름을 숫자 인덱스로 변환한다.
|
||||
size_t operator [] (const char* name) const;
|
||||
|
||||
|
||||
private:
|
||||
/// \brief 복사 생성자 금지
|
||||
/// \brief 복사 생성자 금지
|
||||
cCsvAlias(const cCsvAlias&) {}
|
||||
|
||||
/// \brief 대입 연산자 금지
|
||||
/// \brief 대입 연산자 금지
|
||||
const cCsvAlias& operator = (const cCsvAlias&) { return *this; }
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \class cCsvRow
|
||||
/// \brief CSV 파일의 한 행을 캡슐화한 클래스
|
||||
/// \brief CSV 파일의 한 행을 캡슐화한 클래스
|
||||
///
|
||||
/// CSV의 기본 포맷은 엑셀에서 보이는 하나의 셀을 ',' 문자로 구분한 것이다.
|
||||
/// 하지만, 셀 안에 특수 문자로 쓰이는 ',' 문자나 '"' 문자가 들어갈 경우,
|
||||
/// 모양이 약간 이상하게 변한다. 다음은 그 변화의 예이다.
|
||||
/// CSV의 기본 포맷은 엑셀에서 보이는 하나의 셀을 ',' 문자로 구분한 것이다.
|
||||
/// 하지만, 셀 안에 특수 문자로 쓰이는 ',' 문자나 '"' 문자가 들어갈 경우,
|
||||
/// 모양이 약간 이상하게 변한다. 다음은 그 변화의 예이다.
|
||||
///
|
||||
/// <pre>
|
||||
/// 엑셀에서 보이는 모양 | 실제 CSV 파일에 들어가있는 모양
|
||||
/// 엑셀에서 보이는 모양 | 실제 CSV 파일에 들어가있는 모양
|
||||
/// ---------------------+----------------------------------------------------
|
||||
/// ItemPrice | ItemPrice
|
||||
/// Item,Price | "Item,Price"
|
||||
|
@ -101,9 +101,9 @@ private:
|
|||
/// Item",Price | "Item"",Price"
|
||||
/// </pre>
|
||||
///
|
||||
/// 이 예로서 다음과 같은 사항을 알 수 있다.
|
||||
/// - 셀 내부에 ',' 또는 '"' 문자가 들어갈 경우, 셀 좌우에 '"' 문자가 생긴다.
|
||||
/// - 셀 내부의 '"' 문자는 2개로 치환된다.
|
||||
/// 이 예로서 다음과 같은 사항을 알 수 있다.
|
||||
/// - 셀 내부에 ',' 또는 '"' 문자가 들어갈 경우, 셀 좌우에 '"' 문자가 생긴다.
|
||||
/// - 셀 내부의 '"' 문자는 2개로 치환된다.
|
||||
///
|
||||
/// \sa cCsvFile
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -111,51 +111,51 @@ private:
|
|||
class cCsvRow : public std::vector<std::string>
|
||||
{
|
||||
public:
|
||||
/// \brief 기본 생성자
|
||||
/// \brief 기본 생성자
|
||||
cCsvRow() {}
|
||||
|
||||
/// \brief 소멸자
|
||||
/// \brief 소멸자
|
||||
~cCsvRow() {}
|
||||
|
||||
|
||||
public:
|
||||
/// \brief 해당 셀의 데이터를 int 형으로 반환한다.
|
||||
/// \brief 해당 셀의 데이터를 int 형으로 반환한다.
|
||||
int AsInt(size_t index) const { return atoi(at(index).c_str()); }
|
||||
|
||||
/// \brief 해당 셀의 데이터를 double 형으로 반환한다.
|
||||
/// \brief 해당 셀의 데이터를 double 형으로 반환한다.
|
||||
double AsDouble(size_t index) const { return atof(at(index).c_str()); }
|
||||
|
||||
/// \brief 해당 셀의 데이터를 문자열로 반환한다.
|
||||
/// \brief 해당 셀의 데이터를 문자열로 반환한다.
|
||||
const char* AsString(size_t index) const { return at(index).c_str(); }
|
||||
|
||||
/// \brief 해당하는 이름의 셀 데이터를 int 형으로 반환한다.
|
||||
/// \brief 해당하는 이름의 셀 데이터를 int 형으로 반환한다.
|
||||
int AsInt(const char* name, const cCsvAlias& alias) const {
|
||||
return atoi( at(alias[name]).c_str() );
|
||||
}
|
||||
|
||||
/// \brief 해당하는 이름의 셀 데이터를 int 형으로 반환한다.
|
||||
/// \brief 해당하는 이름의 셀 데이터를 int 형으로 반환한다.
|
||||
double AsDouble(const char* name, const cCsvAlias& alias) const {
|
||||
return atof( at(alias[name]).c_str() );
|
||||
}
|
||||
|
||||
/// \brief 해당하는 이름의 셀 데이터를 문자열로 반환한다.
|
||||
/// \brief 해당하는 이름의 셀 데이터를 문자열로 반환한다.
|
||||
const char* AsString(const char* name, const cCsvAlias& alias) const {
|
||||
return at(alias[name]).c_str();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
/// \brief 복사 생성자 금지
|
||||
/// \brief 복사 생성자 금지
|
||||
cCsvRow(const cCsvRow&) {}
|
||||
|
||||
/// \brief 대입 연산자 금지
|
||||
/// \brief 대입 연산자 금지
|
||||
const cCsvRow& operator = (const cCsvRow&) { return *this; }
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \class cCsvFile
|
||||
/// \brief CSV(Comma Seperated Values) 파일을 read/write하기 위한 클래스
|
||||
/// \brief CSV(Comma Seperated Values) 파일을 read/write하기 위한 클래스
|
||||
///
|
||||
/// <b>sample</b>
|
||||
/// <pre>
|
||||
|
@ -179,8 +179,8 @@ private:
|
|||
/// file.save("test.csv", false);
|
||||
/// </pre>
|
||||
///
|
||||
/// \todo 파일에서만 읽어들일 것이 아니라, 메모리 소스로부터 읽는 함수도
|
||||
/// 있어야 할 듯 하다.
|
||||
/// \todo 파일에서만 읽어들일 것이 아니라, 메모리 소스로부터 읽는 함수도
|
||||
/// 있어야 할 듯 하다.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class cCsvFile
|
||||
|
@ -188,55 +188,55 @@ class cCsvFile
|
|||
private:
|
||||
typedef std::vector<cCsvRow*> ROWS;
|
||||
|
||||
ROWS m_Rows; ///< 행 컬렉션
|
||||
ROWS m_Rows; ///< 행 컬렉션
|
||||
|
||||
|
||||
public:
|
||||
/// \brief 생성자
|
||||
/// \brief 생성자
|
||||
cCsvFile() {}
|
||||
|
||||
/// \brief 소멸자
|
||||
/// \brief 소멸자
|
||||
virtual ~cCsvFile() { Destroy(); }
|
||||
|
||||
|
||||
public:
|
||||
/// \brief 지정된 이름의 CSV 파일을 로드한다.
|
||||
/// \brief 지정된 이름의 CSV 파일을 로드한다.
|
||||
bool Load(const char* fileName, const char seperator=',', const char quote='"');
|
||||
|
||||
/// \brief 가지고 있는 내용을 CSV 파일에다 저장한다.
|
||||
/// \brief 가지고 있는 내용을 CSV 파일에다 저장한다.
|
||||
bool Save(const char* fileName, bool append=false, char seperator=',', char quote='"') const;
|
||||
|
||||
/// \brief 모든 데이터를 메모리에서 삭제한다.
|
||||
/// \brief 모든 데이터를 메모리에서 삭제한다.
|
||||
void Destroy();
|
||||
|
||||
/// \brief 해당하는 인덱스의 행을 반환한다.
|
||||
/// \brief 해당하는 인덱스의 행을 반환한다.
|
||||
cCsvRow* operator [] (size_t index);
|
||||
|
||||
/// \brief 해당하는 인덱스의 행을 반환한다.
|
||||
/// \brief 해당하는 인덱스의 행을 반환한다.
|
||||
const cCsvRow* operator [] (size_t index) const;
|
||||
|
||||
/// \brief 행의 갯수를 반환한다.
|
||||
/// \brief 행의 갯수를 반환한다.
|
||||
size_t GetRowCount() const { return m_Rows.size(); }
|
||||
|
||||
|
||||
private:
|
||||
/// \brief 복사 생성자 금지
|
||||
/// \brief 복사 생성자 금지
|
||||
cCsvFile(const cCsvFile&) {}
|
||||
|
||||
/// \brief 대입 연산자 금지
|
||||
/// \brief 대입 연산자 금지
|
||||
const cCsvFile& operator = (const cCsvFile&) { return *this; }
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \class cCsvTable
|
||||
/// \brief CSV 파일을 이용해 테이블 데이터를 로드하는 경우가 많은데, 이 클래스는
|
||||
/// 그 작업을 좀 더 쉽게 하기 위해 만든 유틸리티 클래스다.
|
||||
/// \brief CSV 파일을 이용해 테이블 데이터를 로드하는 경우가 많은데, 이 클래스는
|
||||
/// 그 작업을 좀 더 쉽게 하기 위해 만든 유틸리티 클래스다.
|
||||
///
|
||||
/// CSV 파일을 로드하는 경우, 숫자를 이용해 셀을 액세스해야 하는데, CSV
|
||||
/// 파일의 포맷이 바뀌는 경우, 이 숫자들을 변경해줘야한다. 이 작업이 꽤
|
||||
/// 신경 집중을 요구하는 데다가, 에러가 발생하기 쉽다. 그러므로 숫자로
|
||||
/// 액세스하기보다는 문자열로 액세스하는 것이 약간 느리지만 낫다고 할 수 있다.
|
||||
/// CSV 파일을 로드하는 경우, 숫자를 이용해 셀을 액세스해야 하는데, CSV
|
||||
/// 파일의 포맷이 바뀌는 경우, 이 숫자들을 변경해줘야한다. 이 작업이 꽤
|
||||
/// 신경 집중을 요구하는 데다가, 에러가 발생하기 쉽다. 그러므로 숫자로
|
||||
/// 액세스하기보다는 문자열로 액세스하는 것이 약간 느리지만 낫다고 할 수 있다.
|
||||
///
|
||||
/// <b>sample</b>
|
||||
/// <pre>
|
||||
|
@ -259,63 +259,63 @@ private:
|
|||
class cCsvTable
|
||||
{
|
||||
public :
|
||||
cCsvFile m_File; ///< CSV 파일 객체
|
||||
cCsvFile m_File; ///< CSV 파일 객체
|
||||
private:
|
||||
cCsvAlias m_Alias; ///< 문자열을 셀 인덱스로 변환하기 위한 객체
|
||||
int m_CurRow; ///< 현재 횡단 중인 행 번호
|
||||
cCsvAlias m_Alias; ///< 문자열을 셀 인덱스로 변환하기 위한 객체
|
||||
int m_CurRow; ///< 현재 횡단 중인 행 번호
|
||||
|
||||
|
||||
public:
|
||||
/// \brief 생성자
|
||||
/// \brief 생성자
|
||||
cCsvTable();
|
||||
|
||||
/// \brief 소멸자
|
||||
/// \brief 소멸자
|
||||
virtual ~cCsvTable();
|
||||
|
||||
|
||||
public:
|
||||
/// \brief 지정된 이름의 CSV 파일을 로드한다.
|
||||
/// \brief 지정된 이름의 CSV 파일을 로드한다.
|
||||
bool Load(const char* fileName, const char seperator=',', const char quote='"');
|
||||
|
||||
/// \brief 셀을 액세스할 때, 숫자 대신 사용할 이름을 등록한다.
|
||||
/// \brief 셀을 액세스할 때, 숫자 대신 사용할 이름을 등록한다.
|
||||
void AddAlias(const char* name, size_t index) { m_Alias.AddAlias(name, index); }
|
||||
|
||||
/// \brief 다음 행으로 넘어간다.
|
||||
/// \brief 다음 행으로 넘어간다.
|
||||
bool Next();
|
||||
|
||||
/// \brief 현재 행의 셀 숫자를 반환한다.
|
||||
/// \brief 현재 행의 셀 숫자를 반환한다.
|
||||
size_t ColCount() const;
|
||||
|
||||
/// \brief 인덱스를 이용해 int 형으로 셀값을 반환한다.
|
||||
/// \brief 인덱스를 이용해 int 형으로 셀값을 반환한다.
|
||||
int AsInt(size_t index) const;
|
||||
|
||||
/// \brief 인덱스를 이용해 double 형으로 셀값을 반환한다.
|
||||
/// \brief 인덱스를 이용해 double 형으로 셀값을 반환한다.
|
||||
double AsDouble(size_t index) const;
|
||||
|
||||
/// \brief 인덱스를 이용해 std::string 형으로 셀값을 반환한다.
|
||||
/// \brief 인덱스를 이용해 std::string 형으로 셀값을 반환한다.
|
||||
const char* AsStringByIndex(size_t index) const;
|
||||
|
||||
/// \brief 셀 이름을 이용해 int 형으로 셀값을 반환한다.
|
||||
/// \brief 셀 이름을 이용해 int 형으로 셀값을 반환한다.
|
||||
int AsInt(const char* name) const { return AsInt(m_Alias[name]); }
|
||||
|
||||
/// \brief 셀 이름을 이용해 double 형으로 셀값을 반환한다.
|
||||
/// \brief 셀 이름을 이용해 double 형으로 셀값을 반환한다.
|
||||
double AsDouble(const char* name) const { return AsDouble(m_Alias[name]); }
|
||||
|
||||
/// \brief 셀 이름을 이용해 std::string 형으로 셀값을 반환한다.
|
||||
/// \brief 셀 이름을 이용해 std::string 형으로 셀값을 반환한다.
|
||||
const char* AsString(const char* name) const { return AsStringByIndex(m_Alias[name]); }
|
||||
|
||||
/// \brief alias를 포함해 모든 데이터를 삭제한다.
|
||||
/// \brief alias를 포함해 모든 데이터를 삭제한다.
|
||||
void Destroy();
|
||||
|
||||
|
||||
private:
|
||||
/// \brief 현재 행을 반환한다.
|
||||
/// \brief 현재 행을 반환한다.
|
||||
const cCsvRow* const CurRow() const;
|
||||
|
||||
/// \brief 복사 생성자 금지
|
||||
/// \brief 복사 생성자 금지
|
||||
cCsvTable(const cCsvTable&) {}
|
||||
|
||||
/// \brief 대입 연산자 금지
|
||||
/// \brief 대입 연산자 금지
|
||||
const cCsvTable& operator = (const cCsvTable&) { return *this; }
|
||||
};
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
#ifndef __INC_METIN2_DB_DBMANAGER_H__
|
||||
#define __INC_METIN2_DB_DBMANAGER_H__
|
||||
|
||||
// 디비 커넥션 클래스의 목적은... 디비에 접속해서 쿼리보내고 결과 받아오는
|
||||
// 모든 일들을 처리한다.
|
||||
// 코드 by 꼬붕 후로그래머 아노아~ = _=)b
|
||||
// 디비 커넥션 클래스의 목적은... 디비에 접속해서 쿼리보내고 결과 받아오는
|
||||
// 모든 일들을 처리한다.
|
||||
// 코드 by 꼬붕 후로그래머 아노아~ = _=)b
|
||||
#include <libsql/include/CAsyncSQL.h>
|
||||
|
||||
#define SQL_SAFE_LENGTH(size) (size * 2 + 1)
|
||||
|
|
|
@ -242,7 +242,7 @@ void CGuildManager::ResultRanking(MYSQL_RES * pRes)
|
|||
|
||||
void CGuildManager::Update()
|
||||
{
|
||||
ProcessReserveWar(); // 예약 전쟁 처리
|
||||
ProcessReserveWar(); // 예약 전쟁 처리
|
||||
|
||||
time_t now = CClientManager::instance().GetCurrentTime();
|
||||
|
||||
|
@ -462,7 +462,7 @@ void CGuildManager::RemoveWar(DWORD GID1, DWORD GID2)
|
|||
}
|
||||
|
||||
//
|
||||
// 길드전 비정상 종료 및 필드전 종료
|
||||
// 길드전 비정상 종료 및 필드전 종료
|
||||
//
|
||||
void CGuildManager::WarEnd(DWORD GID1, DWORD GID2, bool bForceDraw)
|
||||
{
|
||||
|
@ -493,7 +493,7 @@ void CGuildManager::WarEnd(DWORD GID1, DWORD GID2, bool bForceDraw)
|
|||
|
||||
bool bDraw = false;
|
||||
|
||||
if (!bForceDraw) // 강제 무승부가 아닐 경우에는 점수를 체크한다.
|
||||
if (!bForceDraw) // 강제 무승부가 아닐 경우에는 점수를 체크한다.
|
||||
{
|
||||
if (pData->iScore[0] > pData->iScore[1])
|
||||
{
|
||||
|
@ -508,7 +508,7 @@ void CGuildManager::WarEnd(DWORD GID1, DWORD GID2, bool bForceDraw)
|
|||
else
|
||||
bDraw = true;
|
||||
}
|
||||
else // 강제 무승부일 경우에는 무조건 무승부
|
||||
else // 강제 무승부일 경우에는 무조건 무승부
|
||||
bDraw = true;
|
||||
|
||||
if (bDraw)
|
||||
|
@ -516,14 +516,14 @@ void CGuildManager::WarEnd(DWORD GID1, DWORD GID2, bool bForceDraw)
|
|||
else
|
||||
ProcessWinLose(win_guild, lose_guild);
|
||||
|
||||
// DB 서버에서 자체적으로 끝낼 때도 있기 때문에 따로 패킷을 보내줘야 한다.
|
||||
// DB 서버에서 자체적으로 끝낼 때도 있기 때문에 따로 패킷을 보내줘야 한다.
|
||||
CClientManager::instance().for_each_peer(FSendPeerWar(0, GUILD_WAR_END, GID1, GID2));
|
||||
|
||||
RemoveWar(GID1, GID2);
|
||||
}
|
||||
|
||||
//
|
||||
// 길드전 정상 종료
|
||||
// 길드전 정상 종료
|
||||
//
|
||||
void CGuildManager::RecvWarOver(DWORD dwGuildWinner, DWORD dwGuildLoser, bool bDraw, int lWarPrice)
|
||||
{
|
||||
|
@ -571,7 +571,7 @@ void CGuildManager::RecvWarOver(DWORD dwGuildWinner, DWORD dwGuildLoser, bool bD
|
|||
void CGuildManager::RecvWarEnd(DWORD GID1, DWORD GID2)
|
||||
{
|
||||
SPDLOG_DEBUG("GuildWar: RecvWarEnded : {} vs {}", GID1, GID2);
|
||||
WarEnd(GID1, GID2, true); // 무조건 비정상 종료 시켜야 한다.
|
||||
WarEnd(GID1, GID2, true); // 무조건 비정상 종료 시켜야 한다.
|
||||
}
|
||||
|
||||
void CGuildManager::StartWar(BYTE bType, DWORD GID1, DWORD GID2, CGuildWarReserve * pkReserve)
|
||||
|
@ -745,7 +745,7 @@ void CGuildManager::ChangeLadderPoint(DWORD GID, int change)
|
|||
SPDLOG_DEBUG("GuildManager::ChangeLadderPoint {} {}", GID, r.ladder_point);
|
||||
SPDLOG_DEBUG("{}", buf);
|
||||
|
||||
// Packet 보내기
|
||||
// Packet 보내기
|
||||
TPacketGuildLadder p;
|
||||
|
||||
p.dwGuild = GID;
|
||||
|
@ -808,7 +808,7 @@ void CGuildManager::WithdrawMoney(CPeer* peer, DWORD dwGuild, INT iGold)
|
|||
return;
|
||||
}
|
||||
|
||||
// 돈이있으니 출금하고 올려준다
|
||||
// 돈이있으니 출금하고 올려준다
|
||||
if (it->second.gold >= iGold)
|
||||
{
|
||||
it->second.gold -= iGold;
|
||||
|
@ -839,7 +839,7 @@ void CGuildManager::WithdrawMoneyReply(DWORD dwGuild, BYTE bGiveSuccess, INT iGo
|
|||
}
|
||||
|
||||
//
|
||||
// 예약 길드전(관전자가 배팅할 수 있다)
|
||||
// 예약 길드전(관전자가 배팅할 수 있다)
|
||||
//
|
||||
const int c_aiScoreByLevel[GUILD_MAX_LEVEL+1] =
|
||||
{
|
||||
|
@ -869,7 +869,7 @@ const int c_aiScoreByLevel[GUILD_MAX_LEVEL+1] =
|
|||
const int c_aiScoreByRanking[GUILD_RANK_MAX_NUM+1] =
|
||||
{
|
||||
0,
|
||||
55000, // 1위
|
||||
55000, // 1위
|
||||
50000,
|
||||
45000,
|
||||
40000,
|
||||
|
@ -878,7 +878,7 @@ const int c_aiScoreByRanking[GUILD_RANK_MAX_NUM+1] =
|
|||
28000,
|
||||
24000,
|
||||
21000,
|
||||
18000, // 10위
|
||||
18000, // 10위
|
||||
15000,
|
||||
12000,
|
||||
10000,
|
||||
|
@ -888,7 +888,7 @@ const int c_aiScoreByRanking[GUILD_RANK_MAX_NUM+1] =
|
|||
3000,
|
||||
2000,
|
||||
1000,
|
||||
500 // 20위
|
||||
500 // 20위
|
||||
};
|
||||
|
||||
void CGuildManager::BootReserveWar()
|
||||
|
@ -932,8 +932,8 @@ void CGuildManager::BootReserveWar()
|
|||
|
||||
char buf[512];
|
||||
snprintf(buf, sizeof(buf), "GuildWar: BootReserveWar : step %d id %u GID1 %u GID2 %u", i, t.dwID, t.dwGuildFrom, t.dwGuildTo);
|
||||
// i == 0 이면 길드전 도중 DB가 튕긴 것이므로 무승부 처리한다.
|
||||
// 또는, 5분 이하 남은 예약 길드전도 무승부 처리한다. (각자의 배팅액을 돌려준다)
|
||||
// i == 0 이면 길드전 도중 DB가 튕긴 것이므로 무승부 처리한다.
|
||||
// 또는, 5분 이하 남은 예약 길드전도 무승부 처리한다. (각자의 배팅액을 돌려준다)
|
||||
//if (i == 0 || (int) t.dwTime - CClientManager::instance().GetCurrentTime() < 60 * 5)
|
||||
if (i == 0 || (int) t.dwTime - CClientManager::instance().GetCurrentTime() < 0)
|
||||
{
|
||||
|
@ -1010,7 +1010,7 @@ bool CGuildManager::ReserveWar(TPacketGuildWar * p)
|
|||
|
||||
int lvp, rkp, alv, mc;
|
||||
|
||||
// 파워 계산
|
||||
// 파워 계산
|
||||
TGuild & k1 = TouchGuild(GID1);
|
||||
|
||||
lvp = c_aiScoreByLevel[std::min<size_t>(GUILD_MAX_LEVEL, k1.level)];
|
||||
|
@ -1026,7 +1026,7 @@ bool CGuildManager::ReserveWar(TPacketGuildWar * p)
|
|||
t.lPowerFrom = (int) polyPower.Eval();
|
||||
SPDLOG_DEBUG("GuildWar: {} lvp {} rkp {} alv {} mc {} power {}", GID1, lvp, rkp, alv, mc, t.lPowerFrom);
|
||||
|
||||
// 파워 계산
|
||||
// 파워 계산
|
||||
TGuild & k2 = TouchGuild(GID2);
|
||||
|
||||
lvp = c_aiScoreByLevel[std::min<size_t>(GUILD_MAX_LEVEL, k2.level)];
|
||||
|
@ -1042,7 +1042,7 @@ bool CGuildManager::ReserveWar(TPacketGuildWar * p)
|
|||
t.lPowerTo = (int) polyPower.Eval();
|
||||
SPDLOG_DEBUG("GuildWar: {} lvp {} rkp {} alv {} mc {} power {}", GID2, lvp, rkp, alv, mc, t.lPowerTo);
|
||||
|
||||
// 핸디캡 계산
|
||||
// 핸디캡 계산
|
||||
if (t.lPowerTo > t.lPowerFrom)
|
||||
{
|
||||
polyHandicap.SetVar("pA", t.lPowerTo);
|
||||
|
@ -1057,7 +1057,7 @@ bool CGuildManager::ReserveWar(TPacketGuildWar * p)
|
|||
t.lHandicap = (int) polyHandicap.Eval();
|
||||
SPDLOG_DEBUG("GuildWar: handicap {}", t.lHandicap);
|
||||
|
||||
// 쿼리
|
||||
// 쿼리
|
||||
char szQuery[512];
|
||||
|
||||
snprintf(szQuery, sizeof(szQuery),
|
||||
|
@ -1094,7 +1094,7 @@ void CGuildManager::ProcessReserveWar()
|
|||
CGuildWarReserve * pk = it2->second;
|
||||
TGuildWarReserve & r = pk->GetDataRef();
|
||||
|
||||
if (!r.bStarted && r.dwTime - 1800 <= dwCurTime) // 30분 전부터 알린다.
|
||||
if (!r.bStarted && r.dwTime - 1800 <= dwCurTime) // 30분 전부터 알린다.
|
||||
{
|
||||
int iMin = (int) ceil((int)(r.dwTime - dwCurTime) / 60.0);
|
||||
|
||||
|
@ -1135,9 +1135,9 @@ void CGuildManager::ProcessReserveWar()
|
|||
pk->SetLastNoticeMin(iMin);
|
||||
|
||||
if (!g_stLocale.compare("euckr"))
|
||||
CClientManager::instance().SendNotice("%s 길드와 %s 길드의 전쟁이 약 %d분 후 시작 됩니다!", r_1.szName, r_2.szName, iMin);
|
||||
CClientManager::instance().SendNotice("The war between guild %s and guild %s will begin in approximately %d minutes!", r_1.szName, r_2.szName, iMin);
|
||||
else if (!g_stLocale.compare("gb2312"))
|
||||
CClientManager::instance().SendNotice("%s 곤삔뵨 %s 곤삔돨곤삔濫轢쉥瞳 %d롸爐빈역迦!", r_1.szName, r_2.szName, iMin);
|
||||
CClientManager::instance().SendNotice("The war between guild %s and guild %s will begin in approximately %d minutes!", r_1.szName, r_2.szName, iMin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1239,7 +1239,7 @@ void CGuildWarReserve::Initialize()
|
|||
|
||||
void CGuildWarReserve::OnSetup(CPeer * peer)
|
||||
{
|
||||
if (m_data.bStarted) // 이미 시작된 것은 보내지 않는다.
|
||||
if (m_data.bStarted) // 이미 시작된 것은 보내지 않는다.
|
||||
return;
|
||||
|
||||
FSendPeerWar(m_data.bType, GUILD_WAR_RESERVE, m_data.dwGuildFrom, m_data.dwGuildTo) (peer);
|
||||
|
@ -1325,8 +1325,8 @@ bool CGuildWarReserve::Bet(const char * pszLogin, DWORD dwGold, DWORD dwGuild)
|
|||
}
|
||||
|
||||
//
|
||||
// 무승부 처리: 대부분 승부가 나야 정상이지만, 서버 문제 등 특정 상황일 경우에는
|
||||
// 무승부 처리가 있어야 한다.
|
||||
// 무승부 처리: 대부분 승부가 나야 정상이지만, 서버 문제 등 특정 상황일 경우에는
|
||||
// 무승부 처리가 있어야 한다.
|
||||
//
|
||||
void CGuildWarReserve::Draw()
|
||||
{
|
||||
|
@ -1458,7 +1458,7 @@ void CGuildWarReserve::End(int iScoreFrom, int iScoreTo)
|
|||
|
||||
double ratio = (double) it->second.second / dwWinnerBet;
|
||||
|
||||
// 10% 세금 공제 후 분배
|
||||
// 10% 세금 공제 후 분배
|
||||
SPDLOG_DEBUG("WAR_REWARD: {} {} ratio {}", it->first.c_str(), it->second.second, ratio);
|
||||
|
||||
DWORD dwGold = (DWORD) (dwTotalBet * ratio * 0.9);
|
||||
|
|
|
@ -150,7 +150,7 @@ class CGuildWarReserve
|
|||
void SetLastNoticeMin(int iMin) { m_iLastNoticeMin = iMin; }
|
||||
|
||||
private:
|
||||
CGuildWarReserve(); // 기본 생성자를 사용하지 못하도록 의도적으로 구현하지 않음
|
||||
CGuildWarReserve(); // 기본 생성자를 사용하지 못하도록 의도적으로 구현하지 않음
|
||||
|
||||
TGuildWarReserve m_data;
|
||||
// <login, <guild, gold>>
|
||||
|
@ -235,7 +235,7 @@ class CGuildManager : public singleton<CGuildManager>
|
|||
std::map<DWORD, TGuild> m_map_kGuild;
|
||||
std::map<DWORD, std::map<DWORD, time_t> > m_mapGuildWarEndTime;
|
||||
|
||||
std::set<TGuildDeclareInfo> m_DeclareMap; // 선전 포고 상태를 저장
|
||||
std::set<TGuildDeclareInfo> m_DeclareMap; // 선전 포고 상태를 저장
|
||||
std::map<DWORD, std::map<DWORD, TGuildWarInfo> > m_WarMap;
|
||||
|
||||
typedef std::pair<time_t, TGuildWarPQElement *> stPairGuildWar;
|
||||
|
|
|
@ -54,19 +54,19 @@ void ItemAwardManager::Load(SQLMsg * pMsg)
|
|||
if (row[col])
|
||||
{
|
||||
strlcpy(kData->szWhy, row[col], sizeof(kData->szWhy));
|
||||
//게임 중에 why콜룸에 변동이 생기면
|
||||
char* whyStr = kData->szWhy; //why 콜룸 읽기
|
||||
char cmdStr[100] = ""; //why콜룸에서 읽은 값을 임시 문자열에 복사해둠
|
||||
strcpy(cmdStr,whyStr); //명령어 얻는 과정에서 토큰쓰면 원본도 토큰화 되기 때문
|
||||
//게임 중에 why콜룸에 변동이 생기면
|
||||
char* whyStr = kData->szWhy; //why 콜룸 읽기
|
||||
char cmdStr[100] = ""; //why콜룸에서 읽은 값을 임시 문자열에 복사해둠
|
||||
strcpy(cmdStr,whyStr); //명령어 얻는 과정에서 토큰쓰면 원본도 토큰화 되기 때문
|
||||
char command[20] = "";
|
||||
strcpy(command,CClientManager::instance().GetCommand(cmdStr).c_str()); // command 얻기
|
||||
strcpy(command,CClientManager::instance().GetCommand(cmdStr).c_str()); // command 얻기
|
||||
//SPDLOG_ERROR("{}, {}",pItemAward->dwID,command);
|
||||
if( !(strcmp(command,"GIFT") )) // command 가 GIFT이면
|
||||
if( !(strcmp(command,"GIFT") )) // command 가 GIFT이면
|
||||
{
|
||||
TPacketItemAwardInfromer giftData;
|
||||
strcpy(giftData.login, kData->szLogin); //로그인 아이디 복사
|
||||
strcpy(giftData.command, command); //명령어 복사
|
||||
giftData.vnum = kData->dwVnum; //아이템 vnum도 복사
|
||||
strcpy(giftData.login, kData->szLogin); //로그인 아이디 복사
|
||||
strcpy(giftData.command, command); //명령어 복사
|
||||
giftData.vnum = kData->dwVnum; //아이템 vnum도 복사
|
||||
CClientManager::instance().ForwardPacket(HEADER_DG_ITEMAWARD_INFORMER,&giftData,sizeof(TPacketItemAwardInfromer));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,11 +28,11 @@ std::string g_stPlayerDBName = "";
|
|||
|
||||
BOOL g_test_server = false;
|
||||
|
||||
//단위 초
|
||||
//단위 초
|
||||
int g_iPlayerCacheFlushSeconds = 60*7;
|
||||
int g_iItemCacheFlushSeconds = 60*5;
|
||||
|
||||
//g_iLogoutSeconds 수치는 g_iPlayerCacheFlushSeconds 와 g_iItemCacheFlushSeconds 보다 길어야 한다.
|
||||
//g_iLogoutSeconds 수치는 g_iPlayerCacheFlushSeconds 와 g_iItemCacheFlushSeconds 보다 길어야 한다.
|
||||
int g_iLogoutSeconds = 60*10;
|
||||
|
||||
|
||||
|
@ -116,13 +116,13 @@ int main()
|
|||
|
||||
void emptybeat(LPHEART heart, int pulse)
|
||||
{
|
||||
if (!(pulse % heart->passes_per_sec)) // 1초에 한번
|
||||
if (!(pulse % heart->passes_per_sec)) // 1초에 한번
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @version 05/06/13 Bang2ni - 아이템 가격정보 캐시 flush timeout 설정 추가.
|
||||
// @version 05/06/13 Bang2ni - 아이템 가격정보 캐시 flush timeout 설정 추가.
|
||||
//
|
||||
int Start()
|
||||
{
|
||||
|
|
|
@ -253,7 +253,7 @@ namespace marriage
|
|||
|
||||
void CManager::OnSetup(CPeer* peer)
|
||||
{
|
||||
// 결혼한 사람들 보내기
|
||||
// 결혼한 사람들 보내기
|
||||
for (itertype(m_Marriages) it = m_Marriages.begin(); it != m_Marriages.end(); ++it)
|
||||
{
|
||||
TMarriage* pMarriage = *it;
|
||||
|
@ -280,7 +280,7 @@ namespace marriage
|
|||
}
|
||||
}
|
||||
|
||||
// 결혼식 보내기
|
||||
// 결혼식 보내기
|
||||
for (itertype(m_mapRunningWedding) it = m_mapRunningWedding.begin(); it != m_mapRunningWedding.end(); ++it)
|
||||
{
|
||||
const TWedding& t = it->second;
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace marriage
|
|||
DWORD pid2;
|
||||
int love_point;
|
||||
DWORD time;
|
||||
BYTE is_married; // false : 약혼 상태, true : 결혼 상태
|
||||
BYTE is_married; // false : 약혼 상태, true : 결혼 상태
|
||||
std::string name1;
|
||||
std::string name2;
|
||||
|
||||
|
|
|
@ -233,7 +233,7 @@ bool CMonarch::SetMonarch(const char * name)
|
|||
}
|
||||
delete pMsg;
|
||||
|
||||
//db에 입력
|
||||
//db에 입력
|
||||
snprintf(szQuery, sizeof(szQuery),
|
||||
"REPLACE INTO monarch (empire, name, windate, money) VALUES(%d, %d, now(), %ld)", Empire, p->pid[Empire], p->money[Empire]);
|
||||
|
||||
|
|
|
@ -64,9 +64,9 @@ class CPeer : public CPeerBase
|
|||
BYTE m_bChannel;
|
||||
DWORD m_dwHandle;
|
||||
DWORD m_dwUserCount;
|
||||
WORD m_wListenPort; // 게임서버가 클라이언트를 위해 listen 하는 포트
|
||||
WORD m_wP2PPort; // 게임서버가 게임서버 P2P 접속을 위해 listen 하는 포트
|
||||
LONG m_alMaps[MAP_ALLOW_MAX_LEN]; // 어떤 맵을 관장하고 있는가?
|
||||
WORD m_wListenPort; // 게임서버가 클라이언트를 위해 listen 하는 포트
|
||||
WORD m_wP2PPort; // 게임서버가 게임서버 P2P 접속을 위해 listen 하는 포트
|
||||
LONG m_alMaps[MAP_ALLOW_MAX_LEN]; // 어떤 맵을 관장하고 있는가?
|
||||
|
||||
TItemIDRangeTable m_itemRange;
|
||||
TItemIDRangeTable m_itemSpareRange;
|
||||
|
|
|
@ -20,7 +20,7 @@ CPrivManager::~CPrivManager()
|
|||
}
|
||||
|
||||
//
|
||||
// @version 05/06/07 Bang2ni - 중복적으로 보너스가 적용 된 길드에 대한 처리
|
||||
// @version 05/06/07 Bang2ni - 중복적으로 보너스가 적용 된 길드에 대한 처리
|
||||
//
|
||||
void CPrivManager::Update()
|
||||
{
|
||||
|
@ -37,8 +37,8 @@ void CPrivManager::Update()
|
|||
typeof(m_aPrivGuild[p->type].begin()) it = m_aPrivGuild[p->type].find(p->guild_id);
|
||||
|
||||
// ADD_GUILD_PRIV_TIME
|
||||
// 길드에 중복적으로 보너스가 설정되었을 경우 map 의 value 가 갱신(수정) 되었으므로
|
||||
// TPrivGuildData 의 포인터가 같을때 실제로 삭제해 주고 게임서버들에게 cast 해 준다.
|
||||
// 길드에 중복적으로 보너스가 설정되었을 경우 map 의 value 가 갱신(수정) 되었으므로
|
||||
// TPrivGuildData 의 포인터가 같을때 실제로 삭제해 주고 게임서버들에게 cast 해 준다.
|
||||
if (it != m_aPrivGuild[p->type].end() && it->second == p) {
|
||||
m_aPrivGuild[p->type].erase(it);
|
||||
SendChangeGuildPriv(p->guild_id, p->type, 0, 0);
|
||||
|
@ -113,7 +113,7 @@ void CPrivManager::AddCharPriv(DWORD pid, BYTE type, int value)
|
|||
}
|
||||
|
||||
//
|
||||
// @version 05/06/07 Bang2ni - 이미 보너스가 적용 된 길드에 보너스 설정
|
||||
// @version 05/06/07 Bang2ni - 이미 보너스가 적용 된 길드에 보너스 설정
|
||||
//
|
||||
void CPrivManager::AddGuildPriv(DWORD guild_id, BYTE type, int value, time_t duration_sec)
|
||||
{
|
||||
|
@ -131,8 +131,8 @@ void CPrivManager::AddGuildPriv(DWORD guild_id, BYTE type, int value, time_t dur
|
|||
m_pqPrivGuild.push(std::make_pair(end, p));
|
||||
|
||||
// ADD_GUILD_PRIV_TIME
|
||||
// 이미 보너스가 설정되 있다면 map 의 value 를 갱신해 준다.
|
||||
// 이전 value 의 포인터는 priority queue 에서 삭제될 때 해제된다.
|
||||
// 이미 보너스가 설정되 있다면 map 의 value 를 갱신해 준다.
|
||||
// 이전 value 의 포인터는 priority queue 에서 삭제될 때 해제된다.
|
||||
if (it != m_aPrivGuild[type].end())
|
||||
it->second = p;
|
||||
else
|
||||
|
@ -158,8 +158,8 @@ void CPrivManager::AddEmpirePriv(BYTE empire, BYTE type, int value, time_t durat
|
|||
time_t now = CClientManager::instance().GetCurrentTime();
|
||||
time_t end = now+duration_sec;
|
||||
|
||||
// 이전 설정값 무효화
|
||||
// priority_queue에 들어있는 pointer == m_aaPrivEmpire[type][empire]
|
||||
// 이전 설정값 무효화
|
||||
// priority_queue에 들어있는 pointer == m_aaPrivEmpire[type][empire]
|
||||
{
|
||||
if (m_aaPrivEmpire[type][empire])
|
||||
m_aaPrivEmpire[type][empire]->bRemoved = true;
|
||||
|
@ -177,7 +177,7 @@ void CPrivManager::AddEmpirePriv(BYTE empire, BYTE type, int value, time_t durat
|
|||
}
|
||||
|
||||
/**
|
||||
* @version 05/06/08 Bang2ni - 지속시간 추가
|
||||
* @version 05/06/08 Bang2ni - 지속시간 추가
|
||||
*/
|
||||
struct FSendChangeGuildPriv
|
||||
{
|
||||
|
|
|
@ -23,7 +23,7 @@ struct TPrivEmpireData
|
|||
};
|
||||
|
||||
/**
|
||||
* @version 05/06/08 Bang2ni - 지속시간 추가
|
||||
* @version 05/06/08 Bang2ni - 지속시간 추가
|
||||
*/
|
||||
struct TPrivGuildData
|
||||
{
|
||||
|
@ -33,7 +33,7 @@ struct TPrivGuildData
|
|||
DWORD guild_id;
|
||||
|
||||
// ADD_GUILD_PRIV_TIME
|
||||
time_t end_time_sec; ///< 지속시간
|
||||
time_t end_time_sec; ///< 지속시간
|
||||
|
||||
TPrivGuildData(BYTE type, int value, DWORD guild_id, time_t _end_time_sec)
|
||||
: type(type), value(value), bRemoved(false), guild_id(guild_id), end_time_sec(_end_time_sec )
|
||||
|
@ -53,7 +53,7 @@ struct TPrivCharData
|
|||
};
|
||||
|
||||
/**
|
||||
* @version 05/06/08 Bang2ni - Guild privilege 관련 함수 지속 시간 추가
|
||||
* @version 05/06/08 Bang2ni - Guild privilege 관련 함수 지속 시간 추가
|
||||
*/
|
||||
class CPrivManager : public singleton<CPrivManager>
|
||||
{
|
||||
|
|
|
@ -25,23 +25,23 @@ string trim(const string& str){return trim_left(trim_right(str));}
|
|||
|
||||
static string* StringSplit(string strOrigin, string strTok)
|
||||
{
|
||||
int cutAt; //자르는위치
|
||||
int index = 0; //문자열인덱스
|
||||
string* strResult = new string[30]; //결과return 할변수
|
||||
int cutAt; //자르는위치
|
||||
int index = 0; //문자열인덱스
|
||||
string* strResult = new string[30]; //결과return 할변수
|
||||
|
||||
//strTok을찾을때까지반복
|
||||
//strTok을찾을때까지반복
|
||||
while ((cutAt = strOrigin.find_first_of(strTok)) != strOrigin.npos)
|
||||
{
|
||||
if (cutAt > 0) //자르는위치가0보다크면(성공시)
|
||||
if (cutAt > 0) //자르는위치가0보다크면(성공시)
|
||||
{
|
||||
strResult[index++] = strOrigin.substr(0, cutAt); //결과배열에추가
|
||||
strResult[index++] = strOrigin.substr(0, cutAt); //결과배열에추가
|
||||
}
|
||||
strOrigin = strOrigin.substr(cutAt+1); //원본은자른부분제외한나머지
|
||||
strOrigin = strOrigin.substr(cutAt+1); //원본은자른부분제외한나머지
|
||||
}
|
||||
|
||||
if(strOrigin.length() > 0) //원본이아직남았으면
|
||||
if(strOrigin.length() > 0) //원본이아직남았으면
|
||||
{
|
||||
strResult[index++] = strOrigin.substr(0, cutAt); //나머지를결과배열에추가
|
||||
strResult[index++] = strOrigin.substr(0, cutAt); //나머지를결과배열에추가
|
||||
}
|
||||
|
||||
for( int i=0;i<index;i++)
|
||||
|
@ -49,7 +49,7 @@ static string* StringSplit(string strOrigin, string strTok)
|
|||
strResult[i] = trim(strResult[i]);
|
||||
}
|
||||
|
||||
return strResult; //결과return
|
||||
return strResult; //결과return
|
||||
}
|
||||
|
||||
|
||||
|
@ -60,25 +60,25 @@ int get_Item_Type_Value(string inputString)
|
|||
"ITEM_ARMOR", "ITEM_USE",
|
||||
"ITEM_AUTOUSE", "ITEM_MATERIAL",
|
||||
"ITEM_SPECIAL", "ITEM_TOOL",
|
||||
"ITEM_LOTTERY", "ITEM_ELK", //10개
|
||||
"ITEM_LOTTERY", "ITEM_ELK", //10개
|
||||
|
||||
"ITEM_METIN", "ITEM_CONTAINER",
|
||||
"ITEM_FISH", "ITEM_ROD",
|
||||
"ITEM_RESOURCE", "ITEM_CAMPFIRE",
|
||||
"ITEM_UNIQUE", "ITEM_SKILLBOOK",
|
||||
"ITEM_QUEST", "ITEM_POLYMORPH", //20개
|
||||
"ITEM_QUEST", "ITEM_POLYMORPH", //20개
|
||||
|
||||
"ITEM_TREASURE_BOX", "ITEM_TREASURE_KEY",
|
||||
"ITEM_SKILLFORGET", "ITEM_GIFTBOX",
|
||||
"ITEM_PICK", "ITEM_HAIR",
|
||||
"ITEM_TOTEM", "ITEM_BLEND",
|
||||
"ITEM_COSTUME", "ITEM_DS", //30개
|
||||
"ITEM_COSTUME", "ITEM_DS", //30개
|
||||
|
||||
"ITEM_SPECIAL_DS", "ITEM_EXTRACT",
|
||||
"ITEM_SECONDARY_COIN", //33개
|
||||
"ITEM_SECONDARY_COIN", //33개
|
||||
|
||||
"ITEM_RING",
|
||||
"ITEM_BELT", //35개 (EItemTypes 값으로 치면 34)
|
||||
"ITEM_BELT", //35개 (EItemTypes 값으로 치면 34)
|
||||
};
|
||||
|
||||
|
||||
|
@ -159,8 +159,8 @@ int get_Item_SubType_Value(int type_value, string inputString)
|
|||
arSub29, //30
|
||||
arSub31, //31
|
||||
0, //32
|
||||
0, //33 반지
|
||||
0, //34 벨트
|
||||
0, //33 반지
|
||||
0, //34 벨트
|
||||
};
|
||||
static int arNumberOfSubtype[_countof(arSubType)] = {
|
||||
0,
|
||||
|
@ -196,21 +196,21 @@ int get_Item_SubType_Value(int type_value, string inputString)
|
|||
sizeof(arSub29)/sizeof(arSub29[0]),
|
||||
sizeof(arSub31)/sizeof(arSub31[0]),
|
||||
0, // 32
|
||||
0, // 33 반지
|
||||
0, // 34 벨트
|
||||
0, // 33 반지
|
||||
0, // 34 벨트
|
||||
};
|
||||
|
||||
|
||||
assert(_countof(arSubType) > type_value && "Subtype rule: Out of range!!");
|
||||
|
||||
// assert 안 먹히는 듯..
|
||||
// assert 안 먹히는 듯..
|
||||
if (_countof(arSubType) <= type_value)
|
||||
{
|
||||
SPDLOG_ERROR("SubType : Out of range!! (type_value: {}, count of registered subtype: {}", type_value, _countof(arSubType));
|
||||
return -1;
|
||||
}
|
||||
|
||||
//아이템 타입의 서브타입 어레이가 존재하는지 알아보고, 없으면 0 리턴
|
||||
//아이템 타입의 서브타입 어레이가 존재하는지 알아보고, 없으면 0 리턴
|
||||
if (arSubType[type_value]==0) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -246,13 +246,13 @@ int get_Item_AntiFlag_Value(string inputString)
|
|||
|
||||
|
||||
int retValue = 0;
|
||||
string* arInputString = StringSplit(inputString, "|"); //프로토 정보 내용을 단어별로 쪼갠 배열.
|
||||
string* arInputString = StringSplit(inputString, "|"); //프로토 정보 내용을 단어별로 쪼갠 배열.
|
||||
for(int i =0;i<sizeof(arAntiFlag)/sizeof(arAntiFlag[0]);i++) {
|
||||
string tempString = arAntiFlag[i];
|
||||
for (int j=0; j<30 ; j++) //최대 30개 단어까지. (하드코딩)
|
||||
for (int j=0; j<30 ; j++) //최대 30개 단어까지. (하드코딩)
|
||||
{
|
||||
string tempString2 = arInputString[j];
|
||||
if (tempString2.compare(tempString)==0) { //일치하는지 확인.
|
||||
if (tempString2.compare(tempString)==0) { //일치하는지 확인.
|
||||
retValue = retValue + pow((float)2,(float)i);
|
||||
}
|
||||
|
||||
|
@ -275,13 +275,13 @@ int get_Item_Flag_Value(string inputString)
|
|||
|
||||
|
||||
int retValue = 0;
|
||||
string* arInputString = StringSplit(inputString, "|"); //프로토 정보 내용을 단어별로 쪼갠 배열.
|
||||
string* arInputString = StringSplit(inputString, "|"); //프로토 정보 내용을 단어별로 쪼갠 배열.
|
||||
for(int i =0;i<sizeof(arFlag)/sizeof(arFlag[0]);i++) {
|
||||
string tempString = arFlag[i];
|
||||
for (int j=0; j<30 ; j++) //최대 30개 단어까지. (하드코딩)
|
||||
for (int j=0; j<30 ; j++) //최대 30개 단어까지. (하드코딩)
|
||||
{
|
||||
string tempString2 = arInputString[j];
|
||||
if (tempString2.compare(tempString)==0) { //일치하는지 확인.
|
||||
if (tempString2.compare(tempString)==0) { //일치하는지 확인.
|
||||
retValue = retValue + pow((float)2,(float)i);
|
||||
}
|
||||
|
||||
|
@ -303,13 +303,13 @@ int get_Item_WearFlag_Value(string inputString)
|
|||
|
||||
|
||||
int retValue = 0;
|
||||
string* arInputString = StringSplit(inputString, "|"); //프로토 정보 내용을 단어별로 쪼갠 배열.
|
||||
string* arInputString = StringSplit(inputString, "|"); //프로토 정보 내용을 단어별로 쪼갠 배열.
|
||||
for(int i =0;i<sizeof(arWearrFlag)/sizeof(arWearrFlag[0]);i++) {
|
||||
string tempString = arWearrFlag[i];
|
||||
for (int j=0; j<30 ; j++) //최대 30개 단어까지. (하드코딩)
|
||||
for (int j=0; j<30 ; j++) //최대 30개 단어까지. (하드코딩)
|
||||
{
|
||||
string tempString2 = arInputString[j];
|
||||
if (tempString2.compare(tempString)==0) { //일치하는지 확인.
|
||||
if (tempString2.compare(tempString)==0) { //일치하는지 확인.
|
||||
retValue = retValue + pow((float)2,(float)i);
|
||||
}
|
||||
|
||||
|
@ -329,13 +329,13 @@ int get_Item_Immune_Value(string inputString)
|
|||
string arImmune[] = {"PARA","CURSE","STUN","SLEEP","SLOW","POISON","TERROR"};
|
||||
|
||||
int retValue = 0;
|
||||
string* arInputString = StringSplit(inputString, "|"); //프로토 정보 내용을 단어별로 쪼갠 배열.
|
||||
string* arInputString = StringSplit(inputString, "|"); //프로토 정보 내용을 단어별로 쪼갠 배열.
|
||||
for(int i =0;i<sizeof(arImmune)/sizeof(arImmune[0]);i++) {
|
||||
string tempString = arImmune[i];
|
||||
for (int j=0; j<30 ; j++) //최대 30개 단어까지. (하드코딩)
|
||||
for (int j=0; j<30 ; j++) //최대 30개 단어까지. (하드코딩)
|
||||
{
|
||||
string tempString2 = arInputString[j];
|
||||
if (tempString2.compare(tempString)==0) { //일치하는지 확인.
|
||||
if (tempString2.compare(tempString)==0) { //일치하는지 확인.
|
||||
retValue = retValue + pow((float)2,(float)i);
|
||||
}
|
||||
|
||||
|
@ -414,7 +414,7 @@ int get_Item_ApplyType_Value(string inputString)
|
|||
}
|
||||
|
||||
|
||||
//몬스터 프로토도 읽는다.
|
||||
//몬스터 프로토도 읽는다.
|
||||
|
||||
|
||||
int get_Mob_Rank_Value(string inputString)
|
||||
|
@ -508,13 +508,13 @@ int get_Mob_AIFlag_Value(string inputString)
|
|||
|
||||
|
||||
int retValue = 0;
|
||||
string* arInputString = StringSplit(inputString, ","); //프로토 정보 내용을 단어별로 쪼갠 배열.
|
||||
string* arInputString = StringSplit(inputString, ","); //프로토 정보 내용을 단어별로 쪼갠 배열.
|
||||
for(int i =0;i<sizeof(arAIFlag)/sizeof(arAIFlag[0]);i++) {
|
||||
string tempString = arAIFlag[i];
|
||||
for (int j=0; j<30 ; j++) //최대 30개 단어까지. (하드코딩)
|
||||
for (int j=0; j<30 ; j++) //최대 30개 단어까지. (하드코딩)
|
||||
{
|
||||
string tempString2 = arInputString[j];
|
||||
if (tempString2.compare(tempString)==0) { //일치하는지 확인.
|
||||
if (tempString2.compare(tempString)==0) { //일치하는지 확인.
|
||||
retValue = retValue + pow((float)2,(float)i);
|
||||
}
|
||||
|
||||
|
@ -533,13 +533,13 @@ int get_Mob_RaceFlag_Value(string inputString)
|
|||
"ATT_ELEC","ATT_FIRE","ATT_ICE","ATT_WIND","ATT_EARTH","ATT_DARK"};
|
||||
|
||||
int retValue = 0;
|
||||
string* arInputString = StringSplit(inputString, ","); //프로토 정보 내용을 단어별로 쪼갠 배열.
|
||||
string* arInputString = StringSplit(inputString, ","); //프로토 정보 내용을 단어별로 쪼갠 배열.
|
||||
for(int i =0;i<sizeof(arRaceFlag)/sizeof(arRaceFlag[0]);i++) {
|
||||
string tempString = arRaceFlag[i];
|
||||
for (int j=0; j<30 ; j++) //최대 30개 단어까지. (하드코딩)
|
||||
for (int j=0; j<30 ; j++) //최대 30개 단어까지. (하드코딩)
|
||||
{
|
||||
string tempString2 = arInputString[j];
|
||||
if (tempString2.compare(tempString)==0) { //일치하는지 확인.
|
||||
if (tempString2.compare(tempString)==0) { //일치하는지 확인.
|
||||
retValue = retValue + pow((float)2,(float)i);
|
||||
}
|
||||
|
||||
|
@ -557,13 +557,13 @@ int get_Mob_ImmuneFlag_Value(string inputString)
|
|||
string arImmuneFlag[] = {"STUN","SLOW","FALL","CURSE","POISON","TERROR", "REFLECT"};
|
||||
|
||||
int retValue = 0;
|
||||
string* arInputString = StringSplit(inputString, ","); //프로토 정보 내용을 단어별로 쪼갠 배열.
|
||||
string* arInputString = StringSplit(inputString, ","); //프로토 정보 내용을 단어별로 쪼갠 배열.
|
||||
for(int i =0;i<sizeof(arImmuneFlag)/sizeof(arImmuneFlag[0]);i++) {
|
||||
string tempString = arImmuneFlag[i];
|
||||
for (int j=0; j<30 ; j++) //최대 30개 단어까지. (하드코딩)
|
||||
for (int j=0; j<30 ; j++) //최대 30개 단어까지. (하드코딩)
|
||||
{
|
||||
string tempString2 = arInputString[j];
|
||||
if (tempString2.compare(tempString)==0) { //일치하는지 확인.
|
||||
if (tempString2.compare(tempString)==0) { //일치하는지 확인.
|
||||
retValue = retValue + pow((float)2,(float)i);
|
||||
}
|
||||
|
||||
|
@ -581,14 +581,14 @@ int get_Mob_ImmuneFlag_Value(string inputString)
|
|||
|
||||
#ifndef __DUMP_PROTO__
|
||||
|
||||
//몹 테이블을 셋팅해준다.
|
||||
//몹 테이블을 셋팅해준다.
|
||||
bool Set_Proto_Mob_Table(TMobTable *mobTable, cCsvTable &csvTable,std::map<int,const char*> &nameMap)
|
||||
{
|
||||
int col = 0;
|
||||
str_to_number(mobTable->dwVnum, csvTable.AsStringByIndex(col++));
|
||||
strlcpy(mobTable->szName, csvTable.AsStringByIndex(col++), sizeof(mobTable->szName));
|
||||
|
||||
//3. 지역별 이름 넣어주기.
|
||||
//3. 지역별 이름 넣어주기.
|
||||
map<int,const char*>::iterator it;
|
||||
it = nameMap.find(mobTable->dwVnum);
|
||||
if (it != nameMap.end()) {
|
||||
|
@ -749,11 +749,11 @@ bool Set_Proto_Item_Table(TItemTable *itemTable, cCsvTable &csvTable,std::map<in
|
|||
col = col + 1;
|
||||
}
|
||||
|
||||
// vnum 및 vnum range 읽기.
|
||||
// vnum 및 vnum range 읽기.
|
||||
{
|
||||
std::string s(csvTable.AsStringByIndex(0));
|
||||
int pos = s.find("~");
|
||||
// vnum 필드에 '~'가 없다면 패스
|
||||
// vnum 필드에 '~'가 없다면 패스
|
||||
if (std::string::npos == pos)
|
||||
{
|
||||
itemTable->dwVnum = dataArray[0];
|
||||
|
@ -777,7 +777,7 @@ bool Set_Proto_Item_Table(TItemTable *itemTable, cCsvTable &csvTable,std::map<in
|
|||
}
|
||||
|
||||
strlcpy(itemTable->szName, csvTable.AsStringByIndex(1), sizeof(itemTable->szName));
|
||||
//지역별 이름 넣어주기.
|
||||
//지역별 이름 넣어주기.
|
||||
map<int,const char*>::iterator it;
|
||||
it = nameMap.find(itemTable->dwVnum);
|
||||
if (it != nameMap.end()) {
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
#include "CsvReader.h"
|
||||
|
||||
//csv 파일을 읽어와서 아이템 테이블에 넣어준다.
|
||||
void putItemIntoTable(); //(테이블, 테스트여부)
|
||||
//csv 파일을 읽어와서 아이템 테이블에 넣어준다.
|
||||
void putItemIntoTable(); //(테이블, 테스트여부)
|
||||
|
||||
int get_Item_Type_Value(std::string inputString);
|
||||
int get_Item_SubType_Value(int type_value, std::string inputString);
|
||||
|
@ -19,7 +19,7 @@ int get_Item_LimitType_Value(std::string inputString);
|
|||
int get_Item_ApplyType_Value(std::string inputString);
|
||||
|
||||
|
||||
//몬스터 프로토도 읽을 수 있다.
|
||||
//몬스터 프로토도 읽을 수 있다.
|
||||
int get_Mob_Rank_Value(std::string inputString);
|
||||
int get_Mob_Type_Value(std::string inputString);
|
||||
int get_Mob_BattleType_Value(std::string inputString);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define __INC_METIN_II_DB_QID_H__
|
||||
|
||||
/**
|
||||
* @version 05/06/10 Bang2ni - 아이템 가격정보 쿼리 추가(QID_ITEMPRICE_XXX)
|
||||
* @version 05/06/10 Bang2ni - 아이템 가격정보 쿼리 추가(QID_ITEMPRICE_XXX)
|
||||
*/
|
||||
enum QID
|
||||
{
|
||||
|
@ -28,10 +28,10 @@ enum QID
|
|||
QID_GUILD_RANKING, // 19
|
||||
|
||||
// MYSHOP_PRICE_LIST
|
||||
QID_ITEMPRICE_SAVE, ///< 20, 아이템 가격정보 저장 쿼리
|
||||
QID_ITEMPRICE_DESTROY, ///< 21, 아이템 가격정보 삭제 쿼리
|
||||
QID_ITEMPRICE_LOAD_FOR_UPDATE, ///< 22, 가격정보 업데이트를 위한 아이템 가격정보 로드 쿼리
|
||||
QID_ITEMPRICE_LOAD, ///< 22, 아이템 가격정보 로드 쿼리
|
||||
QID_ITEMPRICE_SAVE, ///< 20, 아이템 가격정보 저장 쿼리
|
||||
QID_ITEMPRICE_DESTROY, ///< 21, 아이템 가격정보 저장 쿼리
|
||||
QID_ITEMPRICE_LOAD_FOR_UPDATE, ///< 22, 가격정보 업데이트를 위한 아이템 가격정보 로드 쿼리
|
||||
QID_ITEMPRICE_LOAD, ///< 22, 아이템 가격정보 로드 쿼리
|
||||
// END_OF_MYSHOP_PRICE_LIST
|
||||
};
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ void CGrid::Clear()
|
|||
|
||||
int CGrid::FindBlank(int w, int h)
|
||||
{
|
||||
// 크기가 더 크다면 확인할 필요 없이 그냥 리턴
|
||||
// 크기가 더 크다면 확인할 필요 없이 그냥 리턴
|
||||
if (w > m_iWidth || h > m_iHeight)
|
||||
return -1;
|
||||
|
||||
|
@ -86,7 +86,7 @@ bool CGrid::IsEmpty(int iPos, int w, int h)
|
|||
{
|
||||
int iRow = iPos / m_iWidth;
|
||||
|
||||
// Grid 안쪽인가를 먼저 검사
|
||||
// Grid 안쪽인가를 먼저 검사
|
||||
if (iRow + h > m_iHeight)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -102,14 +102,14 @@ EVENTFUNC(battle_arena_event)
|
|||
case 0:
|
||||
{
|
||||
++pInfo->state;
|
||||
BroadcastNotice(LC_TEXT("몬스터들의 공격까지 5분 남았습니다!!!"));
|
||||
BroadcastNotice(LC_TEXT("Five minutes until the monsters attack!!!"));
|
||||
}
|
||||
return test_server ? PASSES_PER_SEC(60) : PASSES_PER_SEC(60*4);
|
||||
|
||||
case 1:
|
||||
{
|
||||
++pInfo->state;
|
||||
BroadcastNotice(LC_TEXT("몬스터들의 공격까지 1분 남았습니다!!!"));
|
||||
BroadcastNotice(LC_TEXT("One minute left until the monsters attack!!!"));
|
||||
}
|
||||
return test_server ? PASSES_PER_SEC(10) : PASSES_PER_SEC(60);
|
||||
|
||||
|
@ -119,7 +119,7 @@ EVENTFUNC(battle_arena_event)
|
|||
pInfo->wait_count = 0;
|
||||
|
||||
quest::CQuestManager::instance().RequestSetEventFlag("battle_arena", 0);
|
||||
BroadcastNotice(LC_TEXT("몬스터들이 성을 공격하기 시작했습니다."));
|
||||
BroadcastNotice(LC_TEXT("Monsters have started attacking your castle."));
|
||||
|
||||
LPSECTREE_MAP sectree = SECTREE_MANAGER::instance().GetMap(pInfo->nMapIndex);
|
||||
|
||||
|
@ -141,7 +141,7 @@ EVENTFUNC(battle_arena_event)
|
|||
if ( SECTREE_MANAGER::instance().GetMonsterCountInMap(pInfo->nMapIndex) <= 0 )
|
||||
{
|
||||
pInfo->state = 6;
|
||||
SendNoticeMap(LC_TEXT("중앙 제단에 악의 기운이 모여듭니다."), pInfo->nMapIndex, false);
|
||||
SendNoticeMap(LC_TEXT("Evil energy gathers at the center altar."), pInfo->nMapIndex, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -150,7 +150,7 @@ EVENTFUNC(battle_arena_event)
|
|||
if ( pInfo->wait_count >= 5 )
|
||||
{
|
||||
pInfo->state++;
|
||||
SendNoticeMap(LC_TEXT("몬스터들이 물러갈 조짐을 보입니다."), pInfo->nMapIndex, false);
|
||||
SendNoticeMap(LC_TEXT("The monsters are showing signs of retreating."), pInfo->nMapIndex, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -163,8 +163,8 @@ EVENTFUNC(battle_arena_event)
|
|||
case 4 :
|
||||
{
|
||||
pInfo->state++;
|
||||
SendNoticeMap(LC_TEXT("몬스터들이 물러가기 시작했습니다."), pInfo->nMapIndex, false);
|
||||
SendNoticeMap(LC_TEXT("잠시 후 마을로 돌아갑니다."), pInfo->nMapIndex, false);
|
||||
SendNoticeMap(LC_TEXT("The monsters began to retreat."), pInfo->nMapIndex, false);
|
||||
SendNoticeMap(LC_TEXT("After a while, you'll return to the village."), pInfo->nMapIndex, false);
|
||||
|
||||
SECTREE_MANAGER::instance().PurgeMonstersInMap(pInfo->nMapIndex);
|
||||
}
|
||||
|
@ -189,8 +189,8 @@ EVENTFUNC(battle_arena_event)
|
|||
pInfo->state++;
|
||||
pInfo->wait_count = 0;
|
||||
|
||||
SendNoticeMap(LC_TEXT("몬스터들의 대장이 나타났습니다."), pInfo->nMapIndex, false);
|
||||
SendNoticeMap(LC_TEXT("30분 내로 귀목령주를 물리쳐주세요."), pInfo->nMapIndex, false);
|
||||
SendNoticeMap(LC_TEXT("The monster boss has appeared."), pInfo->nMapIndex, false);
|
||||
SendNoticeMap(LC_TEXT("You have 30 minutes to defeat the boss."), pInfo->nMapIndex, false);
|
||||
|
||||
CBattleArena::instance().SpawnLastBoss();
|
||||
}
|
||||
|
@ -200,8 +200,8 @@ EVENTFUNC(battle_arena_event)
|
|||
{
|
||||
if ( SECTREE_MANAGER::instance().GetMonsterCountInMap(pInfo->nMapIndex) <= 0 )
|
||||
{
|
||||
SendNoticeMap(LC_TEXT("귀목령주와 그의 부하들을 모두 물리쳤습니다."), pInfo->nMapIndex, false);
|
||||
SendNoticeMap(LC_TEXT("잠시 후 마을로 돌아갑니다."), pInfo->nMapIndex, false);
|
||||
SendNoticeMap(LC_TEXT("You have defeated the boss and all of his minions."), pInfo->nMapIndex, false);
|
||||
SendNoticeMap(LC_TEXT("After a while, you'll return to the village."), pInfo->nMapIndex, false);
|
||||
|
||||
pInfo->state = 5;
|
||||
|
||||
|
@ -212,8 +212,8 @@ EVENTFUNC(battle_arena_event)
|
|||
|
||||
if ( pInfo->wait_count >= 6 )
|
||||
{
|
||||
SendNoticeMap(LC_TEXT("귀목령주가 퇴각하였습니다."), pInfo->nMapIndex, false);
|
||||
SendNoticeMap(LC_TEXT("잠시 후 마을로 돌아갑니다."), pInfo->nMapIndex, false);
|
||||
SendNoticeMap(LC_TEXT("The monsters have retreated."), pInfo->nMapIndex, false);
|
||||
SendNoticeMap(LC_TEXT("After a while, you'll return to the village."), pInfo->nMapIndex, false);
|
||||
|
||||
SECTREE_MANAGER::instance().PurgeMonstersInMap(pInfo->nMapIndex);
|
||||
SECTREE_MANAGER::instance().PurgeStonesInMap(pInfo->nMapIndex);
|
||||
|
@ -243,9 +243,9 @@ bool CBattleArena::Start(int nEmpire)
|
|||
m_nEmpire = nEmpire;
|
||||
|
||||
char szBuf[1024];
|
||||
snprintf(szBuf, sizeof(szBuf), LC_TEXT("%s의 성으로 몬스터들이 진군하고 있습니다."), EMPIRE_NAME(m_nEmpire));
|
||||
snprintf(szBuf, sizeof(szBuf), LC_TEXT("Monsters are marching on %s's castle."), EMPIRE_NAME(m_nEmpire));
|
||||
BroadcastNotice(szBuf);
|
||||
BroadcastNotice(LC_TEXT("10분 뒤 성을 공격할 예정입니다."));
|
||||
BroadcastNotice(LC_TEXT("We will attack the castle in 10 minutes."));
|
||||
|
||||
if (m_pEvent != NULL) {
|
||||
event_cancel(&m_pEvent);
|
||||
|
|
|
@ -91,7 +91,7 @@ EVENTFUNC( DragonLair_Collapse_Event )
|
|||
if (0 == pInfo->step)
|
||||
{
|
||||
char buf[512];
|
||||
snprintf(buf, 512, LC_TEXT("용가리가 %d 초만에 죽어써효ㅠㅠ"), pInfo->pLair->GetEstimatedTime());
|
||||
snprintf(buf, 512, LC_TEXT("Dragon died in %d seconds."), pInfo->pLair->GetEstimatedTime());
|
||||
SendNoticeMap(buf, pInfo->InstanceMapIndex, true);
|
||||
|
||||
pInfo->step++;
|
||||
|
@ -146,7 +146,7 @@ DWORD CDragonLair::GetEstimatedTime() const
|
|||
|
||||
void CDragonLair::OnDragonDead(LPCHARACTER pDragon)
|
||||
{
|
||||
SPDLOG_DEBUG("DragonLair: 도라곤이 죽어써효");
|
||||
SPDLOG_DEBUG("DragonLair: Dragon is dead and stale");
|
||||
|
||||
LogManager::instance().DragonSlayLog( GuildID_, pDragon->GetMobTable().dwVnum, StartTime_, get_global_time() );
|
||||
}
|
||||
|
@ -237,7 +237,7 @@ void CDragonLairManager::OnDragonDead(LPCHARACTER pDragon, DWORD KillerGuildID)
|
|||
|
||||
iter->second->OnDragonDead( pDragon );
|
||||
|
||||
// 애들 다 집으로 보내고 맵 없애기
|
||||
// 애들 다 집으로 보내고 맵 없애기
|
||||
|
||||
tag_DragonLair_Collapse_EventInfo* info;
|
||||
info = AllocEventInfo<tag_DragonLair_Collapse_EventInfo>();
|
||||
|
|
|
@ -31,7 +31,7 @@ int Gamble(std::vector<float>& vec_probs)
|
|||
return -1;
|
||||
}
|
||||
|
||||
// 가중치 테이블(prob_lst)을 받아 random_set.size()개의 index를 선택하여 random_set을 return
|
||||
// 가중치 테이블(prob_lst)을 받아 random_set.size()개의 index를 선택하여 random_set을 return
|
||||
bool MakeDistinctRandomNumberSet(std::list <float> prob_lst, OUT std::vector<int>& random_set)
|
||||
{
|
||||
int size = prob_lst.size();
|
||||
|
@ -67,11 +67,11 @@ bool MakeDistinctRandomNumberSet(std::list <float> prob_lst, OUT std::vector<int
|
|||
return true;
|
||||
}
|
||||
|
||||
/* 용혼석 Vnum에 대한 comment
|
||||
* ITEM VNUM을 10만 자리부터, FEDCBA라고 한다면
|
||||
* FE : 용혼석 종류. D : 등급
|
||||
* C : 단계 B : 강화
|
||||
* A : 여벌의 번호들...
|
||||
/* 용혼석 Vnum에 대한 comment
|
||||
* ITEM VNUM을 10만 자리부터, FEDCBA라고 한다면
|
||||
* FE : 용혼석 종류. D : 등급
|
||||
* C : 단계 B : 강화
|
||||
* A : 여벌의 번호들...
|
||||
*/
|
||||
|
||||
BYTE GetType(DWORD dwVnum)
|
||||
|
@ -169,7 +169,7 @@ bool DSManager::RefreshItemAttributes(LPITEM pDS)
|
|||
return false;
|
||||
}
|
||||
|
||||
// add_min과 add_max는 더미로 읽음.
|
||||
// add_min과 add_max는 더미로 읽음.
|
||||
int basic_apply_num, add_min, add_max;
|
||||
if (!m_pTable->GetApplyNumSettings(ds_type, grade_idx, basic_apply_num, add_min, add_max))
|
||||
{
|
||||
|
@ -315,14 +315,14 @@ int DSManager::GetDuration(const LPITEM pItem) const
|
|||
return pItem->GetDuration();
|
||||
}
|
||||
|
||||
// 용혼석을 받아서 용심을 추출하는 함수
|
||||
// 용혼석을 받아서 용심을 추출하는 함수
|
||||
bool DSManager::ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtractor)
|
||||
{
|
||||
if (NULL == ch || NULL == pItem)
|
||||
return false;
|
||||
if (pItem->IsEquipped())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("착용 중인 용혼석은 추출할 수 없습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The Dragon Stone cannot be removed."));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -366,7 +366,7 @@ bool DSManager::ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtract
|
|||
}
|
||||
LogManager::instance().ItemLog(ch, pItem, "DS_HEART_EXTRACT_FAIL", "");
|
||||
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용심 추출에 실패하였습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Remaining duration extraction failed."));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
@ -392,12 +392,12 @@ bool DSManager::ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtract
|
|||
std::string s = boost::lexical_cast <std::string> (iCharge);
|
||||
s += "%s";
|
||||
LogManager::instance().ItemLog(ch, pItem, "DS_HEART_EXTRACT_SUCCESS", s.c_str());
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용심 추출에 성공하였습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Dragon Stone remaining duration has been extracted."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 특정 용혼석을 장비창에서 제거할 때에 성공 여부를 결정하고, 실패시 부산물을 주는 함수.
|
||||
// 특정 용혼석을 장비창에서 제거할 때에 성공 여부를 결정하고, 실패시 부산물을 주는 함수.
|
||||
bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM pExtractor)
|
||||
{
|
||||
if (NULL == ch || NULL == pItem)
|
||||
|
@ -406,13 +406,13 @@ bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM
|
|||
return false;
|
||||
}
|
||||
|
||||
// 목표 위치가 valid한지 검사 후, valid하지 않다면 임의의 빈 공간을 찾는다.
|
||||
// 목표 위치가 valid한지 검사 후, valid하지 않다면 임의의 빈 공간을 찾는다.
|
||||
if (!IsValidCellForThisItem(pItem, DestCell))
|
||||
{
|
||||
int iEmptyCell = ch->GetEmptyDragonSoulInventory(pItem);
|
||||
if (iEmptyCell < 0)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("소지품에 빈 공간이 없습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("There isn't enough space in your inventory."));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
@ -430,14 +430,14 @@ bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM
|
|||
int iBonus = 0;
|
||||
float fProb;
|
||||
float fDice;
|
||||
// 용혼석 추출 성공 여부 결정.
|
||||
// 용혼석 추출 성공 여부 결정.
|
||||
{
|
||||
DWORD dwVnum = pItem->GetVnum();
|
||||
|
||||
BYTE ds_type, grade_idx, step_idx, strength_idx;
|
||||
GetDragonSoulInfo(pItem->GetVnum(), ds_type, grade_idx, step_idx, strength_idx);
|
||||
|
||||
// 추출 정보가 없다면 일단 무조건 성공하는 것이라 생각하자.
|
||||
// 추출 정보가 없다면 일단 무조건 성공하는 것이라 생각하자.
|
||||
if (!m_pTable->GetDragonSoulExtValues(ds_type, grade_idx, fProb, dwByProduct))
|
||||
{
|
||||
pItem->AddToCharacter(ch, DestCell);
|
||||
|
@ -454,7 +454,7 @@ bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM
|
|||
bSuccess = fDice <= (fProb * (100 + iBonus) / 100.f);
|
||||
}
|
||||
|
||||
// 캐릭터의 용혼석 추출 및 추가 혹은 제거. 부산물 제공.
|
||||
// 캐릭터의 용혼석 추출 및 추가 혹은 제거. 부산물 제공.
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
|
@ -469,7 +469,7 @@ bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM
|
|||
sprintf(buf, "dice(%d) prob(%d)", (int)fDice, (int)fProb);
|
||||
}
|
||||
LogManager::instance().ItemLog(ch, pItem, "DS_PULL_OUT_SUCCESS", buf);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용혼석 추출에 성공하였습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Dragon Stone has been removed."));
|
||||
pItem->AddToCharacter(ch, DestCell);
|
||||
return true;
|
||||
}
|
||||
|
@ -490,12 +490,12 @@ bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM
|
|||
{
|
||||
LPITEM pByProduct = ch->AutoGiveItem(dwByProduct, true);
|
||||
if (pByProduct)
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용혼석 추출에 실패하여 %s를 얻었습니다."), pByProduct->GetName());
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Removal of Dragon Stone failed. But you have received the following: %s"), pByProduct->GetName());
|
||||
else
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용혼석 추출에 실패하였습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Removal of Dragon Stone failed."));
|
||||
}
|
||||
else
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용혼석 추출에 실패하였습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Removal of Dragon Stone failed."));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -519,8 +519,8 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
|
|||
return false;
|
||||
}
|
||||
|
||||
// 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용
|
||||
// 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다.
|
||||
// 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용
|
||||
// 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다.
|
||||
std::set <LPITEM> set_items;
|
||||
for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++)
|
||||
{
|
||||
|
@ -529,10 +529,10 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
|
|||
LPITEM pItem = ch->GetItem(aItemPoses[i]);
|
||||
if (NULL != pItem)
|
||||
{
|
||||
// 용혼석이 아닌 아이템이 개량창에 있을 수 없다.
|
||||
// 용혼석이 아닌 아이템이 개량창에 있을 수 없다.
|
||||
if (!pItem->IsDragonSoul())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량에 필요한 재료가 아닙니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This item is not required for improving the clarity level."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
|
||||
|
||||
return false;
|
||||
|
@ -557,7 +557,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
|
|||
BYTE ds_type, grade_idx, step_idx, strength_idx;
|
||||
int result_grade;
|
||||
|
||||
// 가장 처음 것을 강화의 기준으로 삼는다.
|
||||
// 가장 처음 것을 강화의 기준으로 삼는다.
|
||||
std::set <LPITEM>::iterator it = set_items.begin();
|
||||
{
|
||||
LPITEM pItem = *it;
|
||||
|
@ -566,7 +566,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
|
|||
|
||||
if (!m_pTable->GetRefineGradeValues(ds_type, grade_idx, need_count, fee, vec_probs))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량할 수 없는 용혼석입니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This item cannot be advanced this way."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
|
||||
|
||||
return false;
|
||||
|
@ -576,8 +576,8 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
|
|||
{
|
||||
LPITEM pItem = *it;
|
||||
|
||||
// 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에,
|
||||
// 별도의 알림 처리는 안함.
|
||||
// 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에,
|
||||
// 별도의 알림 처리는 안함.
|
||||
if (pItem->IsEquipped())
|
||||
{
|
||||
return false;
|
||||
|
@ -585,14 +585,14 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
|
|||
|
||||
if (ds_type != GetType(pItem->GetVnum()) || grade_idx != GetGradeIdx(pItem->GetVnum()))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량에 필요한 재료가 아닙니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This item is not required for improving the clarity level."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 클라에서 한번 갯수 체크를 하기 때문에 count != need_count라면 invalid 클라일 가능성이 크다.
|
||||
// 클라에서 한번 갯수 체크를 하기 때문에 count != need_count라면 invalid 클라일 가능성이 크다.
|
||||
if (count != need_count)
|
||||
{
|
||||
SPDLOG_ERROR("Possiblity of invalid client. Name {}", ch->GetName());
|
||||
|
@ -603,7 +603,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
|
|||
|
||||
if (ch->GetGold() < fee)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("개량을 하기 위한 돈이 부족합니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You do not have enough Yang to use this item."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS);
|
||||
return false;
|
||||
}
|
||||
|
@ -648,7 +648,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
|
|||
char buf[128];
|
||||
sprintf(buf, "GRADE : %d -> %d", grade_idx, result_grade);
|
||||
LogManager::instance().ItemLog(ch, pResultItem, "DS_GRADE_REFINE_SUCCESS", buf);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량에 성공했습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Refinement up one class was successful."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_SUCCEED, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell()));
|
||||
return true;
|
||||
}
|
||||
|
@ -657,7 +657,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
|
|||
char buf[128];
|
||||
sprintf(buf, "GRADE : %d -> %d", grade_idx, result_grade);
|
||||
LogManager::instance().ItemLog(ch, pResultItem, "DS_GRADE_REFINE_FAIL", buf);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량에 실패했습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Refinement up one class failed."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell()));
|
||||
return false;
|
||||
}
|
||||
|
@ -679,18 +679,18 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_
|
|||
return false;
|
||||
}
|
||||
|
||||
// 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용
|
||||
// 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다.
|
||||
// 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용
|
||||
// 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다.
|
||||
std::set <LPITEM> set_items;
|
||||
for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++)
|
||||
{
|
||||
LPITEM pItem = ch->GetItem(aItemPoses[i]);
|
||||
if (NULL != pItem)
|
||||
{
|
||||
// 용혼석이 아닌 아이템이 개량창에 있을 수 없다.
|
||||
// 용혼석이 아닌 아이템이 개량창에 있을 수 없다.
|
||||
if (!pItem->IsDragonSoul())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량에 필요한 재료가 아닙니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You do not own the materials required to strengthen the Dragon Stone."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
|
||||
return false;
|
||||
}
|
||||
|
@ -713,7 +713,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_
|
|||
BYTE ds_type, grade_idx, step_idx, strength_idx;
|
||||
int result_step;
|
||||
|
||||
// 가장 처음 것을 강화의 기준으로 삼는다.
|
||||
// 가장 처음 것을 강화의 기준으로 삼는다.
|
||||
std::set <LPITEM>::iterator it = set_items.begin();
|
||||
{
|
||||
LPITEM pItem = *it;
|
||||
|
@ -721,7 +721,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_
|
|||
|
||||
if (!m_pTable->GetRefineStepValues(ds_type, step_idx, need_count, fee, vec_probs))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량할 수 없는 용혼석입니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This item is not required for refinement."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
|
||||
return false;
|
||||
}
|
||||
|
@ -730,21 +730,21 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_
|
|||
while(++it != set_items.end())
|
||||
{
|
||||
LPITEM pItem = *it;
|
||||
// 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에,
|
||||
// 별도의 알림 처리는 안함.
|
||||
// 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에,
|
||||
// 별도의 알림 처리는 안함.
|
||||
if (pItem->IsEquipped())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (ds_type != GetType(pItem->GetVnum()) || grade_idx != GetGradeIdx(pItem->GetVnum()) || step_idx != GetStepIdx(pItem->GetVnum()))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량에 필요한 재료가 아닙니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You do not own the materials required to strengthen the Dragon Stone."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 클라에서 한번 갯수 체크를 하기 때문에 count != need_count라면 invalid 클라일 가능성이 크다.
|
||||
// 클라에서 한번 갯수 체크를 하기 때문에 count != need_count라면 invalid 클라일 가능성이 크다.
|
||||
if (count != need_count)
|
||||
{
|
||||
SPDLOG_ERROR("Possiblity of invalid client. Name {}", ch->GetName());
|
||||
|
@ -755,7 +755,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_
|
|||
|
||||
if (ch->GetGold() < fee)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("개량을 하기 위한 돈이 부족합니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You do not have enough Yang to use this item."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS);
|
||||
return false;
|
||||
}
|
||||
|
@ -800,7 +800,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_
|
|||
char buf[128];
|
||||
sprintf(buf, "STEP : %d -> %d", step_idx, result_step);
|
||||
LogManager::instance().ItemLog(ch, pResultItem, "DS_STEP_REFINE_SUCCESS", buf);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량에 성공했습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Improvement of the clarity level successful."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_SUCCEED, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell()));
|
||||
return true;
|
||||
}
|
||||
|
@ -809,7 +809,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_
|
|||
char buf[128];
|
||||
sprintf(buf, "STEP : %d -> %d", step_idx, result_step);
|
||||
LogManager::instance().ItemLog(ch, pResultItem, "DS_STEP_REFINE_FAIL", buf);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량에 실패했습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Improvement of the clarity level failed."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell()));
|
||||
return false;
|
||||
}
|
||||
|
@ -840,8 +840,8 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S
|
|||
return false;
|
||||
}
|
||||
|
||||
// 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용
|
||||
// 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다.
|
||||
// 혹시나 모를 중복되는 item pointer 없애기 위해서 set 사용
|
||||
// 이상한 패킷을 보낼 경우, 중복된 TItemPos가 있을 수도 있고, 잘못된 TItemPos가 있을 수도 있다.
|
||||
std::set <LPITEM> set_items;
|
||||
for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++)
|
||||
{
|
||||
|
@ -863,15 +863,15 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S
|
|||
for (std::set <LPITEM>::iterator it = set_items.begin(); it != set_items.end(); it++)
|
||||
{
|
||||
LPITEM pItem = *it;
|
||||
// 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에,
|
||||
// 별도의 알림 처리는 안함.
|
||||
// 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에,
|
||||
// 별도의 알림 처리는 안함.
|
||||
if (pItem->IsEquipped())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 용혼석과 강화석만이 개량창에 있을 수 있다.
|
||||
// 그리고 하나씩만 있어야한다.
|
||||
// 용혼석과 강화석만이 개량창에 있을 수 있다.
|
||||
// 그리고 하나씩만 있어야한다.
|
||||
if (pItem->IsDragonSoul())
|
||||
{
|
||||
if (pDragonSoul != NULL)
|
||||
|
@ -892,7 +892,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S
|
|||
}
|
||||
else
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화에 필요한 재료가 아닙니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This item is not required for improving the clarity level."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
|
||||
return false;
|
||||
}
|
||||
|
@ -912,17 +912,17 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S
|
|||
GetDragonSoulInfo(pDragonSoul->GetVnum(), bType, bGrade, bStep, bStrength);
|
||||
|
||||
float fWeight = 0.f;
|
||||
// 가중치 값이 없다면 강화할 수 없는 용혼석
|
||||
// 가중치 값이 없다면 강화할 수 없는 용혼석
|
||||
if (!m_pTable->GetWeight(bType, bGrade, bStep, bStrength + 1, fWeight))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화할 수 없는 용혼석입니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This Dragon Stone cannot be used for strengthening."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell()));
|
||||
return false;
|
||||
}
|
||||
// 강화했을 때 가중치가 0이라면 더 이상 강화되서는 안된다.
|
||||
// 강화했을 때 가중치가 0이라면 더 이상 강화되서는 안된다.
|
||||
if (fWeight < FLT_EPSILON)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화할 수 없는 용혼석입니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This Dragon Stone cannot be used for strengthening."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell()));
|
||||
return false;
|
||||
}
|
||||
|
@ -931,7 +931,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S
|
|||
float fProb;
|
||||
if (!m_pTable->GetRefineStrengthValues(bType, pRefineStone->GetSubType(), bStrength, fee, fProb))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화할 수 없는 용혼석입니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This Dragon Stone cannot be used for strengthening."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell()));
|
||||
|
||||
return false;
|
||||
|
@ -939,7 +939,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S
|
|||
|
||||
if (ch->GetGold() < fee)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("개량을 하기 위한 돈이 부족합니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You do not have enough Yang to use this item."));
|
||||
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS);
|
||||
return false;
|
||||
}
|
||||
|
@ -967,7 +967,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S
|
|||
char buf[128];
|
||||
sprintf(buf, "STRENGTH : %d -> %d", bStrength, bStrength + 1);
|
||||
LogManager::instance().ItemLog(ch, pDragonSoul, "DS_STRENGTH_REFINE_SUCCESS", buf);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화에 성공했습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Strengthening was successful."));
|
||||
ch->AutoGiveItem(pResult, true);
|
||||
bSubHeader = DS_SUB_HEADER_REFINE_SUCCEED;
|
||||
}
|
||||
|
@ -988,10 +988,10 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S
|
|||
|
||||
char buf[128];
|
||||
sprintf(buf, "STRENGTH : %d -> %d", bStrength, bStrength - 1);
|
||||
// strength강화는 실패시 깨질 수도 있어, 원본 아이템을 바탕으로 로그를 남김.
|
||||
// strength강화는 실패시 깨질 수도 있어, 원본 아이템을 바탕으로 로그를 남김.
|
||||
LogManager::instance().ItemLog(ch, pDragonSoul, "DS_STRENGTH_REFINE_FAIL", buf);
|
||||
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화에 실패했습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Strengthening failed."));
|
||||
pDragonSoul->SetCount(pDragonSoul->GetCount() - 1);
|
||||
pRefineStone->SetCount(pRefineStone->GetCount() - 1);
|
||||
if (NULL != pResult)
|
||||
|
@ -1029,12 +1029,12 @@ int DSManager::LeftTime(LPITEM pItem) const
|
|||
if (pItem == NULL)
|
||||
return false;
|
||||
|
||||
// 일단은 timer based on wear인 용혼석만 시간 다 되어도 안 없어진다.
|
||||
// 일단은 timer based on wear인 용혼석만 시간 다 되어도 안 없어진다.
|
||||
if (pItem->GetProto()->cLimitTimerBasedOnWearIndex >= 0)
|
||||
{
|
||||
return pItem->GetSocket(ITEM_SOCKET_REMAIN_SEC);
|
||||
}
|
||||
// 다른 limit type인 용혼석들은 시간 되면 모두 사라지기 때문에 여기 들어온 아이템은 일단 시간이 남았다고 판단.
|
||||
// 다른 limit type인 용혼석들은 시간 되면 모두 사라지기 때문에 여기 들어온 아이템은 일단 시간이 남았다고 판단.
|
||||
else
|
||||
{
|
||||
return INT_MAX;
|
||||
|
@ -1046,12 +1046,12 @@ bool DSManager::IsTimeLeftDragonSoul(LPITEM pItem) const
|
|||
if (pItem == NULL)
|
||||
return false;
|
||||
|
||||
// 일단은 timer based on wear인 용혼석만 시간 다 되어도 안 없어진다.
|
||||
// 일단은 timer based on wear인 용혼석만 시간 다 되어도 안 없어진다.
|
||||
if (pItem->GetProto()->cLimitTimerBasedOnWearIndex >= 0)
|
||||
{
|
||||
return pItem->GetSocket(ITEM_SOCKET_REMAIN_SEC) > 0;
|
||||
}
|
||||
// 다른 limit type인 용혼석들은 시간 되면 모두 사라지기 때문에 여기 들어온 아이템은 일단 시간이 남았다고 판단.
|
||||
// 다른 limit type인 용혼석들은 시간 되면 모두 사라지기 때문에 여기 들어온 아이템은 일단 시간이 남았다고 판단.
|
||||
else
|
||||
{
|
||||
return true;
|
||||
|
|
|
@ -16,23 +16,23 @@ public:
|
|||
bool ReadDragonSoulTableFile(const char * c_pszFileName);
|
||||
|
||||
void GetDragonSoulInfo(DWORD dwVnum, OUT BYTE& bType, OUT BYTE& bGrade, OUT BYTE& bStep, OUT BYTE& bRefine) const;
|
||||
// fixme : titempos로
|
||||
// fixme : titempos로
|
||||
WORD GetBasePosition(const LPITEM pItem) const;
|
||||
bool IsValidCellForThisItem(const LPITEM pItem, const TItemPos& Cell) const;
|
||||
int GetDuration(const LPITEM pItem) const;
|
||||
|
||||
// 용혼석을 받아서 특정 용심을 추출하는 함수
|
||||
// 용혼석을 받아서 특정 용심을 추출하는 함수
|
||||
bool ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtractor = NULL);
|
||||
|
||||
// 특정 용혼석(pItem)을 장비창에서 제거할 때에 성공 여부를 결정하고,
|
||||
// 실패시 부산물을 주는 함수.(부산물은 dragon_soul_table.txt에 정의)
|
||||
// DestCell에 invalid한 값을 넣으면 성공 시, 용혼석을 빈 공간에 자동 추가.
|
||||
// 실패 시, 용혼석(pItem)은 delete됨.
|
||||
// 추출아이템이 있다면 추출 성공 확률이 pExtractor->GetValue(0)%만큼 증가함.
|
||||
// 부산물은 언제나 자동 추가.
|
||||
// 특정 용혼석(pItem)을 장비창에서 제거할 때에 성공 여부를 결정하고,
|
||||
// 실패시 부산물을 주는 함수.(부산물은 dragon_soul_table.txt에 정의)
|
||||
// DestCell에 invalid한 값을 넣으면 성공 시, 용혼석을 빈 공간에 자동 추가.
|
||||
// 실패 시, 용혼석(pItem)은 delete됨.
|
||||
// 추출아이템이 있다면 추출 성공 확률이 pExtractor->GetValue(0)%만큼 증가함.
|
||||
// 부산물은 언제나 자동 추가.
|
||||
bool PullOut(LPCHARACTER ch, TItemPos DestCell, IN OUT LPITEM& pItem, LPITEM pExtractor = NULL);
|
||||
|
||||
// 용혼석 업그레이드 함수
|
||||
// 용혼석 업그레이드 함수
|
||||
bool DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_REFINE_GRID_SIZE]);
|
||||
bool DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_REFINE_GRID_SIZE]);
|
||||
bool DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_REFINE_GRID_SIZE]);
|
||||
|
@ -47,7 +47,7 @@ public:
|
|||
private:
|
||||
void SendRefineResultPacket(LPCHARACTER ch, BYTE bSubHeader, const TItemPos& pos);
|
||||
|
||||
// 캐릭터의 용혼석 덱을 살펴보고, 활성화 된 용혼석이 없다면, 캐릭터의 용혼석 활성 상태를 off 시키는 함수.
|
||||
// 캐릭터의 용혼석 덱을 살펴보고, 활성화 된 용혼석이 없다면, 캐릭터의 용혼석 활성 상태를 off 시키는 함수.
|
||||
void RefreshDragonSoulState(LPCHARACTER ch);
|
||||
|
||||
DWORD MakeDragonSoulVnum(BYTE bType, BYTE grade, BYTE step, BYTE refine);
|
||||
|
|
|
@ -30,14 +30,14 @@ static Pixel * LoadOldGuildMarkImageFile()
|
|||
|
||||
bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
|
||||
{
|
||||
// 폴더 생성
|
||||
// 폴더 생성
|
||||
#ifndef __WIN32__
|
||||
mkdir("mark", S_IRWXU);
|
||||
#else
|
||||
_mkdir("mark");
|
||||
#endif
|
||||
|
||||
// 인덱스 파일이 있나?
|
||||
// 인덱스 파일이 있나?
|
||||
#ifndef __WIN32__
|
||||
if (0 != access(OLD_MARK_INDEX_FILENAME, F_OK))
|
||||
#else
|
||||
|
@ -45,13 +45,13 @@ bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
|
|||
#endif
|
||||
return true;
|
||||
|
||||
// 인덱스 파일 열기
|
||||
// 인덱스 파일 열기
|
||||
FILE* fp = fopen(OLD_MARK_INDEX_FILENAME, "r");
|
||||
|
||||
if (NULL == fp)
|
||||
return false;
|
||||
|
||||
// 이미지 파일 열기
|
||||
// 이미지 파일 열기
|
||||
Pixel * oldImagePtr = LoadOldGuildMarkImageFile();
|
||||
|
||||
if (NULL == oldImagePtr)
|
||||
|
@ -61,8 +61,8 @@ bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
|
|||
}
|
||||
|
||||
/*
|
||||
// guild_mark.tga가 실제 targa 파일이 아니고, 512 * 512 * 4 크기의 raw 파일이다.
|
||||
// 눈으로 확인하기 위해 실제 targa 파일로 만든다.
|
||||
// guild_mark.tga가 실제 targa 파일이 아니고, 512 * 512 * 4 크기의 raw 파일이다.
|
||||
// 눈으로 확인하기 위해 실제 targa 파일로 만든다.
|
||||
CGuildMarkImage * pkImage = new CGuildMarkImage;
|
||||
pkImage->Build("guild_mark_real.tga");
|
||||
pkImage->Load("guild_mark_real.tga");
|
||||
|
@ -86,7 +86,7 @@ bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
|
|||
continue;
|
||||
}
|
||||
|
||||
// mark id -> 이미지에서의 위치 찾기
|
||||
// mark id -> 이미지에서의 위치 찾기
|
||||
uint row = mark_id / 32;
|
||||
uint col = mark_id % 32;
|
||||
|
||||
|
@ -102,7 +102,7 @@ bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
|
|||
Pixel * src = oldImagePtr + sy * 512 + sx;
|
||||
Pixel * dst = mark;
|
||||
|
||||
// 옛날 이미지에서 마크 한개 복사
|
||||
// 옛날 이미지에서 마크 한개 복사
|
||||
for (int y = 0; y != SGuildMark::HEIGHT; ++y)
|
||||
{
|
||||
for (int x = 0; x != SGuildMark::WIDTH; ++x)
|
||||
|
@ -111,7 +111,7 @@ bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
|
|||
src += 512;
|
||||
}
|
||||
|
||||
// 새 길드 마크 시스템에 넣는다.
|
||||
// 새 길드 마크 시스템에 넣는다.
|
||||
CGuildMarkManager::instance().SaveMark(guild_id, (BYTE *) mark);
|
||||
line[0] = '\0';
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
|
|||
free(oldImagePtr);
|
||||
fclose(fp);
|
||||
|
||||
// 컨버트는 한번만 하면되므로 파일을 옮겨준다.
|
||||
// 컨버트는 한번만 하면되므로 파일을 옮겨준다.
|
||||
#ifndef __WIN32__
|
||||
system("mv -f guild_mark.idx guild_mark.idx.removable");
|
||||
system("mv -f guild_mark.tga guild_mark.tga.removable");
|
||||
|
|
|
@ -129,10 +129,10 @@ void CGuildMarkImage::GetData(UINT x, UINT y, UINT width, UINT height, void * da
|
|||
ilCopyPixels(x, y, 0, width, height, 1, IL_BGRA, IL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
|
||||
// 이미지 = 512x512
|
||||
// 블럭 = 마크 4 x 4
|
||||
// 마크 = 16 x 12
|
||||
// 한 이미지의 블럭 = 8 x 10
|
||||
// 이미지 = 512x512
|
||||
// 블럭 = 마크 4 x 4
|
||||
// 마크 = 16 x 12
|
||||
// 한 이미지의 블럭 = 8 x 10
|
||||
|
||||
// SERVER
|
||||
bool CGuildMarkImage::SaveMark(DWORD posMark, BYTE * pbImage)
|
||||
|
@ -143,14 +143,14 @@ bool CGuildMarkImage::SaveMark(DWORD posMark, BYTE * pbImage)
|
|||
return false;
|
||||
}
|
||||
|
||||
// 마크를 전체 이미지에 그린다.
|
||||
// 마크를 전체 이미지에 그린다.
|
||||
DWORD colMark = posMark % MARK_COL_COUNT;
|
||||
DWORD rowMark = posMark / MARK_COL_COUNT;
|
||||
|
||||
printf("PutMark pos %u %ux%u\n", posMark, colMark * SGuildMark::WIDTH, rowMark * SGuildMark::HEIGHT);
|
||||
PutData(colMark * SGuildMark::WIDTH, rowMark * SGuildMark::HEIGHT, SGuildMark::WIDTH, SGuildMark::HEIGHT, pbImage);
|
||||
|
||||
// 그려진 곳의 블럭을 업데이트
|
||||
// 그려진 곳의 블럭을 업데이트
|
||||
DWORD rowBlock = rowMark / SGuildMarkBlock::MARK_PER_BLOCK_HEIGHT;
|
||||
DWORD colBlock = colMark / SGuildMarkBlock::MARK_PER_BLOCK_WIDTH;
|
||||
|
||||
|
@ -197,7 +197,7 @@ bool CGuildMarkImage::SaveBlockFromCompressedData(DWORD posBlock, const BYTE * p
|
|||
return true;
|
||||
}
|
||||
|
||||
void CGuildMarkImage::BuildAllBlocks() // 이미지 전체를 블럭화
|
||||
void CGuildMarkImage::BuildAllBlocks() // 이미지 전체를 블럭화
|
||||
{
|
||||
Pixel apxBuf[SGuildMarkBlock::SIZE];
|
||||
SPDLOG_INFO("GuildMarkImage::BuildAllBlocks");
|
||||
|
|
|
@ -16,7 +16,7 @@ struct SGuildMark
|
|||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
Pixel m_apxBuf[SIZE]; // 실제 이미지
|
||||
Pixel m_apxBuf[SIZE]; // 실제 이미지
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void Clear();
|
||||
|
@ -38,11 +38,11 @@ struct SGuildMarkBlock
|
|||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
Pixel m_apxBuf[SIZE]; // 실제 이미지
|
||||
Pixel m_apxBuf[SIZE]; // 실제 이미지
|
||||
|
||||
BYTE m_abCompBuf[MAX_COMP_SIZE]; // 압축된 데이터
|
||||
lzo_uint m_sizeCompBuf; // 압축된 크기
|
||||
DWORD m_crc; // 압축된 데이터의 CRC
|
||||
BYTE m_abCompBuf[MAX_COMP_SIZE]; // 압축된 데이터
|
||||
lzo_uint m_sizeCompBuf; // 압축된 크기
|
||||
DWORD m_crc; // 압축된 데이터의 CRC
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
DWORD GetCRC() const;
|
||||
|
@ -87,9 +87,9 @@ class CGuildMarkImage
|
|||
|
||||
bool SaveMark(DWORD posMark, BYTE * pbMarkImage);
|
||||
bool DeleteMark(DWORD posMark);
|
||||
bool SaveBlockFromCompressedData(DWORD posBlock, const BYTE * pbComp, DWORD dwCompSize); // 서버 -> 클라이언트
|
||||
bool SaveBlockFromCompressedData(DWORD posBlock, const BYTE * pbComp, DWORD dwCompSize); // 서버 -> 클라이언트
|
||||
|
||||
DWORD GetEmptyPosition(); // 빈 마크 위치를 얻는다.
|
||||
DWORD GetEmptyPosition(); // 빈 마크 위치를 얻는다.
|
||||
|
||||
void GetBlockCRCList(DWORD * crcList);
|
||||
void GetDiffBlocks(const DWORD * crcList, std::map<BYTE, const SGuildMarkBlock *> & mapDiffBlocks);
|
||||
|
|
|
@ -15,7 +15,7 @@ void CGuildMarkManager::__DeleteImage(CGuildMarkImage * pkImgDel)
|
|||
|
||||
CGuildMarkManager::CGuildMarkManager()
|
||||
{
|
||||
// 남은 mark id 셋을 만든다. (서버용)
|
||||
// 남은 mark id 셋을 만든다. (서버용)
|
||||
for (DWORD i = 0; i < MAX_IMAGE_COUNT * CGuildMarkImage::MARK_TOTAL_COUNT; ++i)
|
||||
m_setFreeMarkID.insert(i);
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ void CGuildMarkManager::SetMarkPathPrefix(const char * prefix)
|
|||
m_pathPrefix = prefix;
|
||||
}
|
||||
|
||||
// 마크 인덱스 불러오기 (서버에서만 사용)
|
||||
// 마크 인덱스 불러오기 (서버에서만 사용)
|
||||
bool CGuildMarkManager::LoadMarkIndex()
|
||||
{
|
||||
char buf[64];
|
||||
|
@ -177,7 +177,7 @@ DWORD CGuildMarkManager::__AllocMarkID(DWORD guildID)
|
|||
DWORD markID = *it;
|
||||
|
||||
DWORD imgIdx = markID / CGuildMarkImage::MARK_TOTAL_COUNT;
|
||||
CGuildMarkImage * pkImage = __GetImage(imgIdx); // 이미지가 없다면 만들기 위해
|
||||
CGuildMarkImage * pkImage = __GetImage(imgIdx); // 이미지가 없다면 만들기 위해
|
||||
|
||||
if (pkImage && AddMarkIDByGuildID(guildID, markID))
|
||||
return markID;
|
||||
|
@ -263,7 +263,7 @@ void CGuildMarkManager::GetDiffBlocks(DWORD imgIdx, const DWORD * crcList, std::
|
|||
{
|
||||
mapDiffBlocks.clear();
|
||||
|
||||
// 클라이언트에서 서버에 없는 이미지를 요청할 수는 없다.
|
||||
// 클라이언트에서 서버에 없는 이미지를 요청할 수는 없다.
|
||||
if (m_mapIdx_Image.end() == m_mapIdx_Image.find(imgIdx))
|
||||
{
|
||||
SPDLOG_ERROR("invalid idx {}", imgIdx);
|
||||
|
@ -290,7 +290,7 @@ bool CGuildMarkManager::SaveBlockFromCompressedData(DWORD imgIdx, DWORD posBlock
|
|||
// CLIENT
|
||||
bool CGuildMarkManager::GetBlockCRCList(DWORD imgIdx, DWORD * crcList)
|
||||
{
|
||||
// 클라이언트에서 서버에 없는 이미지를 요청할 수는 없다.
|
||||
// 클라이언트에서 서버에 없는 이미지를 요청할 수는 없다.
|
||||
if (m_mapIdx_Image.end() == m_mapIdx_Image.find(imgIdx))
|
||||
{
|
||||
SPDLOG_ERROR("invalid idx {}", imgIdx);
|
||||
|
|
|
@ -32,11 +32,11 @@ class CGuildMarkManager : public singleton<CGuildMarkManager>
|
|||
//
|
||||
void SetMarkPathPrefix(const char * prefix);
|
||||
|
||||
bool LoadMarkIndex(); // 마크 인덱스 불러오기 (서버에서만 사용)
|
||||
bool SaveMarkIndex(); // 마크 인덱스 저장하기
|
||||
bool LoadMarkIndex(); // 마크 인덱스 불러오기 (서버에서만 사용)
|
||||
bool SaveMarkIndex(); // 마크 인덱스 저장하기
|
||||
|
||||
void LoadMarkImages(); // 모든 마크 이미지를 불러오기
|
||||
void SaveMarkImage(DWORD imgIdx); // 마크 이미지 저장
|
||||
void LoadMarkImages(); // 모든 마크 이미지를 불러오기
|
||||
void SaveMarkImage(DWORD imgIdx); // 마크 이미지 저장
|
||||
|
||||
bool GetMarkImageFilename(DWORD imgIdx, std::string & path) const;
|
||||
bool AddMarkIDByGuildID(DWORD guildID, DWORD markID);
|
||||
|
|
|
@ -155,11 +155,11 @@ bool COXEventManager::ShowQuizList(LPCHARACTER pkChar)
|
|||
{
|
||||
for (size_t j = 0; j < m_vec_quiz[i].size(); ++j, ++c)
|
||||
{
|
||||
pkChar->ChatPacket(CHAT_TYPE_INFO, "%d %s %s", m_vec_quiz[i][j].level, m_vec_quiz[i][j].Quiz, m_vec_quiz[i][j].answer ? LC_TEXT("참") : LC_TEXT("거짓"));
|
||||
pkChar->ChatPacket(CHAT_TYPE_INFO, "%d %s %s", m_vec_quiz[i][j].level, m_vec_quiz[i][j].Quiz, m_vec_quiz[i][j].answer ? LC_TEXT("TRUE") : LC_TEXT("FALSE"));
|
||||
}
|
||||
}
|
||||
|
||||
pkChar->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("총 퀴즈 수: %d"), c);
|
||||
pkChar->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Total number of the Quiz: %d"), c);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -197,22 +197,22 @@ EVENTFUNC(oxevent_timer)
|
|||
switch (flag)
|
||||
{
|
||||
case 0:
|
||||
SendNoticeMap(LC_TEXT("10초뒤 판정하겠습니다."), OXEVENT_MAP_INDEX, true);
|
||||
SendNoticeMap(LC_TEXT("The result will follow in 10 seconds."), OXEVENT_MAP_INDEX, true);
|
||||
flag++;
|
||||
return PASSES_PER_SEC(10);
|
||||
|
||||
case 1:
|
||||
SendNoticeMap(LC_TEXT("정답은"), OXEVENT_MAP_INDEX, true);
|
||||
SendNoticeMap(LC_TEXT("The correct answer is:"), OXEVENT_MAP_INDEX, true);
|
||||
|
||||
if (info->answer == true)
|
||||
{
|
||||
COXEventManager::instance().CheckAnswer(true);
|
||||
SendNoticeMap(LC_TEXT("O 입니다"), OXEVENT_MAP_INDEX, true);
|
||||
SendNoticeMap(LC_TEXT("Yes (O)"), OXEVENT_MAP_INDEX, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
COXEventManager::instance().CheckAnswer(false);
|
||||
SendNoticeMap(LC_TEXT("X 입니다"), OXEVENT_MAP_INDEX, true);
|
||||
SendNoticeMap(LC_TEXT("No (X)"), OXEVENT_MAP_INDEX, true);
|
||||
}
|
||||
|
||||
if (LC_IsJapan())
|
||||
|
@ -221,7 +221,7 @@ EVENTFUNC(oxevent_timer)
|
|||
}
|
||||
else
|
||||
{
|
||||
SendNoticeMap(LC_TEXT("5초 뒤 틀리신 분들을 바깥으로 이동 시키겠습니다."), OXEVENT_MAP_INDEX, true);
|
||||
SendNoticeMap(LC_TEXT("In 5 sec. everyone who gave an incorrect answer will be removed."), OXEVENT_MAP_INDEX, true);
|
||||
}
|
||||
|
||||
flag++;
|
||||
|
@ -230,7 +230,7 @@ EVENTFUNC(oxevent_timer)
|
|||
case 2:
|
||||
COXEventManager::instance().WarpToAudience();
|
||||
COXEventManager::instance().SetStatus(OXEVENT_CLOSE);
|
||||
SendNoticeMap(LC_TEXT("다음 문제 준비해주세요."), OXEVENT_MAP_INDEX, true);
|
||||
SendNoticeMap(LC_TEXT("Ready for the next question?"), OXEVENT_MAP_INDEX, true);
|
||||
flag = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -247,9 +247,9 @@ bool COXEventManager::Quiz(unsigned char level, int timelimit)
|
|||
|
||||
int idx = Random::get<int>(0, m_vec_quiz[level].size() - 1);
|
||||
|
||||
SendNoticeMap(LC_TEXT("문제 입니다."), OXEVENT_MAP_INDEX, true);
|
||||
SendNoticeMap(LC_TEXT("OX-Question: "), OXEVENT_MAP_INDEX, true);
|
||||
SendNoticeMap(m_vec_quiz[level][idx].Quiz, OXEVENT_MAP_INDEX, true);
|
||||
SendNoticeMap(LC_TEXT("맞으면 O, 틀리면 X로 이동해주세요"), OXEVENT_MAP_INDEX, true);
|
||||
SendNoticeMap(LC_TEXT("If it's correct, then go to O. If it's wrong, go to X."), OXEVENT_MAP_INDEX, true);
|
||||
|
||||
if (m_timedEvent != NULL) {
|
||||
event_cancel(&m_timedEvent);
|
||||
|
@ -312,17 +312,17 @@ bool COXEventManager::CheckAnswer(bool answer)
|
|||
}
|
||||
else
|
||||
{
|
||||
pkChar->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("정답입니다!"));
|
||||
pkChar->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Correct!"));
|
||||
// pkChar->CreateFly(Random::get(FLY_FIREWORK1, FLY_FIREWORK6), pkChar);
|
||||
char chatbuf[256];
|
||||
int len = snprintf(chatbuf, sizeof(chatbuf),
|
||||
"%s %u %u", Random::get(0, 1) == 1 ? "cheer1" : "cheer2", (DWORD)pkChar->GetVID(), 0);
|
||||
|
||||
// 리턴값이 sizeof(chatbuf) 이상일 경우 truncate되었다는 뜻..
|
||||
// 리턴값이 sizeof(chatbuf) 이상일 경우 truncate되었다는 뜻..
|
||||
if (len < 0 || len >= (int) sizeof(chatbuf))
|
||||
len = sizeof(chatbuf) - 1;
|
||||
|
||||
// \0 문자 포함
|
||||
// \0 문자 포함
|
||||
++len;
|
||||
|
||||
TPacketGCChat pack_chat;
|
||||
|
|
|
@ -10,10 +10,10 @@ struct tag_Quiz
|
|||
|
||||
enum OXEventStatus
|
||||
{
|
||||
OXEVENT_FINISH = 0, // OX이벤트가 완전히 끝난 상태
|
||||
OXEVENT_OPEN = 1, // OX이벤트가 시작됨. 을두지(20012)를 통해서 입장가능
|
||||
OXEVENT_CLOSE = 2, // OX이벤트의 참가가 끝남. 을두지(20012)를 통한 입장이 차단됨
|
||||
OXEVENT_QUIZ = 3, // 퀴즈를 출제함.
|
||||
OXEVENT_FINISH = 0, // OX이벤트가 완전히 끝난 상태
|
||||
OXEVENT_OPEN = 1, // OX이벤트가 시작됨. 을두지(20012)를 통해서 입장가능
|
||||
OXEVENT_CLOSE = 2, // OX이벤트의 참가가 끝남. 을두지(20012)를 통한 입장이 차단됨
|
||||
OXEVENT_QUIZ = 3, // 퀴즈를 출제함.
|
||||
|
||||
OXEVENT_ERR = 0xff
|
||||
};
|
||||
|
|
|
@ -18,13 +18,13 @@ EVENTINFO(petsystem_event_info)
|
|||
CPetSystem* pPetSystem;
|
||||
};
|
||||
|
||||
// PetSystem을 update 해주는 event.
|
||||
// PetSystem은 CHRACTER_MANAGER에서 기존 FSM으로 update 해주는 기존 chracters와 달리,
|
||||
// Owner의 STATE를 update 할 때 _UpdateFollowAI 함수로 update 해준다.
|
||||
// 그런데 owner의 state를 update를 CHRACTER_MANAGER에서 해주기 때문에,
|
||||
// petsystem을 update하다가 pet을 unsummon하는 부분에서 문제가 생겼다.
|
||||
// (CHRACTER_MANAGER에서 update 하면 chracter destroy가 pending되어, CPetSystem에서는 dangling 포인터를 가지고 있게 된다.)
|
||||
// 따라서 PetSystem만 업데이트 해주는 event를 발생시킴.
|
||||
// PetSystem을 update 해주는 event.
|
||||
// PetSystem은 CHRACTER_MANAGER에서 기존 FSM으로 update 해주는 기존 chracters와 달리,
|
||||
// Owner의 STATE를 update 할 때 _UpdateFollowAI 함수로 update 해준다.
|
||||
// 그런데 owner의 state를 update를 CHRACTER_MANAGER에서 해주기 때문에,
|
||||
// petsystem을 update하다가 pet을 unsummon하는 부분에서 문제가 생겼다.
|
||||
// (CHRACTER_MANAGER에서 update 하면 chracter destroy가 pending되어, CPetSystem에서는 dangling 포인터를 가지고 있게 된다.)
|
||||
// 따라서 PetSystem만 업데이트 해주는 event를 발생시킴.
|
||||
EVENTFUNC(petsystem_update_event)
|
||||
{
|
||||
petsystem_event_info* info = dynamic_cast<petsystem_event_info*>( event->info );
|
||||
|
@ -41,12 +41,12 @@ EVENTFUNC(petsystem_update_event)
|
|||
|
||||
|
||||
pPetSystem->Update(0);
|
||||
// 0.25초마다 갱신.
|
||||
// 0.25초마다 갱신.
|
||||
return PASSES_PER_SEC(1) / 4;
|
||||
}
|
||||
|
||||
/// NOTE: 1캐릭터가 몇개의 펫을 가질 수 있는지 제한... 캐릭터마다 개수를 다르게 할거라면 변수로 넣등가... 음..
|
||||
/// 가질 수 있는 개수와 동시에 소환할 수 있는 개수가 틀릴 수 있는데 이런건 기획 없으니 일단 무시
|
||||
/// NOTE: 1캐릭터가 몇개의 펫을 가질 수 있는지 제한... 캐릭터마다 개수를 다르게 할거라면 변수로 넣등가... 음..
|
||||
/// 가질 수 있는 개수와 동시에 소환할 수 있는 개수가 틀릴 수 있는데 이런건 기획 없으니 일단 무시
|
||||
const float PET_COUNT_LIMIT = 3;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -119,7 +119,7 @@ void CPetActor::Unsummon()
|
|||
{
|
||||
if (true == this->IsSummoned())
|
||||
{
|
||||
// 버프 삭제
|
||||
// 버프 삭제
|
||||
this->ClearBuff();
|
||||
this->SetSummonItem(NULL);
|
||||
if (NULL != m_pkOwner)
|
||||
|
@ -175,14 +175,14 @@ DWORD CPetActor::Summon(const char* petName, LPITEM pSummonItem, bool bSpawnFar)
|
|||
// m_pkOwner->DetailLog();
|
||||
// m_pkChar->DetailLog();
|
||||
|
||||
//펫의 국가를 주인의 국가로 설정함.
|
||||
//펫의 국가를 주인의 국가로 설정함.
|
||||
m_pkChar->SetEmpire(m_pkOwner->GetEmpire());
|
||||
|
||||
m_dwVID = m_pkChar->GetVID();
|
||||
|
||||
this->SetName(petName);
|
||||
|
||||
// SetSummonItem(pSummonItem)를 부른 후에 ComputePoints를 부르면 버프 적용됨.
|
||||
// SetSummonItem(pSummonItem)를 부른 후에 ComputePoints를 부르면 버프 적용됨.
|
||||
this->SetSummonItem(pSummonItem);
|
||||
m_pkOwner->ComputePoints();
|
||||
m_pkChar->Show(m_pkOwner->GetMapIndex(), x, y, z);
|
||||
|
@ -197,11 +197,11 @@ bool CPetActor::_UpdatAloneActionAI(float fMinDist, float fMaxDist)
|
|||
float dest_x = GetOwner()->GetX() + fDist * cos(r);
|
||||
float dest_y = GetOwner()->GetY() + fDist * sin(r);
|
||||
|
||||
//m_pkChar->SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
|
||||
//m_pkChar->SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
|
||||
|
||||
//GetDeltaByDegree(m_pkChar->GetRotation(), fDist, &fx, &fy);
|
||||
|
||||
// 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다.
|
||||
// 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다.
|
||||
//if (!(SECTREE_MANAGER::instance().IsMovablePosition(m_pkChar->GetMapIndex(), m_pkChar->GetX() + (int) fx, m_pkChar->GetY() + (int) fy)
|
||||
// && SECTREE_MANAGER::instance().IsMovablePosition(m_pkChar->GetMapIndex(), m_pkChar->GetX() + (int) fx/2, m_pkChar->GetY() + (int) fy/2)))
|
||||
// return true;
|
||||
|
@ -218,7 +218,7 @@ bool CPetActor::_UpdatAloneActionAI(float fMinDist, float fMaxDist)
|
|||
return true;
|
||||
}
|
||||
|
||||
// char_state.cpp StateHorse함수 그냥 C&P -_-;
|
||||
// char_state.cpp StateHorse함수 그냥 C&P -_-;
|
||||
bool CPetActor::_UpdateFollowAI()
|
||||
{
|
||||
if (0 == m_pkChar->m_pkMobData)
|
||||
|
@ -227,9 +227,9 @@ bool CPetActor::_UpdateFollowAI()
|
|||
return false;
|
||||
}
|
||||
|
||||
// NOTE: 캐릭터(펫)의 원래 이동 속도를 알아야 하는데, 해당 값(m_pkChar->m_pkMobData->m_table.sMovingSpeed)을 직접적으로 접근해서 알아낼 수도 있지만
|
||||
// m_pkChar->m_pkMobData 값이 invalid한 경우가 자주 발생함. 현재 시간관계상 원인은 다음에 파악하고 일단은 m_pkChar->m_pkMobData 값을 아예 사용하지 않도록 함.
|
||||
// 여기서 매번 검사하는 이유는 최초 초기화 할 때 정상 값을 제대로 못얻어오는 경우도 있음.. -_-;; ㅠㅠㅠㅠㅠㅠㅠㅠㅠ
|
||||
// NOTE: 캐릭터(펫)의 원래 이동 속도를 알아야 하는데, 해당 값(m_pkChar->m_pkMobData->m_table.sMovingSpeed)을 직접적으로 접근해서 알아낼 수도 있지만
|
||||
// m_pkChar->m_pkMobData 값이 invalid한 경우가 자주 발생함. 현재 시간관계상 원인은 다음에 파악하고 일단은 m_pkChar->m_pkMobData 값을 아예 사용하지 않도록 함.
|
||||
// 여기서 매번 검사하는 이유는 최초 초기화 할 때 정상 값을 제대로 못얻어오는 경우도 있음.. -_-;; ㅠㅠㅠㅠㅠㅠㅠㅠㅠ
|
||||
if (0 == m_originalMoveSpeed)
|
||||
{
|
||||
const CMob* mobData = CMobManager::Instance().Get(m_dwVnum);
|
||||
|
@ -237,14 +237,14 @@ bool CPetActor::_UpdateFollowAI()
|
|||
if (0 != mobData)
|
||||
m_originalMoveSpeed = mobData->m_table.sMovingSpeed;
|
||||
}
|
||||
float START_FOLLOW_DISTANCE = 300.0f; // 이 거리 이상 떨어지면 쫓아가기 시작함
|
||||
float START_RUN_DISTANCE = 900.0f; // 이 거리 이상 떨어지면 뛰어서 쫓아감.
|
||||
float START_FOLLOW_DISTANCE = 300.0f; // 이 거리 이상 떨어지면 쫓아가기 시작함
|
||||
float START_RUN_DISTANCE = 900.0f; // 이 거리 이상 떨어지면 뛰어서 쫓아감.
|
||||
|
||||
float RESPAWN_DISTANCE = 4500.f; // 이 거리 이상 멀어지면 주인 옆으로 소환함.
|
||||
int APPROACH = 200; // 접근 거리
|
||||
float RESPAWN_DISTANCE = 4500.f; // 이 거리 이상 멀어지면 주인 옆으로 소환함.
|
||||
int APPROACH = 200; // 접근 거리
|
||||
|
||||
bool bDoMoveAlone = true; // 캐릭터와 가까이 있을 때 혼자 여기저기 움직일건지 여부 -_-;
|
||||
bool bRun = false; // 뛰어야 하나?
|
||||
bool bDoMoveAlone = true; // 캐릭터와 가까이 있을 때 혼자 여기저기 움직일건지 여부 -_-;
|
||||
bool bRun = false; // 뛰어야 하나?
|
||||
|
||||
DWORD currentTime = get_dword_time();
|
||||
|
||||
|
@ -272,7 +272,7 @@ bool CPetActor::_UpdateFollowAI()
|
|||
bRun = true;
|
||||
}
|
||||
|
||||
m_pkChar->SetNowWalking(!bRun); // NOTE: 함수 이름보고 멈추는건줄 알았는데 SetNowWalking(false) 하면 뛰는거임.. -_-;
|
||||
m_pkChar->SetNowWalking(!bRun); // NOTE: 함수 이름보고 멈추는건줄 알았는데 SetNowWalking(false) 하면 뛰는거임.. -_-;
|
||||
|
||||
Follow(APPROACH);
|
||||
|
||||
|
@ -288,7 +288,7 @@ bool CPetActor::_UpdateFollowAI()
|
|||
// m_dwLastActionTime = currentTime;
|
||||
// }
|
||||
//}
|
||||
// Follow 중이지만 주인과 일정 거리 이내로 가까워졌다면 멈춤
|
||||
// Follow 중이지만 주인과 일정 거리 이내로 가까워졌다면 멈춤
|
||||
else
|
||||
m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
|
||||
//else if (currentTime - m_dwLastActionTime > Random::get(5000, 12000))
|
||||
|
@ -303,8 +303,8 @@ bool CPetActor::Update(DWORD deltaTime)
|
|||
{
|
||||
bool bResult = true;
|
||||
|
||||
// 펫 주인이 죽었거나, 소환된 펫의 상태가 이상하다면 펫을 없앰. (NOTE: 가끔가다 이런 저런 이유로 소환된 펫이 DEAD 상태에 빠지는 경우가 있음-_-;)
|
||||
// 펫을 소환한 아이템이 없거나, 내가 가진 상태가 아니라면 펫을 없앰.
|
||||
// 펫 주인이 죽었거나, 소환된 펫의 상태가 이상하다면 펫을 없앰. (NOTE: 가끔가다 이런 저런 이유로 소환된 펫이 DEAD 상태에 빠지는 경우가 있음-_-;)
|
||||
// 펫을 소환한 아이템이 없거나, 내가 가진 상태가 아니라면 펫을 없앰.
|
||||
if (m_pkOwner->IsDead() || (IsSummoned() && m_pkChar->IsDead())
|
||||
|| NULL == ITEM_MANAGER::instance().FindByVID(this->GetSummonItemVID())
|
||||
|| ITEM_MANAGER::instance().FindByVID(this->GetSummonItemVID())->GetOwner() != this->GetOwner()
|
||||
|
@ -320,10 +320,10 @@ bool CPetActor::Update(DWORD deltaTime)
|
|||
return bResult;
|
||||
}
|
||||
|
||||
//NOTE : 주의!!! MinDistance를 크게 잡으면 그 변위만큼의 변화동안은 follow하지 않는다,
|
||||
//NOTE : 주의!!! MinDistance를 크게 잡으면 그 변위만큼의 변화동안은 follow하지 않는다,
|
||||
bool CPetActor::Follow(float fMinDistance)
|
||||
{
|
||||
// 가려는 위치를 바라봐야 한다.
|
||||
// 가려는 위치를 바라봐야 한다.
|
||||
if( !m_pkOwner || !m_pkChar)
|
||||
return false;
|
||||
|
||||
|
@ -367,7 +367,7 @@ void CPetActor::SetSummonItem (LPITEM pItem)
|
|||
|
||||
void CPetActor::GiveBuff()
|
||||
{
|
||||
// 파황 펫 버프는 던전에서만 발생함.
|
||||
// 파황 펫 버프는 던전에서만 발생함.
|
||||
if (34004 == m_dwVnum || 34009 == m_dwVnum)
|
||||
{
|
||||
if (NULL == m_pkOwner->GetDungeon())
|
||||
|
@ -432,15 +432,15 @@ void CPetSystem::Destroy()
|
|||
m_petActorMap.clear();
|
||||
}
|
||||
|
||||
/// 펫 시스템 업데이트. 등록된 펫들의 AI 처리 등을 함.
|
||||
/// 펫 시스템 업데이트. 등록된 펫들의 AI 처리 등을 함.
|
||||
bool CPetSystem::Update(DWORD deltaTime)
|
||||
{
|
||||
bool bResult = true;
|
||||
|
||||
DWORD currentTime = get_dword_time();
|
||||
|
||||
// CHARACTER_MANAGER에서 캐릭터류 Update할 때 매개변수로 주는 (Pulse라고 되어있는)값이 이전 프레임과의 시간차이인줄 알았는데
|
||||
// 전혀 다른 값이라서-_-; 여기에 입력으로 들어오는 deltaTime은 의미가 없음ㅠㅠ
|
||||
// CHARACTER_MANAGER에서 캐릭터류 Update할 때 매개변수로 주는 (Pulse라고 되어있는)값이 이전 프레임과의 시간차이인줄 알았는데
|
||||
// 전혀 다른 값이라서-_-; 여기에 입력으로 들어오는 deltaTime은 의미가 없음ㅠㅠ
|
||||
|
||||
if (m_dwUpdatePeriod > currentTime - m_dwLastUpdateTime)
|
||||
return true;
|
||||
|
@ -473,7 +473,7 @@ bool CPetSystem::Update(DWORD deltaTime)
|
|||
return bResult;
|
||||
}
|
||||
|
||||
/// 관리 목록에서 펫을 지움
|
||||
/// 관리 목록에서 펫을 지움
|
||||
void CPetSystem::DeletePet(DWORD mobVnum)
|
||||
{
|
||||
TPetActorMap::iterator iter = m_petActorMap.find(mobVnum);
|
||||
|
@ -494,7 +494,7 @@ void CPetSystem::DeletePet(DWORD mobVnum)
|
|||
m_petActorMap.erase(iter);
|
||||
}
|
||||
|
||||
/// 관리 목록에서 펫을 지움
|
||||
/// 관리 목록에서 펫을 지움
|
||||
void CPetSystem::DeletePet(CPetActor* petActor)
|
||||
{
|
||||
for (TPetActorMap::iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter)
|
||||
|
@ -542,7 +542,7 @@ CPetActor* CPetSystem::Summon(DWORD mobVnum, LPITEM pSummonItem, const char* pet
|
|||
{
|
||||
CPetActor* petActor = this->GetByVnum(mobVnum);
|
||||
|
||||
// 등록된 펫이 아니라면 새로 생성 후 관리 목록에 등록함.
|
||||
// 등록된 펫이 아니라면 새로 생성 후 관리 목록에 등록함.
|
||||
if (0 == petActor)
|
||||
{
|
||||
petActor = M2_NEW CPetActor(m_pkOwner, mobVnum, options);
|
||||
|
@ -557,7 +557,7 @@ CPetActor* CPetSystem::Summon(DWORD mobVnum, LPITEM pSummonItem, const char* pet
|
|||
|
||||
info->pPetSystem = this;
|
||||
|
||||
m_pkPetSystemUpdateEvent = event_create(petsystem_update_event, info, PASSES_PER_SEC(1) / 4); // 0.25초
|
||||
m_pkPetSystemUpdateEvent = event_create(petsystem_update_event, info, PASSES_PER_SEC(1) / 4); // 0.25초
|
||||
}
|
||||
|
||||
return petActor;
|
||||
|
@ -589,7 +589,7 @@ CPetActor* CPetSystem::GetByVID(DWORD vid) const
|
|||
return bFound ? petActor : 0;
|
||||
}
|
||||
|
||||
/// 등록 된 펫 중에서 주어진 몹 VNUM을 가진 액터를 반환하는 함수.
|
||||
/// 등록 된 펫 중에서 주어진 몹 VNUM을 가진 액터를 반환하는 함수.
|
||||
CPetActor* CPetSystem::GetByVnum(DWORD vnum) const
|
||||
{
|
||||
CPetActor* petActor = 0;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
class CHARACTER;
|
||||
|
||||
// TODO: 펫으로서의 능력치? 라던가 친밀도, 배고픔 기타등등... 수치
|
||||
// TODO: 펫으로서의 능력치? 라던가 친밀도, 배고픔 기타등등... 수치
|
||||
struct SPetAbility
|
||||
{
|
||||
};
|
||||
|
@ -34,8 +34,8 @@ protected:
|
|||
virtual bool Update(DWORD deltaTime);
|
||||
|
||||
protected:
|
||||
virtual bool _UpdateFollowAI(); ///< 주인을 따라다니는 AI 처리
|
||||
virtual bool _UpdatAloneActionAI(float fMinDist, float fMaxDist); ///< 주인 근처에서 혼자 노는 AI 처리
|
||||
virtual bool _UpdateFollowAI(); ///< 주인을 따라다니는 AI 처리
|
||||
virtual bool _UpdatAloneActionAI(float fMinDist, float fMaxDist); ///< 주인 근처에서 혼자 노는 AI 처리
|
||||
|
||||
/// @TODO
|
||||
//virtual bool _UpdateCombatAI();
|
||||
|
@ -62,13 +62,13 @@ public:
|
|||
bool IsSummoned() const { return 0 != m_pkChar; }
|
||||
void SetSummonItem (LPITEM pItem);
|
||||
DWORD GetSummonItemVID () { return m_dwSummonItemVID; }
|
||||
// 버프 주는 함수와 거두는 함수.
|
||||
// 이게 좀 괴랄한게, 서버가 ㅄ라서,
|
||||
// POINT_MOV_SPEED, POINT_ATT_SPEED, POINT_CAST_SPEED는 PointChange()란 함수만 써서 변경해 봐야 소용이 없는게,
|
||||
// PointChange() 이후에 어디선가 ComputePoints()를 하면 싹다 초기화되고,
|
||||
// 더 웃긴건, ComputePoints()를 부르지 않으면 클라의 POINT는 전혀 변하지 않는다는 거다.
|
||||
// 그래서 버프를 주는 것은 ComputePoints() 내부에서 petsystem->RefreshBuff()를 부르도록 하였고,
|
||||
// 버프를 빼는 것은 ClearBuff()를 부르고, ComputePoints를 하는 것으로 한다.
|
||||
// 버프 주는 함수와 거두는 함수.
|
||||
// 이게 좀 괴랄한게, 서버가 ㅄ라서,
|
||||
// POINT_MOV_SPEED, POINT_ATT_SPEED, POINT_CAST_SPEED는 PointChange()란 함수만 써서 변경해 봐야 소용이 없는게,
|
||||
// PointChange() 이후에 어디선가 ComputePoints()를 하면 싹다 초기화되고,
|
||||
// 더 웃긴건, ComputePoints()를 부르지 않으면 클라의 POINT는 전혀 변하지 않는다는 거다.
|
||||
// 그래서 버프를 주는 것은 ComputePoints() 내부에서 petsystem->RefreshBuff()를 부르도록 하였고,
|
||||
// 버프를 빼는 것은 ClearBuff()를 부르고, ComputePoints를 하는 것으로 한다.
|
||||
void GiveBuff();
|
||||
void ClearBuff();
|
||||
|
||||
|
@ -87,7 +87,7 @@ private:
|
|||
LPCHARACTER m_pkChar; // Instance of pet(CHARACTER)
|
||||
LPCHARACTER m_pkOwner;
|
||||
|
||||
// SPetAbility m_petAbility; // 능력치
|
||||
// SPetAbility m_petAbility; // 능력치
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -95,7 +95,7 @@ private:
|
|||
class CPetSystem
|
||||
{
|
||||
public:
|
||||
typedef std::unordered_map<DWORD, CPetActor*> TPetActorMap; /// <VNUM, PetActor> map. (한 캐릭터가 같은 vnum의 펫을 여러개 가질 일이 있을까..??)
|
||||
typedef std::unordered_map<DWORD, CPetActor*> TPetActorMap; /// <VNUM, PetActor> map. (한 캐릭터가 같은 vnum의 펫을 여러개 가질 일이 있을까..??)
|
||||
|
||||
public:
|
||||
CPetSystem(LPCHARACTER owner);
|
||||
|
@ -107,7 +107,7 @@ public:
|
|||
bool Update(DWORD deltaTime);
|
||||
void Destroy();
|
||||
|
||||
size_t CountSummoned() const; ///< 현재 소환된(실체화 된 캐릭터가 있는) 펫의 개수
|
||||
size_t CountSummoned() const; ///< 현재 소환된(실체화 된 캐릭터가 있는) 펫의 개수
|
||||
|
||||
public:
|
||||
void SetUpdatePeriod(DWORD ms);
|
||||
|
@ -117,7 +117,7 @@ public:
|
|||
void Unsummon(DWORD mobVnum, bool bDeleteFromList = false);
|
||||
void Unsummon(CPetActor* petActor, bool bDeleteFromList = false);
|
||||
|
||||
// TODO: 진짜 펫 시스템이 들어갈 때 구현. (캐릭터가 보유한 펫의 정보를 추가할 때 라던가...)
|
||||
// TODO: 진짜 펫 시스템이 들어갈 때 구현. (캐릭터가 보유한 펫의 정보를 추가할 때 라던가...)
|
||||
CPetActor* AddPet(DWORD mobVnum, const char* petName, const SPetAbility& ability, DWORD options = CPetActor::EPetOption_Followable | CPetActor::EPetOption_Summonable | CPetActor::EPetOption_Combatable);
|
||||
|
||||
void DeletePet(DWORD mobVnum);
|
||||
|
@ -126,8 +126,8 @@ public:
|
|||
|
||||
private:
|
||||
TPetActorMap m_petActorMap;
|
||||
LPCHARACTER m_pkOwner; ///< 펫 시스템의 Owner
|
||||
DWORD m_dwUpdatePeriod; ///< 업데이트 주기 (ms단위)
|
||||
LPCHARACTER m_pkOwner; ///< 펫 시스템의 Owner
|
||||
DWORD m_dwUpdatePeriod; ///< 업데이트 주기 (ms단위)
|
||||
DWORD m_dwLastUpdateTime;
|
||||
LPEVENT m_pkPetSystemUpdateEvent;
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "SpeedServer.h"
|
||||
#include "locale_service.h"
|
||||
|
||||
// 쾌도 서버 보너스 경험치 시스템
|
||||
// 쾌도 서버 보너스 경험치 시스템
|
||||
// by rtsummit
|
||||
|
||||
CSpeedServerManager::CSpeedServerManager()
|
||||
|
@ -361,13 +361,13 @@ HME CSpeedServerEmpireExp::GetCurrentExpPriv(int &duration, bool &is_change)
|
|||
|
||||
HME hme;
|
||||
|
||||
// 현재 날짜가 holiday이면 holiday bonus를 도입한다.
|
||||
// 현재 날짜가 holiday이면 holiday bonus를 도입한다.
|
||||
if (holi_it != holiday_map.end())
|
||||
{
|
||||
for (std::list <HME>::iterator it = holi_it->second.begin();
|
||||
it != wday_exp_table[datetime->tm_wday].end(); it++)
|
||||
{
|
||||
// 현재 시각이 시간 구간 안에 포함되면,
|
||||
// 현재 시각이 시간 구간 안에 포함되면,
|
||||
if (total_sec < (it->hour * 3600 + it->min * 60 ))
|
||||
{
|
||||
hme = *it;
|
||||
|
@ -380,7 +380,7 @@ HME CSpeedServerEmpireExp::GetCurrentExpPriv(int &duration, bool &is_change)
|
|||
for (std::list <HME>::iterator it = wday_exp_table[datetime->tm_wday].begin();
|
||||
it != wday_exp_table[datetime->tm_wday].end(); it++)
|
||||
{
|
||||
// 현재 시각이 시간 구간 안에 포함되면,
|
||||
// 현재 시각이 시간 구간 안에 포함되면,
|
||||
if (total_sec < (it->hour * 3600 + it->min * 60 ))
|
||||
{
|
||||
hme = *it;
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
#include <common/length.h>
|
||||
#include <list>
|
||||
|
||||
// castle.cpp 에 있는 것을 복붙 하였다
|
||||
#define EMPIRE_NONE 0 // 아무국가 아님
|
||||
#define EMPIRE_RED 1 // 신수
|
||||
#define EMPIRE_YELLOW 2 // 천조
|
||||
#define EMPIRE_BLUE 3 // 진노
|
||||
// castle.cpp 에 있는 것을 복붙 하였다
|
||||
#define EMPIRE_NONE 0 // 아무국가 아님
|
||||
#define EMPIRE_RED 1 // 신수
|
||||
#define EMPIRE_YELLOW 2 // 천조
|
||||
#define EMPIRE_BLUE 3 // 진노
|
||||
|
||||
class HME
|
||||
{
|
||||
|
|
|
@ -12,17 +12,17 @@
|
|||
|
||||
/**
|
||||
* @class TrafficProfiler
|
||||
* @brief Network I/O traffic 을 패킷 단위로 측정하는 profiler.
|
||||
* @brief Network I/O traffic 을 패킷 단위로 측정하는 profiler.
|
||||
* @author Bang2ni
|
||||
* @version 05/07/07 Bang2ni - First release.
|
||||
*
|
||||
* 시간대 별로 Network I/O 의 traffic 을 패킷 단위로 측정하고, Text file 형태로 보고서를 작성한다.
|
||||
* 시간대 별로 Network I/O 의 traffic 을 패킷 단위로 측정하고, Text file 형태로 보고서를 작성한다.
|
||||
*/
|
||||
class TrafficProfiler : public singleton< TrafficProfiler >
|
||||
{
|
||||
public:
|
||||
|
||||
/// I/O 방향
|
||||
/// I/O 방향
|
||||
enum IODirection {
|
||||
IODIR_INPUT = 0, ///< Input
|
||||
IODIR_OUTPUT, ///< Output
|
||||
|
@ -37,25 +37,25 @@ class TrafficProfiler : public singleton< TrafficProfiler >
|
|||
/// Destructor
|
||||
~TrafficProfiler( void );
|
||||
|
||||
/// Profiling 에 필요한 초기화를 한다.
|
||||
/// Profiling 에 필요한 초기화를 한다.
|
||||
/**
|
||||
* @param [in] dwFlushCycle Flush 주기. 초 단위이다.
|
||||
* @param [in] pszLogFileName Profiling log file 의 이름
|
||||
* @return false 일 경우 profiling log file 을 open 하지 못했다.
|
||||
* @param [in] dwFlushCycle Flush 주기. 초 단위이다.
|
||||
* @param [in] pszLogFileName Profiling log file 의 이름
|
||||
* @return false 일 경우 profiling log file 을 open 하지 못했다.
|
||||
*
|
||||
* profiling log file 을 open(생성) 한다.
|
||||
* profiling log file 을 open(생성) 한다.
|
||||
*/
|
||||
bool Initialize( DWORD dwFlushCycle, const char* pszLogFileName );
|
||||
|
||||
/// Profiling 을 위해 전송됐거나 전송 할 Packet 을 Report 한다.
|
||||
/// Profiling 을 위해 전송됐거나 전송 할 Packet 을 Report 한다.
|
||||
/**
|
||||
* @param [in] dir Profiling 할 Packet 의 방향
|
||||
* @param [in] byHeader Packet 헤더
|
||||
* @param [in] dwSize Packet 의 총 size
|
||||
* @return Initialize 되지 않았다면 false 를 반환한다.
|
||||
* @param [in] dir Profiling 할 Packet 의 방향
|
||||
* @param [in] byHeader Packet 헤더
|
||||
* @param [in] dwSize Packet 의 총 size
|
||||
* @return Initialize 되지 않았다면 false 를 반환한다.
|
||||
*
|
||||
* Packet 에 해당하는 size 를 누적시킨다.
|
||||
* Initialize 이후나 최근 Flush 된 이후에 Flush 주기 만큼 시간이 흐른 후 호출된다면 Report 이후 Flush 한다.
|
||||
* Packet 에 해당하는 size 를 누적시킨다.
|
||||
* Initialize 이후나 최근 Flush 된 이후에 Flush 주기 만큼 시간이 흐른 후 호출된다면 Report 이후 Flush 한다.
|
||||
*/
|
||||
bool Report( IODirection dir, BYTE byHeader, DWORD dwSize )
|
||||
{
|
||||
|
@ -65,22 +65,22 @@ class TrafficProfiler : public singleton< TrafficProfiler >
|
|||
return true;
|
||||
}
|
||||
|
||||
/// 현재까지 Report 된 내용을 파일에 쓴다.
|
||||
/// 현재까지 Report 된 내용을 파일에 쓴다.
|
||||
/**
|
||||
* @return Initialize 되지 않았다.
|
||||
* @return Initialize 되지 않았다.
|
||||
*/
|
||||
bool Flush( void );
|
||||
|
||||
private:
|
||||
|
||||
/// Profling 에 관련된 variables 를 초기화 한다.
|
||||
/// Profling 에 관련된 variables 를 초기화 한다.
|
||||
void InitializeProfiling( void );
|
||||
|
||||
/// Report 된 Packet 의 traffic 를 계산한다.
|
||||
/// Report 된 Packet 의 traffic 를 계산한다.
|
||||
/**
|
||||
* @param [in] dir Profiling 할 Packet 의 방향
|
||||
* @param [in] byHeader Packet 헤더
|
||||
* @param [in] dwSize Packet 의 총 size
|
||||
* @param [in] dir Profiling 할 Packet 의 방향
|
||||
* @param [in] byHeader Packet 헤더
|
||||
* @param [in] dwSize Packet 의 총 size
|
||||
*/
|
||||
void ComputeTraffic( IODirection dir, BYTE byHeader, DWORD dwSize )
|
||||
{
|
||||
|
@ -96,8 +96,8 @@ class TrafficProfiler : public singleton< TrafficProfiler >
|
|||
|
||||
/// Traffic info type.
|
||||
/**
|
||||
* first: 누적된 총 size
|
||||
* second: 이 packet 이 전송된 횟수
|
||||
* first: 누적된 총 size
|
||||
* second: 이 packet 이 전송된 횟수
|
||||
*/
|
||||
typedef std::pair< DWORD, DWORD > TrafficInfo;
|
||||
|
||||
|
@ -105,11 +105,11 @@ class TrafficProfiler : public singleton< TrafficProfiler >
|
|||
typedef std::vector< TrafficInfo > TrafficVec;
|
||||
|
||||
FILE* m_pfProfileLogFile; ///< Profile log file pointer
|
||||
DWORD m_dwFlushCycle; ///< Flush 주기
|
||||
time_t m_tmProfileStartTime; ///< 프로파일을 시작한 시간. Flush 될 때마다 Update 된다.
|
||||
DWORD m_dwTotalTraffic; ///< Report 된 총 Traffic 용량
|
||||
DWORD m_dwTotalPacket; ///< Report 된 총 Packet 수
|
||||
TrafficVec m_aTrafficVec[ IODIR_MAX ]; ///< Report 된 Traffic 을 저장할 vector의 배열. 각 방향마다 vector 를 가진다.
|
||||
DWORD m_dwFlushCycle; ///< Flush 주기
|
||||
time_t m_tmProfileStartTime; ///< 프로파일을 시작한 시간. Flush 될 때마다 Update 된다.
|
||||
DWORD m_dwTotalTraffic; ///< Report 된 총 Traffic 용량
|
||||
DWORD m_dwTotalPacket; ///< Report 된 총 Packet 수
|
||||
TrafficVec m_aTrafficVec[ IODIR_MAX ]; ///< Report 된 Traffic 을 저장할 vector의 배열. 각 방향마다 vector 를 가진다.
|
||||
};
|
||||
|
||||
#endif // _METIN_II_TRAFFICPROFILER_H_
|
||||
|
|
|
@ -54,23 +54,23 @@ enum EAffectTypes
|
|||
AFFECT_DEF_GRADE, // 226
|
||||
|
||||
AFFECT_PREMIUM_START = 500,
|
||||
AFFECT_EXP_BONUS = 500, // 경험의 반지
|
||||
AFFECT_ITEM_BONUS = 501, // 도둑의 장갑
|
||||
AFFECT_EXP_BONUS = 500, // 경험의 반지
|
||||
AFFECT_ITEM_BONUS = 501, // 도둑의 장갑
|
||||
AFFECT_SAFEBOX = 502, // PREMIUM_SAFEBOX,
|
||||
AFFECT_AUTOLOOT = 503, // PREMIUM_AUTOLOOT,
|
||||
AFFECT_FISH_MIND = 504, // PREMIUM_FISH_MIND,
|
||||
AFFECT_MARRIAGE_FAST = 505, // 원앙의 깃털
|
||||
AFFECT_GOLD_BONUS = 506, // 돈 드롭확률 50%증가
|
||||
AFFECT_MARRIAGE_FAST = 505, // 원앙의 깃털
|
||||
AFFECT_GOLD_BONUS = 506, // 돈 드롭확률 50%증가
|
||||
AFFECT_PREMIUM_END = 509,
|
||||
|
||||
AFFECT_MALL = 510, // 몰 아이템 에펙트
|
||||
AFFECT_NO_DEATH_PENALTY = 511, // 용신의 가호 (경험치가 패널티를 한번 막아준다)
|
||||
AFFECT_SKILL_BOOK_BONUS = 512, // 선인의 교훈 (책 수련 성공 확률이 50% 증가)
|
||||
AFFECT_SKILL_NO_BOOK_DELAY = 513, // 주안술서
|
||||
AFFECT_MALL = 510, // 몰 아이템 에펙트
|
||||
AFFECT_NO_DEATH_PENALTY = 511, // 용신의 가호 (경험치가 패널티를 한번 막아준다)
|
||||
AFFECT_SKILL_BOOK_BONUS = 512, // 선인의 교훈 (책 수련 성공 확률이 50% 증가)
|
||||
AFFECT_SKILL_NO_BOOK_DELAY = 513, // 주안술서
|
||||
|
||||
AFFECT_HAIR = 514, // 헤어 효과
|
||||
AFFECT_COLLECT = 515, //수집퀘스트
|
||||
AFFECT_EXP_BONUS_EURO_FREE = 516, // 경험의 반지 (유럽 버전 14 레벨 이하 기본 효과)
|
||||
AFFECT_HAIR = 514, // 헤어 효과
|
||||
AFFECT_COLLECT = 515, //수집퀘스트
|
||||
AFFECT_EXP_BONUS_EURO_FREE = 516, // 경험의 반지 (유럽 버전 14 레벨 이하 기본 효과)
|
||||
AFFECT_EXP_BONUS_EURO_FREE_UNDER_15 = 517,
|
||||
AFFECT_UNIQUE_ABILITY = 518,
|
||||
|
||||
|
@ -121,8 +121,8 @@ enum EAffectBits
|
|||
AFF_SLOW,
|
||||
AFF_STUN,
|
||||
|
||||
AFF_DUNGEON_READY, // 던전에서 준비 상태
|
||||
AFF_DUNGEON_UNIQUE, // 던전 유니크 (클라이언트에서 컬링되지않음)
|
||||
AFF_DUNGEON_READY, // 던전에서 준비 상태
|
||||
AFF_DUNGEON_UNIQUE, // 던전 유니크 (클라이언트에서 컬링되지않음)
|
||||
|
||||
AFF_BUILDING_CONSTRUCTION_SMALL,
|
||||
AFF_BUILDING_CONSTRUCTION_LARGE,
|
||||
|
@ -133,34 +133,34 @@ enum EAffectBits
|
|||
|
||||
AFF_FISH_MIND,
|
||||
|
||||
AFF_JEONGWIHON, // 전귀혼
|
||||
AFF_GEOMGYEONG, // 검경
|
||||
AFF_CHEONGEUN, // 천근추
|
||||
AFF_GYEONGGONG, // 경공술
|
||||
AFF_EUNHYUNG, // 은형법
|
||||
AFF_GWIGUM, // 귀검
|
||||
AFF_TERROR, // 공포
|
||||
AFF_JUMAGAP, // 주마갑
|
||||
AFF_HOSIN, // 호신
|
||||
AFF_BOHO, // 보호
|
||||
AFF_KWAESOK, // 쾌속
|
||||
AFF_MANASHIELD, // 마나쉴드
|
||||
AFF_MUYEONG, // 무영진 affect
|
||||
AFF_REVIVE_INVISIBLE, // 부활시 잠시동안 무적
|
||||
AFF_FIRE, // 지속 불 데미지
|
||||
AFF_GICHEON, // 기천대공
|
||||
AFF_JEUNGRYEOK, // 증력술
|
||||
AFF_TANHWAN_DASH, // 탄환격용 달리기어펙트
|
||||
AFF_PABEOP, // 파법술
|
||||
AFF_CHEONGEUN_WITH_FALL, // 천근추
|
||||
AFF_JEONGWIHON, // 전귀혼
|
||||
AFF_GEOMGYEONG, // 검경
|
||||
AFF_CHEONGEUN, // 천근추
|
||||
AFF_GYEONGGONG, // 경공술
|
||||
AFF_EUNHYUNG, // 은형법
|
||||
AFF_GWIGUM, // 귀검
|
||||
AFF_TERROR, // 공포
|
||||
AFF_JUMAGAP, // 주마갑
|
||||
AFF_HOSIN, // 호신
|
||||
AFF_BOHO, // 보호
|
||||
AFF_KWAESOK, // 쾌속
|
||||
AFF_MANASHIELD, // 마나쉴드
|
||||
AFF_MUYEONG, // 무영진 affect
|
||||
AFF_REVIVE_INVISIBLE, // 부활시 잠시동안 무적
|
||||
AFF_FIRE, // 지속 불 데미지
|
||||
AFF_GICHEON, // 기천대공
|
||||
AFF_JEUNGRYEOK, // 증력술
|
||||
AFF_TANHWAN_DASH, // 탄환격용 달리기어펙트
|
||||
AFF_PABEOP, // 파법술
|
||||
AFF_CHEONGEUN_WITH_FALL, // 천근추
|
||||
AFF_POLYMORPH,
|
||||
AFF_WAR_FLAG1,
|
||||
AFF_WAR_FLAG2,
|
||||
AFF_WAR_FLAG3,
|
||||
|
||||
AFF_CHINA_FIREWORK,
|
||||
AFF_HAIR, // 헤어
|
||||
AFF_GERMANY, // 독일
|
||||
AFF_HAIR, // 헤어
|
||||
AFF_GERMANY, // 독일
|
||||
|
||||
AFF_BITS_MAX
|
||||
};
|
||||
|
@ -170,11 +170,11 @@ extern void SendAffectAddPacket(LPDESC d, CAffect * pkAff);
|
|||
// AFFECT_DURATION_BUG_FIX
|
||||
enum AffectVariable
|
||||
{
|
||||
// Affect가 무한대로 들어가 있어야 할 경우 사용.
|
||||
// 시간을 계속 줄이기 때문에 매우 큰값으로 무한대를 에뮬레이션함.
|
||||
//// 24비트는 적으므로 25비트를 사용.
|
||||
// ... 25비트 사용한다고 해놓고선 29bit 사용하고 있는 엄청난 주석이란...
|
||||
// collect quest에서 무한 시간을 60년으로 사용하고 있으므로, 여기도 60년으로 하자.
|
||||
// Affect가 무한대로 들어가 있어야 할 경우 사용.
|
||||
// 시간을 계속 줄이기 때문에 매우 큰값으로 무한대를 에뮬레이션함.
|
||||
//// 24비트는 적으므로 25비트를 사용.
|
||||
// ... 25비트 사용한다고 해놓고선 29bit 사용하고 있는 엄청난 주석이란...
|
||||
// collect quest에서 무한 시간을 60년으로 사용하고 있으므로, 여기도 60년으로 하자.
|
||||
|
||||
INFINITE_AFFECT_DURATION = 60 * 365 * 24 * 60 * 60
|
||||
};
|
||||
|
|
|
@ -55,7 +55,7 @@ const char* FN_weapon_type(int weapon)
|
|||
class ANI
|
||||
{
|
||||
protected:
|
||||
// [종족][일반0탈것1][무기][콤보]
|
||||
// [종족][일반0탈것1][무기][콤보]
|
||||
DWORD m_speed[MAIN_RACE_MAX_NUM][2][WEAPON_NUM_TYPES][9];
|
||||
|
||||
public:
|
||||
|
@ -126,14 +126,14 @@ ANI::ANI()
|
|||
bool ANI::load()
|
||||
{
|
||||
const char* dir_name[MAIN_RACE_MAX_NUM] = {
|
||||
"data/pc/warrior", // 무사(남)
|
||||
"data/pc/assassin", // 자객(여)
|
||||
"data/pc/sura", // 수라(남)
|
||||
"data/pc/shaman", // 무당(여)
|
||||
"data/pc2/warrior", // 무사(여)
|
||||
"data/pc2/assassin", // 자객(남)
|
||||
"data/pc2/sura", // 수라(여)
|
||||
"data/pc2/shaman" // 무당(남)
|
||||
"data/pc/warrior", // 무사(남)
|
||||
"data/pc/assassin", // 자객(여)
|
||||
"data/pc/sura", // 수라(남)
|
||||
"data/pc/shaman", // 무당(여)
|
||||
"data/pc2/warrior", // 무사(여)
|
||||
"data/pc2/assassin", // 자객(남)
|
||||
"data/pc2/sura", // 수라(여)
|
||||
"data/pc2/shaman" // 무당(남)
|
||||
};
|
||||
|
||||
for (int race = 0; race <MAIN_RACE_MAX_NUM; ++race)
|
||||
|
@ -203,13 +203,13 @@ bool ANI::load_one_race(int race, const char *dir_name)
|
|||
|
||||
for (BYTE combo = 1; combo <= 8; ++combo)
|
||||
{
|
||||
// 말 안탔을 때
|
||||
// 말 안탔을 때
|
||||
m_speed[race][0][weapon][combo] = load_one_weapon(dir_name, weapon, combo, false);
|
||||
m_speed[race][0][weapon][0] = std::min(m_speed[race][0][weapon][0], m_speed[race][0][weapon][combo]); // 최소값
|
||||
m_speed[race][0][weapon][0] = std::min(m_speed[race][0][weapon][0], m_speed[race][0][weapon][combo]); // 최소값
|
||||
|
||||
// 말 탔을 때
|
||||
// 말 탔을 때
|
||||
m_speed[race][1][weapon][combo] = load_one_weapon(dir_name, weapon, combo, true);
|
||||
m_speed[race][1][weapon][0] = std::min(m_speed[race][1][weapon][0], m_speed[race][1][weapon][combo]); // 최소값
|
||||
m_speed[race][1][weapon][0] = std::min(m_speed[race][1][weapon][0], m_speed[race][1][weapon][combo]); // 최소값
|
||||
|
||||
SPDLOG_TRACE("combo{:02} speed={} horse={}",
|
||||
combo, m_speed[race][0][weapon][combo], m_speed[race][1][weapon][combo]);
|
||||
|
@ -337,8 +337,8 @@ DWORD ani_attack_speed(LPCHARACTER ch)
|
|||
ch->GetPoint(POINT_ATT_SPEED));
|
||||
*/
|
||||
|
||||
/* 투핸디드 소드의 경우 삼연참공격과 승마시 */
|
||||
/* 오류가 많아 한손검 속도로 생각하자 */
|
||||
/* 투핸디드 소드의 경우 삼연참공격과 승마시 */
|
||||
/* 오류가 많아 한손검 속도로 생각하자 */
|
||||
if (weapon == WEAPON_TWO_HANDED)
|
||||
weapon = WEAPON_SWORD;
|
||||
|
||||
|
|
|
@ -233,17 +233,17 @@ EVENTFUNC(ready_to_start_event)
|
|||
|
||||
if (chA != NULL)
|
||||
{
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련 상대가 사라져 대련을 종료합니다."));
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The duel has finished, because your combatant vanished."));
|
||||
SPDLOG_DEBUG("ARENA: Oppernent is disappered. MyPID({}) OppPID({})", pArena->GetPlayerAPID(), pArena->GetPlayerBPID());
|
||||
}
|
||||
|
||||
if (chB != NULL)
|
||||
{
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련 상대가 사라져 대련을 종료합니다."));
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The duel has finished, because your combatant vanished."));
|
||||
SPDLOG_DEBUG("ARENA: Oppernent is disappered. MyPID({}) OppPID({})", pArena->GetPlayerBPID(), pArena->GetPlayerAPID());
|
||||
}
|
||||
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("대련 상대가 사라져 대련을 종료합니다."));
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("The duel has finished, because your combatant vanished."));
|
||||
|
||||
pArena->EndDuel();
|
||||
return 0;
|
||||
|
@ -260,20 +260,20 @@ EVENTFUNC(ready_to_start_event)
|
|||
|
||||
if (count > 10000)
|
||||
{
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("물약 제한이 없습니다."));
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("물약 제한이 없습니다."));
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("There is no limit for Potions."));
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("There is no limit for Potions."));
|
||||
}
|
||||
else
|
||||
{
|
||||
chA->SetPotionLimit(count);
|
||||
chB->SetPotionLimit(count);
|
||||
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("물약을 %d 개 까지 사용 가능합니다."), chA->GetPotionLimit());
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("물약을 %d 개 까지 사용 가능합니다."), chB->GetPotionLimit());
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can use up to %d potions."), chA->GetPotionLimit());
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can use up to %d potions."), chB->GetPotionLimit());
|
||||
}
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("10초뒤 대련이 시작됩니다."));
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("10초뒤 대련이 시작됩니다."));
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("10초뒤 대련이 시작됩니다."));
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The fight will start in 10 seconds."));
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The fight will start in 10 seconds."));
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("The fight will start in 10 seconds."));
|
||||
|
||||
info->state++;
|
||||
return PASSES_PER_SEC(10);
|
||||
|
@ -282,15 +282,15 @@ EVENTFUNC(ready_to_start_event)
|
|||
|
||||
case 1:
|
||||
{
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련이 시작되었습니다."));
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련이 시작되었습니다."));
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("대련이 시작되었습니다."));
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The duel has begun."));
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The duel has begun."));
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("The duel has begun."));
|
||||
|
||||
TPacketGCDuelStart duelStart;
|
||||
duelStart.header = HEADER_GC_DUEL_START;
|
||||
duelStart.wSize = sizeof(TPacketGCDuelStart) + 4;
|
||||
|
||||
DWORD dwOppList[8]; // 최대 파티원 8명 이므로..
|
||||
DWORD dwOppList[8]; // 최대 파티원 8명 이므로..
|
||||
|
||||
dwOppList[0] = (DWORD)chB->GetVID();
|
||||
TEMP_BUFFER buf;
|
||||
|
@ -339,7 +339,7 @@ EVENTFUNC(ready_to_start_event)
|
|||
|
||||
TEMP_BUFFER buf;
|
||||
TEMP_BUFFER buf2;
|
||||
DWORD dwOppList[8]; // 최대 파티원 8명 이므로..
|
||||
DWORD dwOppList[8]; // 최대 파티원 8명 이므로..
|
||||
TPacketGCDuelStart duelStart;
|
||||
duelStart.header = HEADER_GC_DUEL_START;
|
||||
duelStart.wSize = sizeof(TPacketGCDuelStart) + 4;
|
||||
|
@ -354,9 +354,9 @@ EVENTFUNC(ready_to_start_event)
|
|||
buf2.write(&dwOppList[0], 4);
|
||||
chB->GetDesc()->Packet(buf2.read_peek(), buf2.size());
|
||||
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련이 시작되었습니다."));
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련이 시작되었습니다."));
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("대련이 시작되었습니다."));
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The duel has begun."));
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The duel has begun."));
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("The duel has begun."));
|
||||
|
||||
pArena->ClearEvent();
|
||||
|
||||
|
@ -366,9 +366,9 @@ EVENTFUNC(ready_to_start_event)
|
|||
|
||||
default:
|
||||
{
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련장 문제로 인하여 대련을 종료합니다."));
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련장 문제로 인하여 대련을 종료합니다."));
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("대련장 문제로 인하여 대련을 종료합니다."));
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The duel is being finished because there is a problem in the duel arena."));
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The duel is being finished because there is a problem in the duel arena."));
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("The duel is being finished because there is a problem in the duel arena."));
|
||||
|
||||
SPDLOG_DEBUG("ARENA: Something wrong in event func. info->state({})", info->state);
|
||||
|
||||
|
@ -407,17 +407,17 @@ EVENTFUNC(duel_time_out)
|
|||
{
|
||||
if (chA != NULL)
|
||||
{
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련 상대가 사라져 대련을 종료합니다."));
|
||||
chA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The duel has finished, because your combatant vanished."));
|
||||
SPDLOG_DEBUG("ARENA: Oppernent is disappered. MyPID({}) OppPID({})", pArena->GetPlayerAPID(), pArena->GetPlayerBPID());
|
||||
}
|
||||
|
||||
if (chB != NULL)
|
||||
{
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련 상대가 사라져 대련을 종료합니다."));
|
||||
chB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The duel has finished, because your combatant vanished."));
|
||||
SPDLOG_DEBUG("ARENA: Oppernent is disappered. MyPID({}) OppPID({})", pArena->GetPlayerBPID(), pArena->GetPlayerAPID());
|
||||
}
|
||||
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("대련 상대가 사라져 대련을 종료합니다."));
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("The duel has finished, because your combatant vanished."));
|
||||
|
||||
pArena->EndDuel();
|
||||
return 0;
|
||||
|
@ -427,14 +427,14 @@ EVENTFUNC(duel_time_out)
|
|||
switch (info->state)
|
||||
{
|
||||
case 0:
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("대련 시간 초과로 대련을 중단합니다."));
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("10초뒤 마을로 이동합니다."));
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("The duel has finished because of a timeout."));
|
||||
pArena->SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("In 10 seconds you will be teleported into the city."));
|
||||
|
||||
chA->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("대련 시간 초과로 대련을 중단합니다."));
|
||||
chA->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("10초뒤 마을로 이동합니다."));
|
||||
chA->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("The duel has finished because of a timeout."));
|
||||
chA->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("In 10 seconds you will be teleported into the city."));
|
||||
|
||||
chB->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("대련 시간 초과로 대련을 중단합니다."));
|
||||
chB->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("10초뒤 마을로 이동합니다."));
|
||||
chB->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("The duel has finished because of a timeout."));
|
||||
chB->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("In 10 seconds you will be teleported into the city."));
|
||||
|
||||
TPacketGCDuelStart duelStart;
|
||||
duelStart.header = HEADER_GC_DUEL_START;
|
||||
|
@ -678,7 +678,7 @@ bool CArenaMap::CanAttack(LPCHARACTER pCharAttacker, LPCHARACTER pCharVictim)
|
|||
|
||||
bool CArena::CanAttack(DWORD dwPIDA, DWORD dwPIDB)
|
||||
{
|
||||
// 1:1 전용 다대다 할 경우 수정 필요
|
||||
// 1:1 전용 다대다 할 경우 수정 필요
|
||||
if (m_dwPIDA == dwPIDA && m_dwPIDB == dwPIDB) return true;
|
||||
if (m_dwPIDA == dwPIDB && m_dwPIDB == dwPIDA) return true;
|
||||
|
||||
|
@ -728,20 +728,20 @@ bool CArena::OnDead(DWORD dwPIDA, DWORD dwPIDB)
|
|||
|
||||
if (pCharA == NULL && pCharB == NULL)
|
||||
{
|
||||
// 둘다 접속이 끊어졌다 ?!
|
||||
SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("대련자 문제로 인하여 대련을 중단합니다."));
|
||||
// 둘다 접속이 끊어졌다 ?!
|
||||
SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("The duel has been stopped because there is a problem in the arena."));
|
||||
restart = false;
|
||||
}
|
||||
else if (pCharA == NULL && pCharB != NULL)
|
||||
{
|
||||
pCharB->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("상대방 캐릭터의 문제로 인하여 대련을 종료합니다."));
|
||||
SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("대련자 문제로 인하여 대련을 종료합니다."));
|
||||
pCharB->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("Your combatant has got some problems. The duel is being cancelled."));
|
||||
SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("The duel is being cancelled as there is a problem with the combatant."));
|
||||
restart = false;
|
||||
}
|
||||
else if (pCharA != NULL && pCharB == NULL)
|
||||
{
|
||||
pCharA->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("상대방 캐릭터의 문제로 인하여 대련을 종료합니다."));
|
||||
SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("대련자 문제로 인하여 대련을 종료합니다."));
|
||||
pCharA->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("Your combatant has got some problems. The duel is being cancelled."));
|
||||
SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("The duel is being cancelled as there is a problem with the combatant."));
|
||||
restart = false;
|
||||
}
|
||||
else if (pCharA != NULL && pCharB != NULL)
|
||||
|
@ -752,9 +752,9 @@ bool CArena::OnDead(DWORD dwPIDA, DWORD dwPIDB)
|
|||
|
||||
if (m_dwSetPointOfA >= m_dwSetCount)
|
||||
{
|
||||
pCharA->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("%s 님이 대련에서 승리하였습니다."), pCharA->GetName());
|
||||
pCharB->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("%s 님이 대련에서 승리하였습니다."), pCharA->GetName());
|
||||
SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("%s 님이 대련에서 승리하였습니다."), pCharA->GetName());
|
||||
pCharA->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("%s has won the duel."), pCharA->GetName());
|
||||
pCharB->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("%s has won the duel."), pCharA->GetName());
|
||||
SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("%s has won the duel."), pCharA->GetName());
|
||||
|
||||
SPDLOG_DEBUG("ARENA: Duel is end. Winner {}({}) Loser {}({})",
|
||||
pCharA->GetName(), GetPlayerAPID(), pCharB->GetName(), GetPlayerBPID());
|
||||
|
@ -762,10 +762,10 @@ bool CArena::OnDead(DWORD dwPIDA, DWORD dwPIDB)
|
|||
else
|
||||
{
|
||||
restart = true;
|
||||
pCharA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님이 승리하였습니다."), pCharA->GetName());
|
||||
pCharA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s has won."), pCharA->GetName());
|
||||
pCharA->ChatPacket(CHAT_TYPE_NOTICE, "%s %d : %d %s", pCharA->GetName(), m_dwSetPointOfA, m_dwSetPointOfB, pCharB->GetName());
|
||||
|
||||
pCharB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님이 승리하였습니다."), pCharA->GetName());
|
||||
pCharB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s has won."), pCharA->GetName());
|
||||
pCharB->ChatPacket(CHAT_TYPE_NOTICE, "%s %d : %d %s", pCharA->GetName(), m_dwSetPointOfA, m_dwSetPointOfB, pCharB->GetName());
|
||||
|
||||
SendChatPacketToObserver(CHAT_TYPE_NOTICE, "%s %d : %d %s", pCharA->GetName(), m_dwSetPointOfA, m_dwSetPointOfB, pCharB->GetName());
|
||||
|
@ -779,19 +779,19 @@ bool CArena::OnDead(DWORD dwPIDA, DWORD dwPIDB)
|
|||
m_dwSetPointOfB++;
|
||||
if (m_dwSetPointOfB >= m_dwSetCount)
|
||||
{
|
||||
pCharA->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("%s 님이 대련에서 승리하였습니다."), pCharB->GetName());
|
||||
pCharB->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("%s 님이 대련에서 승리하였습니다."), pCharB->GetName());
|
||||
SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("%s 님이 대련에서 승리하였습니다."), pCharB->GetName());
|
||||
pCharA->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("%s has won the duel."), pCharB->GetName());
|
||||
pCharB->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("%s has won the duel."), pCharB->GetName());
|
||||
SendChatPacketToObserver(CHAT_TYPE_NOTICE, LC_TEXT("%s has won the duel."), pCharB->GetName());
|
||||
|
||||
SPDLOG_DEBUG("ARENA: Duel is end. Winner({}) Loser({})", GetPlayerBPID(), GetPlayerAPID());
|
||||
}
|
||||
else
|
||||
{
|
||||
restart = true;
|
||||
pCharA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님이 승리하였습니다."), pCharB->GetName());
|
||||
pCharA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s has won."), pCharB->GetName());
|
||||
pCharA->ChatPacket(CHAT_TYPE_NOTICE, "%s %d : %d %s", pCharA->GetName(), m_dwSetPointOfA, m_dwSetPointOfB, pCharB->GetName());
|
||||
|
||||
pCharB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님이 승리하였습니다."), pCharB->GetName());
|
||||
pCharB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s has won."), pCharB->GetName());
|
||||
pCharB->ChatPacket(CHAT_TYPE_NOTICE, "%s %d : %d %s", pCharA->GetName(), m_dwSetPointOfA, m_dwSetPointOfB, pCharB->GetName());
|
||||
|
||||
SendChatPacketToObserver(CHAT_TYPE_NOTICE, "%s %d : %d %s", pCharA->GetName(), m_dwSetPointOfA, m_dwSetPointOfB, pCharB->GetName());
|
||||
|
@ -811,18 +811,18 @@ bool CArena::OnDead(DWORD dwPIDA, DWORD dwPIDB)
|
|||
}
|
||||
else
|
||||
{
|
||||
// 오면 안된다 ?!
|
||||
// 오면 안된다 ?!
|
||||
}
|
||||
|
||||
if (restart == false)
|
||||
{
|
||||
if (pCharA != NULL)
|
||||
pCharA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("10초뒤 마을로 되돌아갑니다."));
|
||||
pCharA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You will be teleported into the city in 10 seconds."));
|
||||
|
||||
if ( pCharB != NULL)
|
||||
pCharB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("10초뒤 마을로 되돌아갑니다."));
|
||||
pCharB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You will be teleported into the city in 10 seconds."));
|
||||
|
||||
SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("10초뒤 마을로 되돌아갑니다."));
|
||||
SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("You will be teleported into the city in 10 seconds."));
|
||||
|
||||
if (m_pEvent != NULL) {
|
||||
event_cancel(&m_pEvent);
|
||||
|
@ -838,12 +838,12 @@ bool CArena::OnDead(DWORD dwPIDA, DWORD dwPIDB)
|
|||
else
|
||||
{
|
||||
if (pCharA != NULL)
|
||||
pCharA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("10초뒤 다음 판을 시작합니다."));
|
||||
pCharA->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The next round will begin in 10 seconds."));
|
||||
|
||||
if (pCharB != NULL)
|
||||
pCharB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("10초뒤 다음 판을 시작합니다."));
|
||||
pCharB->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The next round will begin in 10 seconds."));
|
||||
|
||||
SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("10초뒤 다음 판을 시작합니다."));
|
||||
SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("The next round will begin in 10 seconds."));
|
||||
|
||||
if (m_pEvent != NULL) {
|
||||
event_cancel(&m_pEvent);
|
||||
|
@ -949,7 +949,7 @@ void CArena::OnDisconnect(DWORD pid)
|
|||
if (m_dwPIDA == pid)
|
||||
{
|
||||
if (GetPlayerB() != NULL)
|
||||
GetPlayerB()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방 캐릭터가 접속을 종료하여 대련을 중지합니다."));
|
||||
GetPlayerB()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The combatants have been separated. The duel has been stopped."));
|
||||
|
||||
SPDLOG_DEBUG("ARENA : Duel is end because of Opp({}) is disconnect. MyPID({})", GetPlayerAPID(), GetPlayerBPID());
|
||||
EndDuel();
|
||||
|
@ -957,7 +957,7 @@ void CArena::OnDisconnect(DWORD pid)
|
|||
else if (m_dwPIDB == pid)
|
||||
{
|
||||
if (GetPlayerA() != NULL)
|
||||
GetPlayerA()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방 캐릭터가 접속을 종료하여 대련을 중지합니다."));
|
||||
GetPlayerA()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The combatants have been separated. The duel has been stopped."));
|
||||
|
||||
SPDLOG_DEBUG("ARENA : Duel is end because of Opp({}) is disconnect. MyPID({})", GetPlayerBPID(), GetPlayerAPID());
|
||||
EndDuel();
|
||||
|
|
|
@ -215,7 +215,7 @@ void AuctionBoard::YourItemInfoList (TItemInfoVec& vec, DWORD player_id, int sta
|
|||
}
|
||||
|
||||
// 0~1, 2~3, 4~5, 6~7, 8~9
|
||||
// 짝수면 descending, 홀수면 accending.
|
||||
// 짝수면 descending, 홀수면 accending.
|
||||
struct FCheckGradeSatisfied
|
||||
{
|
||||
BYTE grade;
|
||||
|
@ -796,7 +796,7 @@ void AuctionManager::YourBidItemInfoList (AuctionBoard::TItemInfoVec& vec, DWORD
|
|||
}
|
||||
else
|
||||
{
|
||||
// expired 만들고 여기서 넣어야한다.
|
||||
// expired 만들고 여기서 넣어야한다.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -881,21 +881,21 @@ void AuctionManager::enroll_auction (LPCHARACTER ch, LPITEM item, BYTE empire, i
|
|||
}
|
||||
if (item->IsEquipped())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "장착한 건 등록할 수 없어.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "I can't register anything that's equipped.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetAuctionItemInfo (item->GetID()))
|
||||
{
|
||||
SPDLOG_ERROR("Item {} is already in auction.", item->GetID());
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "이미 등록한 거야. 도대체 뭐지?");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "I'm already registered. What the heck?");
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->GetWindow() == AUCTION)
|
||||
{
|
||||
SPDLOG_ERROR("Item {} is already in auction.", item->GetID());
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "얜 또 뭐냐..");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "What the hell is this...");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -918,21 +918,21 @@ void AuctionManager::enroll_sale (LPCHARACTER ch, LPITEM item, DWORD wisher_id,
|
|||
}
|
||||
if (item->IsEquipped())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "장착한 건 등록할 수 없어.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "I can't register anything that's equipped.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSaleItemInfo (item->GetID()))
|
||||
{
|
||||
SPDLOG_ERROR("Item {} is already in auction.", item->GetID());
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "이미 등록한 거야. 도대체 뭐지?");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "I'm already registered. What the heck?");
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->GetWindow() == AUCTION)
|
||||
{
|
||||
SPDLOG_ERROR("Item {} is already in auction.", item->GetID());
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "얜 또 뭐냐..");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "What the hell is this...");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -959,11 +959,11 @@ void AuctionManager::bid (LPCHARACTER ch, DWORD item_id, int bid_price)
|
|||
std::pair <int, bool> mb = MyBid.GetMoney(ch->GetPlayerID(), item_id);
|
||||
if (mb.first != -1)
|
||||
{
|
||||
ch->ChatPacket (CHAT_TYPE_INFO, "재입찰을 하란 말이다.");
|
||||
ch->ChatPacket (CHAT_TYPE_INFO, "Re-bid.");
|
||||
}
|
||||
if (ch->GetGold() < bid_price)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "돈이 부족해");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "I don't have enough money");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -975,7 +975,7 @@ void AuctionManager::bid (LPCHARACTER ch, DWORD item_id, int bid_price)
|
|||
}
|
||||
|
||||
// fixme
|
||||
// 반드시 돈!!!
|
||||
// 반드시 돈!!!
|
||||
void AuctionManager::immediate_purchase (LPCHARACTER ch, DWORD item_id)
|
||||
{
|
||||
TAuctionItemInfo* item_info = GetAuctionItemInfo (item_id);
|
||||
|
@ -988,13 +988,13 @@ void AuctionManager::immediate_purchase (LPCHARACTER ch, DWORD item_id)
|
|||
|
||||
if (item_info->get_impur_price() == 0)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "즉구 할 수 엄서");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "Improvisation");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch->GetGold() < item_info->get_impur_price())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "돈이 부족해");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "I don't have enough money");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1005,7 +1005,7 @@ void AuctionManager::immediate_purchase (LPCHARACTER ch, DWORD item_id)
|
|||
db_clientdesc->DBPacket(HEADER_GD_COMMAND_AUCTION, ch->GetPlayerID(), &pack_impur, sizeof(TPacketGDCommnadAuction));
|
||||
}
|
||||
|
||||
// 시작
|
||||
// 시작
|
||||
void AuctionManager::get_auctioned_item (LPCHARACTER ch, DWORD item_id, DWORD item_num)
|
||||
{
|
||||
TItemTable* proto = ITEM_MANAGER::instance().GetTable(item_num);
|
||||
|
@ -1013,7 +1013,7 @@ void AuctionManager::get_auctioned_item (LPCHARACTER ch, DWORD item_id, DWORD it
|
|||
|
||||
if (pos == -1)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "자리가 엄서");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "Tight Spot");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1069,13 +1069,13 @@ void AuctionManager::rebid (LPCHARACTER ch, DWORD item_id, int bid_price)
|
|||
|
||||
if (lock)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "입찰 중이야.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "You're bidding.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch->GetGold() + money < bid_price)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "돈이 부족해");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "I don't have enough money");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1101,14 +1101,14 @@ void AuctionManager::bid_cancel (LPCHARACTER ch, DWORD item_id)
|
|||
|
||||
if (lock)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "입찰 중이야.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "You're bidding.");
|
||||
return;
|
||||
}
|
||||
|
||||
TAuctionItemInfo* item_info = GetAuctionItemInfo(item_id);
|
||||
if (item_info->get_bidder_id() == ch->GetPlayerID())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "니가 최고 입찰자야. 취소 못해.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "You're the highest bidder. I can't cancel.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1120,7 +1120,7 @@ void AuctionManager::bid_cancel (LPCHARACTER ch, DWORD item_id)
|
|||
db_clientdesc->DBPacket(HEADER_GD_COMMAND_AUCTION, ch->GetPlayerID(), &pack_bc, sizeof(TPacketGDCommnadAuction));
|
||||
}
|
||||
|
||||
// 끝
|
||||
// 끝
|
||||
void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuction* cmd_result)
|
||||
{
|
||||
LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(commander_id);
|
||||
|
@ -1142,7 +1142,7 @@ void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuc
|
|||
Auction.InsertItemInfo (item_info);
|
||||
if (ch != NULL)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "경매장에 등록했어.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "You've registered for the auction.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1157,7 +1157,7 @@ void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuc
|
|||
LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID (player_item->owner);
|
||||
|
||||
ch->AutoGiveItem (item, true);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "경매장에 등록하지 못했어.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "Failed to register for the auction house.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1179,7 +1179,7 @@ void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuc
|
|||
Sale.InsertItemInfo (item_info);
|
||||
if (ch != NULL)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "판매장에 등록했어.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "You've signed up for a storefront.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1193,7 +1193,7 @@ void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuc
|
|||
|
||||
|
||||
ch->AutoGiveItem (item, true);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "판매장에 등록하지 못했어.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "Failed to enroll in a storefront.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1210,7 +1210,7 @@ void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuc
|
|||
Wish.InsertItemInfo (item_info);
|
||||
if (ch != NULL)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "삽니다에 등록했어.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "Signed Up.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1218,7 +1218,7 @@ void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuc
|
|||
{
|
||||
if (ch != NULL)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "삽니다에 등록하지 못했어.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "Failed to sign up.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1238,7 +1238,7 @@ void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuc
|
|||
MyBid.Insert(new_item_info->bidder_id, new_item_info->item_id, new_item_info->get_bid_price());
|
||||
if (ch != NULL)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "입찰했어.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "You bid.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1254,7 +1254,7 @@ void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuc
|
|||
memcpy (old_item_info, new_item_info, sizeof(TAuctionItemInfo));
|
||||
if (ch != NULL)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "즉구 해버렸어.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "I improvised.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1277,7 +1277,7 @@ void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuc
|
|||
{
|
||||
LPITEM item = ITEM_MANAGER::instance().CreateItem(player_item->vnum, player_item->count, item_id);
|
||||
ch->AutoGiveItem (item, true);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "가져왔어.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "Imported.");
|
||||
if (cmd == AUCTION_GET_AUC || cmd == AUCTION_CANCEL_AUC)
|
||||
{
|
||||
TPacketGDCommnadAuction pack_dai;
|
||||
|
@ -1337,7 +1337,7 @@ void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuc
|
|||
}
|
||||
else if (ch != NULL)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "취소했어.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "Canceled.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1354,7 +1354,7 @@ void AuctionManager::recv_result_auction (DWORD commander_id, TPacketDGResultAuc
|
|||
}
|
||||
else
|
||||
{
|
||||
// insert하면 lock이 풀린다.
|
||||
// insert하면 lock이 풀린다.
|
||||
DWORD item_id = cmd_result->target;
|
||||
cmd_result++;
|
||||
TAuctionItemInfo* auction_info = (TAuctionItemInfo*)cmd_result;
|
||||
|
|
|
@ -63,7 +63,7 @@ private:
|
|||
|
||||
TPCMap offer_map;
|
||||
|
||||
// sorting을 위한 members
|
||||
// sorting을 위한 members
|
||||
public:
|
||||
typedef std::vector <TAuctionItemInfo*> TItemInfoVec;
|
||||
private:
|
||||
|
@ -76,7 +76,7 @@ private:
|
|||
public:
|
||||
void SortedItemInfos (TItemInfoVec& vec, BYTE grade, BYTE category, int start_idx, BYTE size, BYTE order[5]);
|
||||
|
||||
// 나의 경매장을 위한 함수.
|
||||
// 나의 경매장을 위한 함수.
|
||||
void YourItemInfoList (TItemInfoVec& vec, DWORD player_id, int start_idx, BYTE size);
|
||||
|
||||
};
|
||||
|
@ -131,7 +131,7 @@ private:
|
|||
typedef std::pair <int, bool> BidInfo;
|
||||
typedef std::map <DWORD, BidInfo > TItemMap;
|
||||
typedef std::unordered_map <DWORD, TItemMap*> TMyBidBoard;
|
||||
// bidder_id가 key
|
||||
// bidder_id가 key
|
||||
TMyBidBoard pc_map;
|
||||
|
||||
public:
|
||||
|
@ -144,7 +144,7 @@ public:
|
|||
|
||||
BidInfo GetMoney (DWORD player_id, DWORD item_id);
|
||||
bool Delete (DWORD player_id, DWORD item_id);
|
||||
// 이미 있으면 덮어 씌운다.
|
||||
// 이미 있으면 덮어 씌운다.
|
||||
void Insert (DWORD player_id, DWORD item_id, int money);
|
||||
void Lock (DWORD player_id, DWORD item_id);
|
||||
void UnLock (DWORD player_id, DWORD item_id);
|
||||
|
@ -156,7 +156,7 @@ private :
|
|||
typedef std::unordered_map<DWORD, LPITEM> TItemMap;
|
||||
TItemMap auction_item_map;
|
||||
|
||||
// auction에 등록된 정보 중 가격, 등등 아이템 테이블에 포함되지 않는 정보들을 관리하는 것들
|
||||
// auction에 등록된 정보 중 가격, 등등 아이템 테이블에 포함되지 않는 정보들을 관리하는 것들
|
||||
AuctionBoard Auction;
|
||||
SaleBoard Sale;
|
||||
WishBoard Wish;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "banword.h"
|
||||
#include "config.h"
|
||||
|
||||
extern void SendLog(const char * c_pszBuf); // 운영자에게만 공지
|
||||
extern void SendLog(const char * c_pszBuf); // 운영자에게만 공지
|
||||
|
||||
CBanwordManager::CBanwordManager()
|
||||
{
|
||||
|
|
|
@ -46,7 +46,7 @@ bool timed_event_cancel(LPCHARACTER ch)
|
|||
}
|
||||
|
||||
/* RECALL_DELAY
|
||||
차후 전투로 인해 귀환부 딜레이가 취소 되어야 할 경우 주석 해제
|
||||
차후 전투로 인해 귀환부 딜레이가 취소 되어야 할 경우 주석 해제
|
||||
if (ch->m_pk_RecallEvent)
|
||||
{
|
||||
event_cancel(&ch->m_pkRecallEvent);
|
||||
|
@ -59,11 +59,11 @@ bool timed_event_cancel(LPCHARACTER ch)
|
|||
|
||||
bool battle_is_attackable(LPCHARACTER ch, LPCHARACTER victim)
|
||||
{
|
||||
// 상대방이 죽었으면 중단한다.
|
||||
// 상대방이 죽었으면 중단한다.
|
||||
if (victim->IsDead())
|
||||
return false;
|
||||
|
||||
// 안전지대면 중단
|
||||
// 안전지대면 중단
|
||||
{
|
||||
SECTREE *sectree = NULL;
|
||||
|
||||
|
@ -77,7 +77,7 @@ bool battle_is_attackable(LPCHARACTER ch, LPCHARACTER victim)
|
|||
}
|
||||
|
||||
|
||||
// 내가 죽었으면 중단한다.
|
||||
// 내가 죽었으면 중단한다.
|
||||
if (ch->IsStun() || ch->IsDead())
|
||||
return false;
|
||||
|
||||
|
@ -119,7 +119,7 @@ int battle_melee_attack(LPCHARACTER ch, LPCHARACTER victim)
|
|||
if (test_server&&ch->IsPC())
|
||||
SPDLOG_TRACE("battle_melee_attack : [{}] attack to [{}]", ch->GetName(), victim->GetName());
|
||||
|
||||
// 거리 체크
|
||||
// 거리 체크
|
||||
int distance = DISTANCE_APPROX(ch->GetX() - victim->GetX(), ch->GetY() - victim->GetY());
|
||||
|
||||
if (!victim->IsBuilding())
|
||||
|
@ -128,12 +128,12 @@ int battle_melee_attack(LPCHARACTER ch, LPCHARACTER victim)
|
|||
|
||||
if (false == ch->IsPC())
|
||||
{
|
||||
// 몬스터의 경우 몬스터 공격 거리를 사용
|
||||
// 몬스터의 경우 몬스터 공격 거리를 사용
|
||||
max = (int) (ch->GetMobAttackRange() * 1.15f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// PC일 경우 상대가 melee 몹일 경우 몹의 공격 거리가 최대 공격 거리
|
||||
// PC일 경우 상대가 melee 몹일 경우 몹의 공격 거리가 최대 공격 거리
|
||||
if (false == victim->IsPC() && BATTLE_TYPE_MELEE == victim->GetMobBattleType())
|
||||
max = std::max(300, (int) (victim->GetMobAttackRange() * 1.15f));
|
||||
}
|
||||
|
@ -147,10 +147,10 @@ int battle_melee_attack(LPCHARACTER ch, LPCHARACTER victim)
|
|||
}
|
||||
|
||||
if (timed_event_cancel(ch))
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("전투가 시작 되어 취소 되었습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Action cancelled. You have entered a battle."));
|
||||
|
||||
if (timed_event_cancel(victim))
|
||||
victim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("전투가 시작 되어 취소 되었습니다."));
|
||||
victim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Action cancelled. You have entered a battle."));
|
||||
|
||||
ch->SetPosition(POS_FIGHTING);
|
||||
ch->SetVictim(victim);
|
||||
|
@ -161,7 +161,7 @@ int battle_melee_attack(LPCHARACTER ch, LPCHARACTER victim)
|
|||
return battle_hit(ch, victim);
|
||||
}
|
||||
|
||||
// 실제 GET_BATTLE_VICTIM을 NULL로 만들고 이벤트를 캔슬 시킨다.
|
||||
// 실제 GET_BATTLE_VICTIM을 NULL로 만들고 이벤트를 캔슬 시킨다.
|
||||
void battle_end_ex(LPCHARACTER ch)
|
||||
{
|
||||
if (ch->IsPosition(POS_FIGHTING))
|
||||
|
@ -208,7 +208,7 @@ float CalcAttackRating(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, bool bIgnor
|
|||
int iARSrc;
|
||||
int iERSrc;
|
||||
|
||||
if (LC_IsYMIR()) // 천마
|
||||
if (LC_IsYMIR()) // 천마
|
||||
{
|
||||
iARSrc = std::min(90, pkAttacker->GetPolymorphPoint(POINT_DX));
|
||||
iERSrc = std::min(90, pkVictim->GetPolymorphPoint(POINT_DX));
|
||||
|
@ -238,11 +238,11 @@ float CalcAttackRating(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, bool bIgnor
|
|||
|
||||
int CalcAttBonus(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, int iAtk)
|
||||
{
|
||||
// PvP에는 적용하지않음
|
||||
// PvP에는 적용하지않음
|
||||
if (!pkVictim->IsPC())
|
||||
iAtk += pkAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_ATTACK_BONUS);
|
||||
|
||||
// PvP에는 적용하지않음
|
||||
// PvP에는 적용하지않음
|
||||
if (!pkAttacker->IsPC())
|
||||
{
|
||||
int iReduceDamagePct = pkVictim->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_TRANSFER_DAMAGE);
|
||||
|
@ -327,9 +327,9 @@ int CalcAttBonus(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, int iAtk)
|
|||
}
|
||||
}
|
||||
|
||||
//[ mob -> PC ] 원소 속성 방어 적용
|
||||
//[ mob -> PC ] 원소 속성 방어 적용
|
||||
//2013/01/17
|
||||
//몬스터 속성공격 데미지의 30%에 해당하는 수치에만 저항이 적용됨.
|
||||
//몬스터 속성공격 데미지의 30%에 해당하는 수치에만 저항이 적용됨.
|
||||
if (pkAttacker->IsNPC() && pkVictim->IsPC())
|
||||
{
|
||||
if (pkAttacker->IsRaceFlag(RACE_FLAG_ATT_ELEC))
|
||||
|
@ -553,7 +553,7 @@ int CalcArrowDamage(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, LPITEM pkBow,
|
|||
if (!pkArrow)
|
||||
return 0;
|
||||
|
||||
// 타격치 계산부
|
||||
// 타격치 계산부
|
||||
int iDist = (int) (DISTANCE_SQRT(pkAttacker->GetX() - pkVictim->GetX(), pkAttacker->GetY() - pkVictim->GetY()));
|
||||
//int iGap = (iDist / 100) - 5 - pkBow->GetValue(5) - pkAttacker->GetPoint(POINT_BOW_DISTANCE);
|
||||
int iGap = (iDist / 100) - 5 - pkAttacker->GetPoint(POINT_BOW_DISTANCE);
|
||||
|
@ -613,7 +613,7 @@ int CalcArrowDamage(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, LPITEM pkBow,
|
|||
|
||||
void NormalAttackAffect(LPCHARACTER pkAttacker, LPCHARACTER pkVictim)
|
||||
{
|
||||
// 독 공격은 특이하므로 특수 처리
|
||||
// 독 공격은 특이하므로 특수 처리
|
||||
if (pkAttacker->GetPoint(POINT_POISON_PCT) && !pkVictim->IsAffectFlag(AFF_POISON))
|
||||
{
|
||||
if (Random::get(1, 100) <= pkAttacker->GetPoint(POINT_POISON_PCT))
|
||||
|
@ -637,7 +637,7 @@ int battle_hit(LPCHARACTER pkAttacker, LPCHARACTER pkVictim)
|
|||
|
||||
NormalAttackAffect(pkAttacker, pkVictim);
|
||||
|
||||
// 데미지 계산
|
||||
// 데미지 계산
|
||||
//iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST)) / 100;
|
||||
LPITEM pkWeapon = pkAttacker->GetWear(WEAR_WEAPON);
|
||||
|
||||
|
@ -670,7 +670,7 @@ int battle_hit(LPCHARACTER pkAttacker, LPCHARACTER pkVictim)
|
|||
}
|
||||
|
||||
|
||||
//최종적인 데미지 보정. (2011년 2월 현재 대왕거미에게만 적용.)
|
||||
//최종적인 데미지 보정. (2011년 2월 현재 대왕거미에게만 적용.)
|
||||
float attMul = pkAttacker->GetAttMul();
|
||||
float tempIDam = iDam;
|
||||
iDam = attMul * tempIDam + 0.5f;
|
||||
|
@ -691,19 +691,19 @@ DWORD GET_ATTACK_SPEED(LPCHARACTER ch)
|
|||
return 1000;
|
||||
|
||||
LPITEM item = ch->GetWear(WEAR_WEAPON);
|
||||
DWORD default_bonus = SPEEDHACK_LIMIT_BONUS * 3; // 유두리 공속(기본 80) (일반 유저가 speed hack 에 걸리는 것을 막기 위해 *3 추가. 2013.09.11 CYH)
|
||||
DWORD default_bonus = SPEEDHACK_LIMIT_BONUS * 3; // 유두리 공속(기본 80) (일반 유저가 speed hack 에 걸리는 것을 막기 위해 *3 추가. 2013.09.11 CYH)
|
||||
DWORD riding_bonus = 0;
|
||||
|
||||
if (ch->IsRiding())
|
||||
{
|
||||
// 뭔가를 탔으면 추가공속 50
|
||||
// 뭔가를 탔으면 추가공속 50
|
||||
riding_bonus = 50;
|
||||
}
|
||||
|
||||
DWORD ani_speed = ani_attack_speed(ch);
|
||||
DWORD real_speed = (ani_speed * 100) / (default_bonus + ch->GetPoint(POINT_ATT_SPEED) + riding_bonus);
|
||||
|
||||
// 단검의 경우 공속 2배
|
||||
// 단검의 경우 공속 2배
|
||||
if (item && item->GetSubType() == WEAPON_DAGGER)
|
||||
real_speed /= 2;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "char.h"
|
||||
|
||||
enum EBattleTypes // 상대방 기준
|
||||
enum EBattleTypes // 상대방 기준
|
||||
{
|
||||
BATTLE_NONE,
|
||||
BATTLE_DAMAGE,
|
||||
|
@ -30,7 +30,7 @@ extern void NormalAttackAffect(LPCHARACTER pkAttacker, LPCHARACTER pkVictim);
|
|||
|
||||
extern int battle_hit(LPCHARACTER ch, LPCHARACTER victim);
|
||||
|
||||
// 특성 공격
|
||||
// 특성 공격
|
||||
inline void AttackAffect(LPCHARACTER pkAttacker,
|
||||
LPCHARACTER pkVictim,
|
||||
BYTE att_point,
|
||||
|
|
|
@ -13,7 +13,7 @@ public:
|
|||
{
|
||||
static TGradeUnit beltGradeByLevelTable[] =
|
||||
{
|
||||
0, // 벨트+0
|
||||
0, // 벨트+0
|
||||
1, // +1
|
||||
1, // +2
|
||||
2, // +3
|
||||
|
@ -34,20 +34,20 @@ public:
|
|||
return beltGradeByLevelTable[level];
|
||||
}
|
||||
|
||||
// 현재 벨트 레벨을 기준으로, 어떤 셀들을 이용할 수 있는지 리턴
|
||||
// 현재 벨트 레벨을 기준으로, 어떤 셀들을 이용할 수 있는지 리턴
|
||||
static const TGradeUnit* GetAvailableRuleTableByGrade()
|
||||
{
|
||||
/**
|
||||
벨트는 총 +0 ~ +9 레벨을 가질 수 있으며, 레벨에 따라 7단계 등급으로 구분되어 인벤토리가 활성 화 된다.
|
||||
벨트 레벨에 따른 사용 가능한 셀은 아래 그림과 같음. 현재 등급 >= 활성가능 등급이면 사용 가능.
|
||||
(단, 현재 레벨이 0이면 무조건 사용 불가, 괄호 안의 숫자는 등급)
|
||||
벨트는 총 +0 ~ +9 레벨을 가질 수 있으며, 레벨에 따라 7단계 등급으로 구분되어 인벤토리가 활성 화 된다.
|
||||
벨트 레벨에 따른 사용 가능한 셀은 아래 그림과 같음. 현재 등급 >= 활성가능 등급이면 사용 가능.
|
||||
(단, 현재 레벨이 0이면 무조건 사용 불가, 괄호 안의 숫자는 등급)
|
||||
|
||||
2(1) 4(2) 6(4) 8(6)
|
||||
5(3) 5(3) 6(4) 8(6)
|
||||
7(5) 7(5) 7(5) 8(6)
|
||||
9(7) 9(7) 9(7) 9(7)
|
||||
|
||||
벨트 인벤토리의 크기는 4x4 (16칸)
|
||||
벨트 인벤토리의 크기는 4x4 (16칸)
|
||||
*/
|
||||
|
||||
static TGradeUnit availableRuleByGrade[BELT_INVENTORY_SLOT_COUNT] = {
|
||||
|
@ -62,14 +62,14 @@ public:
|
|||
|
||||
static bool IsAvailableCell(WORD cell, int beltGrade /*int beltLevel*/)
|
||||
{
|
||||
// 기획 또 바뀜.. 아놔...
|
||||
// 기획 또 바뀜.. 아놔...
|
||||
//const TGradeUnit beltGrade = GetBeltGradeByRefineLevel(beltLevel);
|
||||
const TGradeUnit* ruleTable = GetAvailableRuleTableByGrade();
|
||||
|
||||
return ruleTable[cell] <= beltGrade;
|
||||
}
|
||||
|
||||
/// pc의 벨트 인벤토리에 아이템이 하나라도 존재하는 지 검사하는 함수.
|
||||
/// pc의 벨트 인벤토리에 아이템이 하나라도 존재하는 지 검사하는 함수.
|
||||
static bool IsExistItemInBeltInventory(LPCHARACTER pc)
|
||||
{
|
||||
for (WORD i = BELT_INVENTORY_SLOT_START; i < BELT_INVENTORY_SLOT_END; ++i)
|
||||
|
@ -83,7 +83,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
/// item이 벨트 인벤토리에 들어갈 수 있는 타입인지 검사하는 함수. (이 규칙은 기획자가 결정함)
|
||||
/// item이 벨트 인벤토리에 들어갈 수 있는 타입인지 검사하는 함수. (이 규칙은 기획자가 결정함)
|
||||
static bool CanMoveIntoBeltInventory(LPITEM item)
|
||||
{
|
||||
bool canMove = false;
|
||||
|
|
|
@ -170,10 +170,10 @@ static int FN_random_index()
|
|||
return 0;
|
||||
}
|
||||
|
||||
// 충기환의 확률 테이블
|
||||
// blend.txt에서 확률도 받도록 고치면 깔끔하겠지만
|
||||
// 각 나라별로 item proto 등을 따로 관리하므로,
|
||||
// 혼란이 올 수 있어 이렇게 추가한다.
|
||||
// 충기환의 확률 테이블
|
||||
// blend.txt에서 확률도 받도록 고치면 깔끔하겠지만
|
||||
// 각 나라별로 item proto 등을 따로 관리하므로,
|
||||
// 혼란이 올 수 있어 이렇게 추가한다.
|
||||
// by rtsummit
|
||||
|
||||
static int FN_ECS_random_index()
|
||||
|
|
|
@ -39,8 +39,8 @@ void CBuffOnAttributes::RemoveBuffFromItem(LPITEM pItem)
|
|||
{
|
||||
TPlayerItemAttribute attr = pItem->GetAttribute(j);
|
||||
TMapAttr::iterator it = m_map_additional_attrs.find(attr.bType);
|
||||
// m_map_additional_attrs에서 해당 attribute type에 대한 값을 제거하고,
|
||||
// 변경된 값의 (m_bBuffValue)%만큼의 버프 효과 감소
|
||||
// m_map_additional_attrs에서 해당 attribute type에 대한 값을 제거하고,
|
||||
// 변경된 값의 (m_bBuffValue)%만큼의 버프 효과 감소
|
||||
if (it != m_map_additional_attrs.end())
|
||||
{
|
||||
int& sum_of_attr_value = it->second;
|
||||
|
@ -76,15 +76,15 @@ void CBuffOnAttributes::AddBuffFromItem(LPITEM pItem)
|
|||
TPlayerItemAttribute attr = pItem->GetAttribute(j);
|
||||
TMapAttr::iterator it = m_map_additional_attrs.find(attr.bType);
|
||||
|
||||
// m_map_additional_attrs에서 해당 attribute type에 대한 값이 없다면 추가.
|
||||
// 추가된 값의 (m_bBuffValue)%만큼의 버프 효과 추가
|
||||
// m_map_additional_attrs에서 해당 attribute type에 대한 값이 없다면 추가.
|
||||
// 추가된 값의 (m_bBuffValue)%만큼의 버프 효과 추가
|
||||
if (it == m_map_additional_attrs.end())
|
||||
{
|
||||
m_pBuffOwner->ApplyPoint(attr.bType, attr.sValue * m_bBuffValue / 100);
|
||||
m_map_additional_attrs.insert(TMapAttr::value_type(attr.bType, attr.sValue));
|
||||
}
|
||||
// m_map_additional_attrs에서 해당 attribute type에 대한 값이 있다면, 그 값을 증가시키고,
|
||||
// 변경된 값의 (m_bBuffValue)%만큼의 버프 효과 추가
|
||||
// m_map_additional_attrs에서 해당 attribute type에 대한 값이 있다면, 그 값을 증가시키고,
|
||||
// 변경된 값의 (m_bBuffValue)%만큼의 버프 효과 추가
|
||||
else
|
||||
{
|
||||
int& sum_of_attr_value = it->second;
|
||||
|
@ -105,8 +105,8 @@ void CBuffOnAttributes::ChangeBuffValue(BYTE bNewValue)
|
|||
Off();
|
||||
else
|
||||
{
|
||||
// 기존에, m_map_additional_attrs의 값의 (m_bBuffValue)%만큼이 버프로 들어가 있었으므로,
|
||||
// (bNewValue)%만큼으로 값을 변경함.
|
||||
// 기존에, m_map_additional_attrs의 값의 (m_bBuffValue)%만큼이 버프로 들어가 있었으므로,
|
||||
// (bNewValue)%만큼으로 값을 변경함.
|
||||
for (TMapAttr::iterator it = m_map_additional_attrs.begin(); it != m_map_additional_attrs.end(); it++)
|
||||
{
|
||||
int& sum_of_attr_value = it->second;
|
||||
|
|
|
@ -9,20 +9,20 @@ public:
|
|||
CBuffOnAttributes(LPCHARACTER pOwner, BYTE m_point_type, std::vector <BYTE>* vec_buff_targets);
|
||||
~CBuffOnAttributes();
|
||||
|
||||
// 장착 중 이면서, m_p_vec_buff_wear_targets에 해당하는 아이템인 경우, 해당 아이템으로 인해 붙은 효과를 제거.
|
||||
// 장착 중 이면서, m_p_vec_buff_wear_targets에 해당하는 아이템인 경우, 해당 아이템으로 인해 붙은 효과를 제거.
|
||||
void RemoveBuffFromItem(LPITEM pItem);
|
||||
// m_p_vec_buff_wear_targets에 해당하는 아이템인 경우, 해당 아이템의 attribute에 대한 효과 추가.
|
||||
// m_p_vec_buff_wear_targets에 해당하는 아이템인 경우, 해당 아이템의 attribute에 대한 효과 추가.
|
||||
void AddBuffFromItem(LPITEM pItem);
|
||||
// m_bBuffValue를 바꾸고, 버프의 값도 바꿈.
|
||||
// m_bBuffValue를 바꾸고, 버프의 값도 바꿈.
|
||||
void ChangeBuffValue(BYTE bNewValue);
|
||||
// CHRACTRE::ComputePoints에서 속성치를 초기화하고 다시 계산하므로,
|
||||
// 버프 속성치들을 강제적으로 owner에게 줌.
|
||||
// CHRACTRE::ComputePoints에서 속성치를 초기화하고 다시 계산하므로,
|
||||
// 버프 속성치들을 강제적으로 owner에게 줌.
|
||||
void GiveAllAttributes();
|
||||
|
||||
// m_p_vec_buff_wear_targets에 해당하는 모든 아이템의 attribute를 type별로 합산하고,
|
||||
// 그 attribute들의 (m_bBuffValue)% 만큼을 버프로 줌.
|
||||
// m_p_vec_buff_wear_targets에 해당하는 모든 아이템의 attribute를 type별로 합산하고,
|
||||
// 그 attribute들의 (m_bBuffValue)% 만큼을 버프로 줌.
|
||||
bool On(BYTE bValue);
|
||||
// 버프 제거 후, 초기화
|
||||
// 버프 제거 후, 초기화
|
||||
void Off();
|
||||
|
||||
void Initialize();
|
||||
|
@ -32,9 +32,9 @@ private:
|
|||
BYTE m_bBuffValue;
|
||||
std::vector <BYTE>* m_p_vec_buff_wear_targets;
|
||||
|
||||
// apply_type, apply_value 페어의 맵
|
||||
// apply_type, apply_value 페어의 맵
|
||||
typedef std::map <BYTE, int> TMapAttr;
|
||||
// m_p_vec_buff_wear_targets에 해당하는 모든 아이템의 attribute를 type별로 합산하여 가지고 있음.
|
||||
// m_p_vec_buff_wear_targets에 해당하는 모든 아이템의 attribute를 type별로 합산하여 가지고 있음.
|
||||
TMapAttr m_map_additional_attrs;
|
||||
|
||||
};
|
||||
|
|
|
@ -112,7 +112,7 @@ void CObject::EncodeInsertPacket(LPENTITY entity)
|
|||
pack.z = GetZ();
|
||||
pack.wRaceNum = m_data.dwVnum;
|
||||
|
||||
// 빌딩 회전 정보(벽일때는 문 위치)를 변환
|
||||
// 빌딩 회전 정보(벽일때는 문 위치)를 변환
|
||||
pack.dwAffectFlag[0] = unsigned(m_data.xRot);
|
||||
pack.dwAffectFlag[1] = unsigned(m_data.yRot);
|
||||
|
||||
|
@ -298,7 +298,7 @@ void CObject::RegenNPC()
|
|||
|
||||
m_chNPC->SetGuild(pGuild);
|
||||
|
||||
// 힘의 신전일 경우 길드 레벨을 길마에게 저장해놓는다
|
||||
// 힘의 신전일 경우 길드 레벨을 길마에게 저장해놓는다
|
||||
if ( m_pProto->dwVnum == 14061 || m_pProto->dwVnum == 14062 || m_pProto->dwVnum == 14063 )
|
||||
{
|
||||
quest::PC* pPC = quest::CQuestManager::instance().GetPC(pGuild->GetMasterPID());
|
||||
|
@ -690,10 +690,10 @@ TObjectProto * CManager::GetObjectProto(DWORD dwVnum)
|
|||
|
||||
bool CManager::LoadLand(TLand * pTable) // from DB
|
||||
{
|
||||
// MapAllow에 없는 맵의 땅일지라도 load를 해야한다.
|
||||
// 건물(object)이 어느 길드에 속해 있는지 알기 위해서는 건물이 세위진 땅이 어느 길드 소속인지 알아한다.
|
||||
// 만약 땅을 load해 놓지 않으면 길드 건물이 어느 길드에 소속된 건지 알지 못해서
|
||||
// 길드 건물에 의한 길드 버프를 받지 못한다.
|
||||
// MapAllow에 없는 맵의 땅일지라도 load를 해야한다.
|
||||
// 건물(object)이 어느 길드에 속해 있는지 알기 위해서는 건물이 세위진 땅이 어느 길드 소속인지 알아한다.
|
||||
// 만약 땅을 load해 놓지 않으면 길드 건물이 어느 길드에 소속된 건지 알지 못해서
|
||||
// 길드 건물에 의한 길드 버프를 받지 못한다.
|
||||
//if (!map_allow_find(pTable->lMapIndex))
|
||||
// return false;
|
||||
|
||||
|
@ -1098,7 +1098,7 @@ bool CLand::RequestCreateWall(int nMapIndex, float rot)
|
|||
int wall_half_w = 1000;
|
||||
int wall_half_h = 1362;
|
||||
|
||||
if (rot == 0.0f) // 남쪽 문
|
||||
if (rot == 0.0f) // 남쪽 문
|
||||
{
|
||||
int door_x = wall_x;
|
||||
int door_y = wall_y + wall_half_h;
|
||||
|
@ -1107,7 +1107,7 @@ bool CLand::RequestCreateWall(int nMapIndex, float rot)
|
|||
RequestCreateObject(WALL_LEFT_VNUM, nMapIndex, wall_x - wall_half_w, wall_y, door_x, door_y, 0.0f, WALL_ANOTHER_CHECKING_ENABLE);
|
||||
RequestCreateObject(WALL_RIGHT_VNUM, nMapIndex, wall_x + wall_half_w, wall_y, door_x, door_y, 0.0f, WALL_ANOTHER_CHECKING_ENABLE);
|
||||
}
|
||||
else if (rot == 180.0f) // 북쪽 문
|
||||
else if (rot == 180.0f) // 북쪽 문
|
||||
{
|
||||
int door_x = wall_x;
|
||||
int door_y = wall_y - wall_half_h;
|
||||
|
@ -1116,7 +1116,7 @@ bool CLand::RequestCreateWall(int nMapIndex, float rot)
|
|||
RequestCreateObject(WALL_LEFT_VNUM, nMapIndex, wall_x - wall_half_w, wall_y, door_x, door_y, 0.0f, WALL_ANOTHER_CHECKING_ENABLE);
|
||||
RequestCreateObject(WALL_RIGHT_VNUM, nMapIndex, wall_x + wall_half_w, wall_y, door_x, door_y, 0.0f, WALL_ANOTHER_CHECKING_ENABLE);
|
||||
}
|
||||
else if (rot == 90.0f) // 동쪽 문
|
||||
else if (rot == 90.0f) // 동쪽 문
|
||||
{
|
||||
int door_x = wall_x + wall_half_h;
|
||||
int door_y = wall_y;
|
||||
|
@ -1125,7 +1125,7 @@ bool CLand::RequestCreateWall(int nMapIndex, float rot)
|
|||
RequestCreateObject(WALL_LEFT_VNUM, nMapIndex, wall_x, wall_y - wall_half_w, door_x, door_y, 90.0f, WALL_ANOTHER_CHECKING_ENABLE);
|
||||
RequestCreateObject(WALL_RIGHT_VNUM, nMapIndex, wall_x, wall_y + wall_half_w, door_x, door_y, 90.0f, WALL_ANOTHER_CHECKING_ENABLE);
|
||||
}
|
||||
else if (rot == 270.0f) // 서쪽 문
|
||||
else if (rot == 270.0f) // 서쪽 문
|
||||
{
|
||||
int door_x = wall_x - wall_half_h;
|
||||
int door_y = wall_y;
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
* file : castle.cpp
|
||||
* author : mhh
|
||||
* description :
|
||||
* 봉화 번호 : 11506 - 11510
|
||||
* 메틴석 번호 : 8012 - 8014, 8024-8027
|
||||
* 봉화 번호 : 11506 - 11510
|
||||
* 메틴석 번호 : 8012 - 8014, 8024-8027
|
||||
*/
|
||||
|
||||
#define _castle_cpp_
|
||||
|
@ -21,13 +21,13 @@
|
|||
#include "char.h"
|
||||
#include "sectree_manager.h"
|
||||
|
||||
#define EMPIRE_NONE 0 // 아무국가 아님
|
||||
#define EMPIRE_RED 1 // 신수
|
||||
#define EMPIRE_YELLOW 2 // 천조
|
||||
#define EMPIRE_BLUE 3 // 진노
|
||||
#define EMPIRE_NONE 0 // 아무국가 아님
|
||||
#define EMPIRE_RED 1 // 신수
|
||||
#define EMPIRE_YELLOW 2 // 천조
|
||||
#define EMPIRE_BLUE 3 // 진노
|
||||
|
||||
|
||||
#define SIEGE_EVENT_PULSE PASSES_PER_SEC(60*5) // 5분
|
||||
#define SIEGE_EVENT_PULSE PASSES_PER_SEC(60*5) // 5분
|
||||
|
||||
|
||||
#define GET_CAHR_MANAGER() CHARACTER_MANAGER::instance()
|
||||
|
@ -171,7 +171,7 @@ static POSITION s_frog_pos[4][MAX_CASTLE_FROG] = {
|
|||
};
|
||||
|
||||
|
||||
/* 경비병 경비구역 */
|
||||
/* 경비병 경비구역 */
|
||||
struct GUARD_REGION
|
||||
{
|
||||
int sx, sy, ex, ey;
|
||||
|
@ -247,10 +247,10 @@ EVENTFUNC(castle_siege_event)
|
|||
|
||||
info->pulse += SIEGE_EVENT_PULSE;
|
||||
|
||||
// 공성 시작후 30분 이내라면 안내만 하자
|
||||
// 공성 시작후 30분 이내라면 안내만 하자
|
||||
if (info->pulse < PASSES_PER_SEC(30*60))
|
||||
{
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("%s에서 봉화를 둘러싸고 전투가 진행중입니다."),
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("There are %s wars to inflame the bonfires."),
|
||||
EMPIRE_NAME(GET_SIEGE_EMPIRE()));
|
||||
BroadcastNotice(buf);
|
||||
|
||||
|
@ -264,19 +264,19 @@ EVENTFUNC(castle_siege_event)
|
|||
|
||||
case CASTLE_SIEGE_STRUGGLE:
|
||||
{
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("%s이 수성에 성공했습니다."), EMPIRE_NAME(GET_SIEGE_EMPIRE()));
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("%s has successfully defended."), EMPIRE_NAME(GET_SIEGE_EMPIRE()));
|
||||
BroadcastNotice(buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("지금부터 %s은 30분간 봉화를 파괴하여 보상을 획득 할 수 있습니다."), EMPIRE_NAME(GET_SIEGE_EMPIRE()));
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("30 minutes from now on the player %s can get a reward because he destroyed the bonfire."), EMPIRE_NAME(GET_SIEGE_EMPIRE()));
|
||||
BroadcastNotice(buf);
|
||||
|
||||
GET_SIEGE_STATE() = CASTLE_SIEGE_END;
|
||||
|
||||
return PASSES_PER_SEC(60*30); // 30분
|
||||
return PASSES_PER_SEC(60*30); // 30분
|
||||
}
|
||||
break;
|
||||
case CASTLE_SIEGE_END:
|
||||
BroadcastNotice(LC_TEXT("30분이 경과했습니다.. 봉화가 사라집니다."));
|
||||
BroadcastNotice(LC_TEXT("30 minutes are over. The bonfires have disappeared."));
|
||||
castle_end_siege();
|
||||
break;
|
||||
}
|
||||
|
@ -331,7 +331,7 @@ EVENTFUNC(castle_stone_event)
|
|||
if (NULL == sectree_map)
|
||||
return 0;
|
||||
|
||||
/* 15마리씩 2번 소환 */
|
||||
/* 15마리씩 2번 소환 */
|
||||
const int SPAWN_COUNT = 15;
|
||||
|
||||
if (info->spawn_count < (SPAWN_COUNT * 2))
|
||||
|
@ -351,7 +351,7 @@ EVENTFUNC(castle_stone_event)
|
|||
info->spawn_count += SPAWN_COUNT;
|
||||
|
||||
if (info->spawn_count < (SPAWN_COUNT * 2))
|
||||
return PASSES_PER_SEC(30 * 60); // 30분
|
||||
return PASSES_PER_SEC(30 * 60); // 30분
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
@ -598,24 +598,24 @@ void castle_start_siege(int empire, int tower_count)
|
|||
|
||||
castle_spawn_tower(empire, tower_count);
|
||||
|
||||
/* 공성 타이머 시작 */
|
||||
/* 공성 타이머 시작 */
|
||||
{
|
||||
castle_event_info* info = AllocEventInfo<castle_event_info>();
|
||||
|
||||
info->empire = empire;
|
||||
info->pulse = 0;
|
||||
|
||||
GET_SIEGE_EVENT(empire) = event_create(castle_siege_event, info, /*5분*/SIEGE_EVENT_PULSE);
|
||||
GET_SIEGE_EVENT(empire) = event_create(castle_siege_event, info, /*5분*/SIEGE_EVENT_PULSE);
|
||||
}
|
||||
|
||||
/* 메틴석 소환 타이머 시작 */
|
||||
/* 메틴석 소환 타이머 시작 */
|
||||
{
|
||||
castle_stone_event_info* info = AllocEventInfo<castle_stone_event_info>();
|
||||
|
||||
info->spawn_count = 0;
|
||||
info->empire = empire;
|
||||
|
||||
GET_STONE_EVENT(empire) = event_create(castle_stone_event, info, /* 1초 */PASSES_PER_SEC(1));
|
||||
GET_STONE_EVENT(empire) = event_create(castle_stone_event, info, /* 1초 */PASSES_PER_SEC(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -649,7 +649,7 @@ LPCHARACTER castle_spawn_frog(int empire)
|
|||
int dir = 1;
|
||||
int map_index = FN_castle_map_index(empire);
|
||||
|
||||
/* 황금두꺼비 소환할 곳이 있나? */
|
||||
/* 황금두꺼비 소환할 곳이 있나? */
|
||||
POSITION *empty_pos = FN_empty_frog_pos(empire);
|
||||
if (NULL == empty_pos)
|
||||
return NULL;
|
||||
|
@ -667,7 +667,7 @@ LPCHARACTER castle_spawn_frog(int empire)
|
|||
{
|
||||
frog->SetEmpire(empire);
|
||||
int empty_index = FN_empty_frog_index(empire);
|
||||
// 스폰성공
|
||||
// 스폰성공
|
||||
GET_FROG(empire, empty_index) = frog;
|
||||
return frog;
|
||||
}
|
||||
|
@ -778,7 +778,7 @@ bool castle_spawn_tower(int empire, int tower_count)
|
|||
if (NULL == sectree_map)
|
||||
return false;
|
||||
|
||||
// 초기화
|
||||
// 초기화
|
||||
DO_ALL_TOWER(i)
|
||||
{
|
||||
if (GET_TOWER(empire, i))
|
||||
|
@ -786,7 +786,7 @@ bool castle_spawn_tower(int empire, int tower_count)
|
|||
GET_TOWER(empire, i) = NULL;
|
||||
}
|
||||
|
||||
int spawn_count = std::clamp(tower_count, MIN_CASTLE_TOWER, MAX_CASTLE_TOWER); // 5 ~ 10마리
|
||||
int spawn_count = std::clamp(tower_count, MIN_CASTLE_TOWER, MAX_CASTLE_TOWER); // 5 ~ 10마리
|
||||
|
||||
for (int j = 0; j < spawn_count; ++j)
|
||||
{
|
||||
|
@ -796,13 +796,13 @@ bool castle_spawn_tower(int empire, int tower_count)
|
|||
// broad cast
|
||||
{
|
||||
char buf[1024];
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("%s에 전쟁의 시작을 알리는 봉화가 나타났습니다."), EMPIRE_NAME(empire));
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("A bonfire was inflamed at %s to warn because of a battle."), EMPIRE_NAME(empire));
|
||||
BroadcastNotice(buf);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 경비병리더가 죽으면 단순하게 슬롯만 비운다. */
|
||||
/* 경비병리더가 죽으면 단순하게 슬롯만 비운다. */
|
||||
void castle_guard_die(LPCHARACTER ch, LPCHARACTER killer)
|
||||
{
|
||||
int empire = ch->GetEmpire();
|
||||
|
@ -823,7 +823,7 @@ void castle_guard_die(LPCHARACTER ch, LPCHARACTER killer)
|
|||
}
|
||||
|
||||
|
||||
/* 황금 두꺼비가 죽으면 killer에게 1천만냥 */
|
||||
/* 황금 두꺼비가 죽으면 killer에게 1천만냥 */
|
||||
void castle_frog_die(LPCHARACTER ch, LPCHARACTER killer)
|
||||
{
|
||||
if (NULL == ch || NULL == killer)
|
||||
|
@ -837,15 +837,15 @@ void castle_frog_die(LPCHARACTER ch, LPCHARACTER killer)
|
|||
{
|
||||
GET_FROG(empire, i) = NULL;
|
||||
|
||||
killer->PointChange(POINT_GOLD, 10000000 /*1천만*/, true);
|
||||
//CMonarch::instance().SendtoDBAddMoney(30000000/*3천만*/, killer->GetEmpire(), killer);
|
||||
killer->PointChange(POINT_GOLD, 10000000 /*1천만*/, true);
|
||||
//CMonarch::instance().SendtoDBAddMoney(30000000/*3천만*/, killer->GetEmpire(), killer);
|
||||
castle_save();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 봉화가 모두 죽으면(?) 공성전이 끝난다 */
|
||||
/* 봉화가 모두 죽으면(?) 공성전이 끝난다 */
|
||||
void castle_tower_die(LPCHARACTER ch, LPCHARACTER killer)
|
||||
{
|
||||
char buf[1024] = {0};
|
||||
|
@ -864,7 +864,7 @@ void castle_tower_die(LPCHARACTER ch, LPCHARACTER killer)
|
|||
case CASTLE_SIEGE_END:
|
||||
{
|
||||
int siege_end = true;
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("%s이 봉화를 파괴했습니다."), EMPIRE_NAME(killer_empire));
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("%s has destroyed the bonfire."), EMPIRE_NAME(killer_empire));
|
||||
BroadcastNotice(buf);
|
||||
|
||||
LogManager::instance().CharLog(killer, 0, "CASTLE_TORCH_KILL", "");
|
||||
|
@ -885,12 +885,12 @@ void castle_tower_die(LPCHARACTER ch, LPCHARACTER killer)
|
|||
{
|
||||
if (GET_SIEGE_STATE() == CASTLE_SIEGE_STRUGGLE)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("%s이 수성에 실패하여 전쟁에 패배하였습니다.."), EMPIRE_NAME(GET_SIEGE_EMPIRE()));
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("%s lost the war as they have not been able to defend the castle."), EMPIRE_NAME(GET_SIEGE_EMPIRE()));
|
||||
BroadcastNotice(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("%s이 모든 봉화를 파괴하였습니다."), EMPIRE_NAME(GET_SIEGE_EMPIRE()));
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("%s has destroyed all the bonfires."), EMPIRE_NAME(GET_SIEGE_EMPIRE()));
|
||||
BroadcastNotice(buf);
|
||||
}
|
||||
castle_end_siege();
|
||||
|
@ -929,27 +929,27 @@ bool castle_is_guard_vnum(DWORD vnum)
|
|||
{
|
||||
switch (vnum)
|
||||
{
|
||||
/* 상급 창경비병 */
|
||||
/* 상급 창경비병 */
|
||||
case 11112:
|
||||
case 11114:
|
||||
case 11116:
|
||||
/* 중급 창경비병 */
|
||||
/* 중급 창경비병 */
|
||||
case 11106:
|
||||
case 11108:
|
||||
case 11110:
|
||||
/* 하급 창경비병 */
|
||||
/* 하급 창경비병 */
|
||||
case 11100:
|
||||
case 11102:
|
||||
case 11104:
|
||||
/* 상급 활경비병 */
|
||||
/* 상급 활경비병 */
|
||||
case 11113:
|
||||
case 11115:
|
||||
case 11117:
|
||||
/* 중급 활경비병 */
|
||||
/* 중급 활경비병 */
|
||||
case 11107:
|
||||
case 11109:
|
||||
case 11111:
|
||||
/* 하급 활경비병 */
|
||||
/* 하급 활경비병 */
|
||||
case 11101:
|
||||
case 11103:
|
||||
case 11105:
|
||||
|
@ -963,34 +963,34 @@ int castle_cost_of_hiring_guard(DWORD group_vnum)
|
|||
{
|
||||
switch (group_vnum)
|
||||
{
|
||||
/* 하급 */
|
||||
case 9501: /* 신수 창경비 */
|
||||
case 9511: /* 진노 창경비 */
|
||||
case 9521: /* 천조 창경비 */
|
||||
/* 하급 */
|
||||
case 9501: /* 신수 창경비 */
|
||||
case 9511: /* 진노 창경비 */
|
||||
case 9521: /* 천조 창경비 */
|
||||
|
||||
case 9502: /* 신수 활경비 */
|
||||
case 9512: /* 진노 활경비 */
|
||||
case 9522: /* 천조 활경비 */
|
||||
case 9502: /* 신수 활경비 */
|
||||
case 9512: /* 진노 활경비 */
|
||||
case 9522: /* 천조 활경비 */
|
||||
return (100*10000);
|
||||
|
||||
/* 중급 */
|
||||
case 9503: /* 신수 창경비 */
|
||||
case 9513: /* 진노 창경비 */
|
||||
case 9523: /* 천조 창경비 */
|
||||
/* 중급 */
|
||||
case 9503: /* 신수 창경비 */
|
||||
case 9513: /* 진노 창경비 */
|
||||
case 9523: /* 천조 창경비 */
|
||||
|
||||
case 9504: /* 신수 활경비 */
|
||||
case 9514: /* 진노 활경비 */
|
||||
case 9524: /* 천조 활경비 */
|
||||
case 9504: /* 신수 활경비 */
|
||||
case 9514: /* 진노 활경비 */
|
||||
case 9524: /* 천조 활경비 */
|
||||
return (300*10000);
|
||||
|
||||
/* 상급 */
|
||||
case 9505: /* 신수 창경비 */
|
||||
case 9515: /* 진노 창경비 */
|
||||
case 9525: /* 천조 창경비 */
|
||||
/* 상급 */
|
||||
case 9505: /* 신수 창경비 */
|
||||
case 9515: /* 진노 창경비 */
|
||||
case 9525: /* 천조 창경비 */
|
||||
|
||||
case 9506: /* 신수 활경비 */
|
||||
case 9516: /* 진노 활경비 */
|
||||
case 9526: /* 천조 활경비 */
|
||||
case 9506: /* 신수 활경비 */
|
||||
case 9516: /* 진노 활경비 */
|
||||
case 9526: /* 천조 활경비 */
|
||||
return (1000*10000);
|
||||
}
|
||||
|
||||
|
@ -1010,7 +1010,7 @@ bool castle_can_attack(LPCHARACTER ch, LPCHARACTER victim)
|
|||
|
||||
if (CASTLE_SIEGE_END == GET_SIEGE_STATE())
|
||||
{
|
||||
// 수성에 성공했을때 같은 제국만 봉화를 칠 수 있음
|
||||
// 수성에 성공했을때 같은 제국만 봉화를 칠 수 있음
|
||||
if (castle_is_tower_vnum(victim->GetRaceNum()))
|
||||
{
|
||||
if (ch->GetEmpire() == victim->GetEmpire())
|
||||
|
@ -1020,7 +1020,7 @@ bool castle_can_attack(LPCHARACTER ch, LPCHARACTER victim)
|
|||
}
|
||||
}
|
||||
|
||||
// 같은 제국은 파괴 불가
|
||||
// 같은 제국은 파괴 불가
|
||||
if (ch->GetEmpire() == victim->GetEmpire())
|
||||
return false;
|
||||
|
||||
|
@ -1044,7 +1044,7 @@ bool castle_frog_to_empire_money(LPCHARACTER ch)
|
|||
if (false == CMonarch::instance().SendtoDBAddMoney(CASTLE_FROG_PRICE, empire, ch))
|
||||
return false;
|
||||
|
||||
GET_FROG(empire, i) = NULL; // 등록해제
|
||||
GET_FROG(empire, i) = NULL; // 등록해제
|
||||
npc->Dead(/*killer*/NULL, /*immediate_dead*/true);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -9,36 +9,36 @@
|
|||
#define _castle_h_
|
||||
|
||||
|
||||
#define MAX_CASTLE_GUARD_REGION 4 // 경비병 배치 구역
|
||||
#define MAX_CASTLE_GUARD_PER_REGION 10 // 한지역에 배치할수있는 경비병그룹
|
||||
#define MAX_CASTLE_FROG 20 // 황금 두꺼비
|
||||
#define MAX_CASTLE_TOWER 10 // 봉화 최대 소환 개수
|
||||
#define MIN_CASTLE_TOWER 5 // 봉화 최소 소환 개수
|
||||
#define MAX_CASTLE_GUARD_REGION 4 // 경비병 배치 구역
|
||||
#define MAX_CASTLE_GUARD_PER_REGION 10 // 한지역에 배치할수있는 경비병그룹
|
||||
#define MAX_CASTLE_FROG 20 // 황금 두꺼비
|
||||
#define MAX_CASTLE_TOWER 10 // 봉화 최대 소환 개수
|
||||
#define MIN_CASTLE_TOWER 5 // 봉화 최소 소환 개수
|
||||
|
||||
|
||||
#define CASTLE_FROG_PRICE 100000000 // 황금두꺼비 가격 (1억)
|
||||
#define CASTLE_FROG_VNUM 11505 // 황금두꺼비 번호
|
||||
//#define CASTLE_TOWER_VNUM 11506 // 봉화 번호
|
||||
#define CASTLE_FROG_PRICE 100000000 // 황금두꺼비 가격 (1억)
|
||||
#define CASTLE_FROG_VNUM 11505 // 황금두꺼비 번호
|
||||
//#define CASTLE_TOWER_VNUM 11506 // 봉화 번호
|
||||
#define IS_CASTLE_MAP(map) (181==(map)||182==(map)||(183)==(map))
|
||||
//#define IS_CASTLE_TOWER(vnum) (11506==(vnum)||11507==(vnum)||11508==(vnum)||11509==(vnum) || 11510==(vnum))
|
||||
|
||||
|
||||
enum CASTLE_STATE
|
||||
{
|
||||
CASTLE_SIEGE_NONE, // 평화모드
|
||||
CASTLE_SIEGE_STRUGGLE, // 공성중
|
||||
CASTLE_SIEGE_END // 수성에 성공했다면 1시간동안 봉화를 깰 수 있다.
|
||||
CASTLE_SIEGE_NONE, // 평화모드
|
||||
CASTLE_SIEGE_STRUGGLE, // 공성중
|
||||
CASTLE_SIEGE_END // 수성에 성공했다면 1시간동안 봉화를 깰 수 있다.
|
||||
};
|
||||
|
||||
|
||||
struct CASTLE_DATA
|
||||
{
|
||||
LPCHARACTER frog[MAX_CASTLE_FROG]; // 황금두꺼비
|
||||
LPCHARACTER frog[MAX_CASTLE_FROG]; // 황금두꺼비
|
||||
|
||||
LPCHARACTER guard[MAX_CASTLE_GUARD_REGION][MAX_CASTLE_GUARD_PER_REGION]; // 경비병 리더
|
||||
DWORD guard_group[MAX_CASTLE_GUARD_REGION][MAX_CASTLE_GUARD_PER_REGION]; // 경비병 리더
|
||||
LPCHARACTER guard[MAX_CASTLE_GUARD_REGION][MAX_CASTLE_GUARD_PER_REGION]; // 경비병 리더
|
||||
DWORD guard_group[MAX_CASTLE_GUARD_REGION][MAX_CASTLE_GUARD_PER_REGION]; // 경비병 리더
|
||||
|
||||
LPCHARACTER tower[MAX_CASTLE_TOWER]; // 봉화
|
||||
LPCHARACTER tower[MAX_CASTLE_TOWER]; // 봉화
|
||||
|
||||
LPEVENT siege_event;
|
||||
LPEVENT stone_event;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -83,7 +83,7 @@ enum EDamageType
|
|||
DAMAGE_TYPE_NONE,
|
||||
DAMAGE_TYPE_NORMAL,
|
||||
DAMAGE_TYPE_NORMAL_RANGE,
|
||||
//스킬
|
||||
//스킬
|
||||
DAMAGE_TYPE_MELEE,
|
||||
DAMAGE_TYPE_RANGE,
|
||||
DAMAGE_TYPE_FIRE,
|
||||
|
@ -105,103 +105,103 @@ enum EPointTypes
|
|||
POINT_MAX_HP, // 6
|
||||
POINT_SP, // 7
|
||||
POINT_MAX_SP, // 8
|
||||
POINT_STAMINA, // 9 스테미너
|
||||
POINT_MAX_STAMINA, // 10 최대 스테미너
|
||||
POINT_STAMINA, // 9 스테미너
|
||||
POINT_MAX_STAMINA, // 10 최대 스테미너
|
||||
|
||||
POINT_GOLD, // 11
|
||||
POINT_ST, // 12 근력
|
||||
POINT_HT, // 13 체력
|
||||
POINT_DX, // 14 민첩성
|
||||
POINT_IQ, // 15 정신력
|
||||
POINT_ST, // 12 근력
|
||||
POINT_HT, // 13 체력
|
||||
POINT_DX, // 14 민첩성
|
||||
POINT_IQ, // 15 정신력
|
||||
POINT_DEF_GRADE, // 16 ...
|
||||
POINT_ATT_SPEED, // 17 공격속도
|
||||
POINT_ATT_GRADE, // 18 공격력 MAX
|
||||
POINT_MOV_SPEED, // 19 이동속도
|
||||
POINT_CLIENT_DEF_GRADE, // 20 방어등급
|
||||
POINT_CASTING_SPEED, // 21 주문속도 (쿨다운타임*100) / (100 + 이값) = 최종 쿨다운 타임
|
||||
POINT_MAGIC_ATT_GRADE, // 22 마법공격력
|
||||
POINT_MAGIC_DEF_GRADE, // 23 마법방어력
|
||||
POINT_EMPIRE_POINT, // 24 제국점수
|
||||
POINT_LEVEL_STEP, // 25 한 레벨에서의 단계.. (1 2 3 될 때 보상, 4 되면 레벨 업)
|
||||
POINT_STAT, // 26 능력치 올릴 수 있는 개수
|
||||
POINT_SUB_SKILL, // 27 보조 스킬 포인트
|
||||
POINT_SKILL, // 28 액티브 스킬 포인트
|
||||
POINT_WEAPON_MIN, // 29 무기 최소 데미지
|
||||
POINT_WEAPON_MAX, // 30 무기 최대 데미지
|
||||
POINT_PLAYTIME, // 31 플레이시간
|
||||
POINT_HP_REGEN, // 32 HP 회복률
|
||||
POINT_SP_REGEN, // 33 SP 회복률
|
||||
POINT_ATT_SPEED, // 17 공격속도
|
||||
POINT_ATT_GRADE, // 18 공격력 MAX
|
||||
POINT_MOV_SPEED, // 19 이동속도
|
||||
POINT_CLIENT_DEF_GRADE, // 20 방어등급
|
||||
POINT_CASTING_SPEED, // 21 주문속도 (쿨다운타임*100) / (100 + 이값) = 최종 쿨다운 타임
|
||||
POINT_MAGIC_ATT_GRADE, // 22 마법공격력
|
||||
POINT_MAGIC_DEF_GRADE, // 23 마법방어력
|
||||
POINT_EMPIRE_POINT, // 24 제국점수
|
||||
POINT_LEVEL_STEP, // 25 한 레벨에서의 단계.. (1 2 3 될 때 보상, 4 되면 레벨 업)
|
||||
POINT_STAT, // 26 능력치 올릴 수 있는 개수
|
||||
POINT_SUB_SKILL, // 27 보조 스킬 포인트
|
||||
POINT_SKILL, // 28 액티브 스킬 포인트
|
||||
POINT_WEAPON_MIN, // 29 무기 최소 데미지
|
||||
POINT_WEAPON_MAX, // 30 무기 최대 데미지
|
||||
POINT_PLAYTIME, // 31 플레이시간
|
||||
POINT_HP_REGEN, // 32 HP 회복률
|
||||
POINT_SP_REGEN, // 33 SP 회복률
|
||||
|
||||
POINT_BOW_DISTANCE, // 34 활 사정거리 증가치 (meter)
|
||||
POINT_BOW_DISTANCE, // 34 활 사정거리 증가치 (meter)
|
||||
|
||||
POINT_HP_RECOVERY, // 35 체력 회복 증가량
|
||||
POINT_SP_RECOVERY, // 36 정신력 회복 증가량
|
||||
POINT_HP_RECOVERY, // 35 체력 회복 증가량
|
||||
POINT_SP_RECOVERY, // 36 정신력 회복 증가량
|
||||
|
||||
POINT_POISON_PCT, // 37 독 확률
|
||||
POINT_STUN_PCT, // 38 기절 확률
|
||||
POINT_SLOW_PCT, // 39 슬로우 확률
|
||||
POINT_CRITICAL_PCT, // 40 크리티컬 확률
|
||||
POINT_PENETRATE_PCT, // 41 관통타격 확률
|
||||
POINT_CURSE_PCT, // 42 저주 확률
|
||||
POINT_POISON_PCT, // 37 독 확률
|
||||
POINT_STUN_PCT, // 38 기절 확률
|
||||
POINT_SLOW_PCT, // 39 슬로우 확률
|
||||
POINT_CRITICAL_PCT, // 40 크리티컬 확률
|
||||
POINT_PENETRATE_PCT, // 41 관통타격 확률
|
||||
POINT_CURSE_PCT, // 42 저주 확률
|
||||
|
||||
POINT_ATTBONUS_HUMAN, // 43 인간에게 강함
|
||||
POINT_ATTBONUS_ANIMAL, // 44 동물에게 데미지 % 증가
|
||||
POINT_ATTBONUS_ORC, // 45 웅귀에게 데미지 % 증가
|
||||
POINT_ATTBONUS_MILGYO, // 46 밀교에게 데미지 % 증가
|
||||
POINT_ATTBONUS_UNDEAD, // 47 시체에게 데미지 % 증가
|
||||
POINT_ATTBONUS_DEVIL, // 48 마귀(악마)에게 데미지 % 증가
|
||||
POINT_ATTBONUS_INSECT, // 49 벌레족
|
||||
POINT_ATTBONUS_FIRE, // 50 화염족
|
||||
POINT_ATTBONUS_ICE, // 51 빙설족
|
||||
POINT_ATTBONUS_DESERT, // 52 사막족
|
||||
POINT_ATTBONUS_MONSTER, // 53 모든 몬스터에게 강함
|
||||
POINT_ATTBONUS_WARRIOR, // 54 무사에게 강함
|
||||
POINT_ATTBONUS_ASSASSIN, // 55 자객에게 강함
|
||||
POINT_ATTBONUS_SURA, // 56 수라에게 강함
|
||||
POINT_ATTBONUS_SHAMAN, // 57 무당에게 강함
|
||||
POINT_ATTBONUS_TREE, // 58 나무에게 강함 20050729.myevan UNUSED5
|
||||
POINT_ATTBONUS_HUMAN, // 43 인간에게 강함
|
||||
POINT_ATTBONUS_ANIMAL, // 44 동물에게 데미지 % 증가
|
||||
POINT_ATTBONUS_ORC, // 45 웅귀에게 데미지 % 증가
|
||||
POINT_ATTBONUS_MILGYO, // 46 밀교에게 데미지 % 증가
|
||||
POINT_ATTBONUS_UNDEAD, // 47 시체에게 데미지 % 증가
|
||||
POINT_ATTBONUS_DEVIL, // 48 마귀(악마)에게 데미지 % 증가
|
||||
POINT_ATTBONUS_INSECT, // 49 벌레족
|
||||
POINT_ATTBONUS_FIRE, // 50 화염족
|
||||
POINT_ATTBONUS_ICE, // 51 빙설족
|
||||
POINT_ATTBONUS_DESERT, // 52 사막족
|
||||
POINT_ATTBONUS_MONSTER, // 53 모든 몬스터에게 강함
|
||||
POINT_ATTBONUS_WARRIOR, // 54 무사에게 강함
|
||||
POINT_ATTBONUS_ASSASSIN, // 55 자객에게 강함
|
||||
POINT_ATTBONUS_SURA, // 56 수라에게 강함
|
||||
POINT_ATTBONUS_SHAMAN, // 57 무당에게 강함
|
||||
POINT_ATTBONUS_TREE, // 58 나무에게 강함 20050729.myevan UNUSED5
|
||||
|
||||
POINT_RESIST_WARRIOR, // 59 무사에게 저항
|
||||
POINT_RESIST_ASSASSIN, // 60 자객에게 저항
|
||||
POINT_RESIST_SURA, // 61 수라에게 저항
|
||||
POINT_RESIST_SHAMAN, // 62 무당에게 저항
|
||||
POINT_RESIST_WARRIOR, // 59 무사에게 저항
|
||||
POINT_RESIST_ASSASSIN, // 60 자객에게 저항
|
||||
POINT_RESIST_SURA, // 61 수라에게 저항
|
||||
POINT_RESIST_SHAMAN, // 62 무당에게 저항
|
||||
|
||||
POINT_STEAL_HP, // 63 생명력 흡수
|
||||
POINT_STEAL_SP, // 64 정신력 흡수
|
||||
POINT_STEAL_HP, // 63 생명력 흡수
|
||||
POINT_STEAL_SP, // 64 정신력 흡수
|
||||
|
||||
POINT_MANA_BURN_PCT, // 65 마나 번
|
||||
POINT_MANA_BURN_PCT, // 65 마나 번
|
||||
|
||||
/// 피해시 보너스 ///
|
||||
/// 피해시 보너스 ///
|
||||
|
||||
POINT_DAMAGE_SP_RECOVER, // 66 공격당할 시 정신력 회복 확률
|
||||
POINT_DAMAGE_SP_RECOVER, // 66 공격당할 시 정신력 회복 확률
|
||||
|
||||
POINT_BLOCK, // 67 블럭율
|
||||
POINT_DODGE, // 68 회피율
|
||||
POINT_BLOCK, // 67 블럭율
|
||||
POINT_DODGE, // 68 회피율
|
||||
|
||||
POINT_RESIST_SWORD, // 69
|
||||
POINT_RESIST_TWOHAND, // 70
|
||||
POINT_RESIST_DAGGER, // 71
|
||||
POINT_RESIST_BELL, // 72
|
||||
POINT_RESIST_FAN, // 73
|
||||
POINT_RESIST_BOW, // 74 화살 저항 : 대미지 감소
|
||||
POINT_RESIST_FIRE, // 75 화염 저항 : 화염공격에 대한 대미지 감소
|
||||
POINT_RESIST_ELEC, // 76 전기 저항 : 전기공격에 대한 대미지 감소
|
||||
POINT_RESIST_MAGIC, // 77 술법 저항 : 모든술법에 대한 대미지 감소
|
||||
POINT_RESIST_WIND, // 78 바람 저항 : 바람공격에 대한 대미지 감소
|
||||
POINT_RESIST_BOW, // 74 화살 저항 : 대미지 감소
|
||||
POINT_RESIST_FIRE, // 75 화염 저항 : 화염공격에 대한 대미지 감소
|
||||
POINT_RESIST_ELEC, // 76 전기 저항 : 전기공격에 대한 대미지 감소
|
||||
POINT_RESIST_MAGIC, // 77 술법 저항 : 모든술법에 대한 대미지 감소
|
||||
POINT_RESIST_WIND, // 78 바람 저항 : 바람공격에 대한 대미지 감소
|
||||
|
||||
POINT_REFLECT_MELEE, // 79 공격 반사
|
||||
POINT_REFLECT_MELEE, // 79 공격 반사
|
||||
|
||||
/// 특수 피해시 ///
|
||||
POINT_REFLECT_CURSE, // 80 저주 반사
|
||||
POINT_POISON_REDUCE, // 81 독데미지 감소
|
||||
/// 특수 피해시 ///
|
||||
POINT_REFLECT_CURSE, // 80 저주 반사
|
||||
POINT_POISON_REDUCE, // 81 독데미지 감소
|
||||
|
||||
/// 적 소멸시 ///
|
||||
POINT_KILL_SP_RECOVER, // 82 적 소멸시 MP 회복
|
||||
/// 적 소멸시 ///
|
||||
POINT_KILL_SP_RECOVER, // 82 적 소멸시 MP 회복
|
||||
POINT_EXP_DOUBLE_BONUS, // 83
|
||||
POINT_GOLD_DOUBLE_BONUS, // 84
|
||||
POINT_ITEM_DROP_BONUS, // 85
|
||||
|
||||
/// 회복 관련 ///
|
||||
/// 회복 관련 ///
|
||||
POINT_POTION_BONUS, // 86
|
||||
POINT_KILL_HP_RECOVERY, // 87
|
||||
|
||||
|
@ -225,7 +225,7 @@ enum EPointTypes
|
|||
|
||||
POINT_HIT_HP_RECOVERY, // 100
|
||||
POINT_HIT_SP_RECOVERY, // 101
|
||||
POINT_MANASHIELD, // 102 흑신수호 스킬에 의한 마나쉴드 효과 정도
|
||||
POINT_MANASHIELD, // 102 흑신수호 스킬에 의한 마나쉴드 효과 정도
|
||||
|
||||
POINT_PARTY_BUFFER_BONUS, // 103
|
||||
POINT_PARTY_SKILL_MASTER_BONUS, // 104
|
||||
|
@ -234,58 +234,57 @@ enum EPointTypes
|
|||
POINT_SP_RECOVER_CONTINUE, // 106
|
||||
|
||||
POINT_STEAL_GOLD, // 107
|
||||
POINT_POLYMORPH, // 108 변신한 몬스터 번호
|
||||
POINT_MOUNT, // 109 타고있는 몬스터 번호
|
||||
POINT_POLYMORPH, // 108 변신한 몬스터 번호
|
||||
POINT_MOUNT, // 109 타고있는 몬스터 번호
|
||||
|
||||
POINT_PARTY_HASTE_BONUS, // 110
|
||||
POINT_PARTY_DEFENDER_BONUS, // 111
|
||||
POINT_STAT_RESET_COUNT, // 112 피의 단약 사용을 통한 스텟 리셋 포인트 (1당 1포인트 리셋가능)
|
||||
POINT_STAT_RESET_COUNT, // 112 피의 단약 사용을 통한 스텟 리셋 포인트 (1당 1포인트 리셋가능)
|
||||
|
||||
POINT_HORSE_SKILL, // 113
|
||||
|
||||
POINT_MALL_ATTBONUS, // 114 공격력 +x%
|
||||
POINT_MALL_DEFBONUS, // 115 방어력 +x%
|
||||
POINT_MALL_EXPBONUS, // 116 경험치 +x%
|
||||
POINT_MALL_ITEMBONUS, // 117 아이템 드롭율 x/10배
|
||||
POINT_MALL_GOLDBONUS, // 118 돈 드롭율 x/10배
|
||||
POINT_MALL_ATTBONUS, // 114 공격력 +x%
|
||||
POINT_MALL_DEFBONUS, // 115 방어력 +x%
|
||||
POINT_MALL_EXPBONUS, // 116 경험치 +x%
|
||||
POINT_MALL_ITEMBONUS, // 117 아이템 드롭율 x/10배
|
||||
POINT_MALL_GOLDBONUS, // 118 돈 드롭율 x/10배
|
||||
|
||||
POINT_MAX_HP_PCT, // 119 최대생명력 +x%
|
||||
POINT_MAX_SP_PCT, // 120 최대정신력 +x%
|
||||
POINT_MAX_HP_PCT, // 119 최대생명력 +x%
|
||||
POINT_MAX_SP_PCT, // 120 최대정신력 +x%
|
||||
|
||||
POINT_SKILL_DAMAGE_BONUS, // 121 스킬 데미지 *(100+x)%
|
||||
POINT_NORMAL_HIT_DAMAGE_BONUS, // 122 평타 데미지 *(100+x)%
|
||||
POINT_SKILL_DAMAGE_BONUS, // 121 스킬 데미지 *(100+x)%
|
||||
POINT_NORMAL_HIT_DAMAGE_BONUS, // 122 평타 데미지 *(100+x)%
|
||||
|
||||
// DEFEND_BONUS_ATTRIBUTES
|
||||
POINT_SKILL_DEFEND_BONUS, // 123 스킬 방어 데미지
|
||||
POINT_NORMAL_HIT_DEFEND_BONUS, // 124 평타 방어 데미지
|
||||
POINT_SKILL_DEFEND_BONUS, // 123 스킬 방어 데미지
|
||||
POINT_NORMAL_HIT_DEFEND_BONUS, // 124 평타 방어 데미지
|
||||
// END_OF_DEFEND_BONUS_ATTRIBUTES
|
||||
|
||||
// TODO: check if the PC_BANG_* bonuses can be safely removed
|
||||
// PC_BANG_ITEM_ADD
|
||||
POINT_PC_BANG_EXP_BONUS, // 125 PC방 전용 경험치 보너스
|
||||
POINT_PC_BANG_DROP_BONUS, // 126 PC방 전용 드롭률 보너스
|
||||
POINT_PC_BANG_EXP_BONUS, // 125 PC방 전용 경험치 보너스
|
||||
POINT_PC_BANG_DROP_BONUS, // 126 PC방 전용 드롭률 보너스
|
||||
// END_PC_BANG_ITEM_ADD
|
||||
POINT_RAMADAN_CANDY_BONUS_EXP, // 라마단 사탕 경험치 증가용
|
||||
|
||||
POINT_RAMADAN_CANDY_BONUS_EXP, // 라마단 사탕 경험치 증가용
|
||||
POINT_ENERGY = 128, // 128 기력
|
||||
|
||||
POINT_ENERGY = 128, // 128 기력
|
||||
|
||||
// 기력 ui 용.
|
||||
// 서버에서 쓰지 않기만, 클라이언트에서 기력의 끝 시간을 POINT로 관리하기 때문에 이렇게 한다.
|
||||
// 아 부끄럽다
|
||||
POINT_ENERGY_END_TIME = 129, // 129 기력 종료 시간
|
||||
// 기력 ui 용.
|
||||
// 서버에서 쓰지 않기만, 클라이언트에서 기력의 끝 시간을 POINT로 관리하기 때문에 이렇게 한다.
|
||||
// 아 부끄럽다
|
||||
POINT_ENERGY_END_TIME = 129, // 129 기력 종료 시간
|
||||
|
||||
POINT_COSTUME_ATTR_BONUS = 130,
|
||||
POINT_MAGIC_ATT_BONUS_PER = 131,
|
||||
POINT_MELEE_MAGIC_ATT_BONUS_PER = 132,
|
||||
|
||||
// 추가 속성 저항
|
||||
POINT_RESIST_ICE = 133, // 냉기 저항 : 얼음공격에 대한 대미지 감소
|
||||
POINT_RESIST_EARTH = 134, // 대지 저항 : 얼음공격에 대한 대미지 감소
|
||||
POINT_RESIST_DARK = 135, // 어둠 저항 : 얼음공격에 대한 대미지 감소
|
||||
// 추가 속성 저항
|
||||
POINT_RESIST_ICE = 133, // 냉기 저항 : 얼음공격에 대한 대미지 감소
|
||||
POINT_RESIST_EARTH = 134, // 대지 저항 : 얼음공격에 대한 대미지 감소
|
||||
POINT_RESIST_DARK = 135, // 어둠 저항 : 얼음공격에 대한 대미지 감소
|
||||
|
||||
POINT_RESIST_CRITICAL = 136, // 크리티컬 저항 : 상대의 크리티컬 확률을 감소
|
||||
POINT_RESIST_PENETRATE = 137, // 관통타격 저항 : 상대의 관통타격 확률을 감소
|
||||
POINT_RESIST_CRITICAL = 136, // 크리티컬 저항 : 상대의 크리티컬 확률을 감소
|
||||
POINT_RESIST_PENETRATE = 137, // 관통타격 저항 : 상대의 관통타격 확률을 감소
|
||||
|
||||
//POINT_MAX_NUM = 129 common/length.h
|
||||
};
|
||||
|
@ -354,7 +353,7 @@ struct DynamicCharacterPtr {
|
|||
uint32_t id;
|
||||
};
|
||||
|
||||
/* 저장하는 데이터 */
|
||||
/* 저장하는 데이터 */
|
||||
typedef struct character_point
|
||||
{
|
||||
int points[POINT_MAX_NUM];
|
||||
|
@ -377,7 +376,7 @@ typedef struct character_point
|
|||
BYTE skill_group;
|
||||
} CHARACTER_POINT;
|
||||
|
||||
/* 저장되지 않는 캐릭터 데이터 */
|
||||
/* 저장되지 않는 캐릭터 데이터 */
|
||||
typedef struct character_point_instant
|
||||
{
|
||||
int points[POINT_MAX_NUM];
|
||||
|
@ -399,7 +398,7 @@ typedef struct character_point_instant
|
|||
LPITEM pItems[INVENTORY_AND_EQUIP_SLOT_MAX];
|
||||
BYTE bItemGrid[INVENTORY_AND_EQUIP_SLOT_MAX];
|
||||
|
||||
// 용혼석 인벤토리.
|
||||
// 용혼석 인벤토리.
|
||||
LPITEM pDSItems[DRAGON_SOUL_INVENTORY_MAX_NUM];
|
||||
WORD wDSItemGrid[DRAGON_SOUL_INVENTORY_MAX_NUM];
|
||||
|
||||
|
@ -411,7 +410,7 @@ typedef struct character_point_instant
|
|||
|
||||
BYTE gm_level;
|
||||
|
||||
BYTE bBasePart; // 평상복 번호
|
||||
BYTE bBasePart; // 평상복 번호
|
||||
|
||||
int iMaxStamina;
|
||||
|
||||
|
@ -509,7 +508,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
{
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Entity 관련
|
||||
// Entity 관련
|
||||
virtual void EncodeInsertPacket(LPENTITY entity);
|
||||
virtual void EncodeRemovePacket(LPENTITY entity);
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -519,7 +518,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
void UpdatePacket();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// FSM (Finite State Machine) 관련
|
||||
// FSM (Finite State Machine) 관련
|
||||
protected:
|
||||
CStateTemplate<CHARACTER> m_stateMove;
|
||||
CStateTemplate<CHARACTER> m_stateBattle;
|
||||
|
@ -589,13 +588,13 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
DWORD GetPlayerID() const { return m_dwPlayerID; }
|
||||
|
||||
void SetPlayerProto(const TPlayerTable * table);
|
||||
void CreatePlayerProto(TPlayerTable & tab); // 저장 시 사용
|
||||
void CreatePlayerProto(TPlayerTable & tab); // 저장 시 사용
|
||||
|
||||
void SetProto(const CMob * c_pkMob);
|
||||
WORD GetRaceNum() const;
|
||||
|
||||
void Save(); // DelayedSave
|
||||
void SaveReal(); // 실제 저장
|
||||
void SaveReal(); // 실제 저장
|
||||
void FlushDelayedSaveItem();
|
||||
|
||||
const char * GetName() const;
|
||||
|
@ -636,7 +635,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
DWORD GetExp() const { return m_points.exp; }
|
||||
void SetExp(DWORD exp) { m_points.exp = exp; }
|
||||
DWORD GetNextExp() const;
|
||||
LPCHARACTER DistributeExp(); // 제일 많이 때린 사람을 리턴한다.
|
||||
LPCHARACTER DistributeExp(); // 제일 많이 때린 사람을 리턴한다.
|
||||
void DistributeHP(LPCHARACTER pkKiller);
|
||||
void DistributeSP(LPCHARACTER pkKiller, int iMethod=0);
|
||||
|
||||
|
@ -719,14 +718,14 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
DWORD GetPolymorphItemVnum() const;
|
||||
DWORD GetMonsterDrainSPPoint() const;
|
||||
|
||||
void MainCharacterPacket(); // 내가 메인캐릭터라고 보내준다.
|
||||
void MainCharacterPacket(); // 내가 메인캐릭터라고 보내준다.
|
||||
|
||||
void ComputePoints();
|
||||
void ComputeBattlePoints();
|
||||
void PointChange(BYTE type, int amount, bool bAmount = false, bool bBroadcast = false);
|
||||
void PointsPacket();
|
||||
void ApplyPoint(BYTE bApplyType, int iVal);
|
||||
void CheckMaximumPoints(); // HP, SP 등의 현재 값이 최대값 보다 높은지 검사하고 높다면 낮춘다.
|
||||
void CheckMaximumPoints(); // HP, SP 등의 현재 값이 최대값 보다 높은지 검사하고 높다면 낮춘다.
|
||||
|
||||
bool Show(int lMapIndex, int x, int y, int z = INT_MAX, bool bShowSpawnMotion = false);
|
||||
|
||||
|
@ -750,7 +749,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
bool IsBlockMode(BYTE bFlag) const { return (m_pointsInstant.bBlockMode & bFlag)?true:false; }
|
||||
|
||||
bool IsPolymorphed() const { return m_dwPolymorphRace>0; }
|
||||
bool IsPolyMaintainStat() const { return m_bPolyMaintainStat; } // 이전 스텟을 유지하는 폴리모프.
|
||||
bool IsPolyMaintainStat() const { return m_bPolyMaintainStat; } // 이전 스텟을 유지하는 폴리모프.
|
||||
void SetPolymorph(DWORD dwRaceNum, bool bMaintainStat = false);
|
||||
DWORD GetPolymorphVnum() const { return m_dwPolymorphRace; }
|
||||
int GetPolymorphPower() const;
|
||||
|
@ -805,15 +804,15 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
void SetNowWalking(bool bWalkFlag);
|
||||
void ResetWalking() { SetNowWalking(m_bWalking); }
|
||||
|
||||
bool Goto(int x, int y); // 바로 이동 시키지 않고 목표 위치로 BLENDING 시킨다.
|
||||
bool Goto(int x, int y); // 바로 이동 시키지 않고 목표 위치로 BLENDING 시킨다.
|
||||
void Stop();
|
||||
|
||||
bool CanMove() const; // 이동할 수 있는가?
|
||||
bool CanMove() const; // 이동할 수 있는가?
|
||||
|
||||
void SyncPacket();
|
||||
bool Sync(int x, int y); // 실제 이 메소드로 이동 한다 (각 종 조건에 의한 이동 불가가 없음)
|
||||
bool Move(int x, int y); // 조건을 검사하고 Sync 메소드를 통해 이동 한다.
|
||||
void OnMove(bool bIsAttack = false); // 움직일때 불린다. Move() 메소드 이외에서도 불릴 수 있다.
|
||||
bool Sync(int x, int y); // 실제 이 메소드로 이동 한다 (각 종 조건에 의한 이동 불가가 없음)
|
||||
bool Move(int x, int y); // 조건을 검사하고 Sync 메소드를 통해 이동 한다.
|
||||
void OnMove(bool bIsAttack = false); // 움직일때 불린다. Move() 메소드 이외에서도 불릴 수 있다.
|
||||
DWORD GetMotionMode() const;
|
||||
float GetMoveMotionSpeed() const;
|
||||
float GetMoveSpeed() const;
|
||||
|
@ -824,7 +823,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
DWORD GetLastMoveTime() const { return m_dwLastMoveTime; }
|
||||
DWORD GetLastAttackTime() const { return m_dwLastAttackTime; }
|
||||
|
||||
void SetLastAttacked(DWORD time); // 마지막으로 공격받은 시간 및 위치를 저장함
|
||||
void SetLastAttacked(DWORD time); // 마지막으로 공격받은 시간 및 위치를 저장함
|
||||
|
||||
bool SetSyncOwner(LPCHARACTER ch, bool bRemoveFromList = true);
|
||||
bool IsSyncOwner(LPCHARACTER ch) const;
|
||||
|
@ -851,7 +850,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
|
||||
float m_fSyncTime;
|
||||
LPCHARACTER m_pkChrSyncOwner;
|
||||
CHARACTER_LIST m_kLst_pkChrSyncOwned; // 내가 SyncOwner인 자들
|
||||
CHARACTER_LIST m_kLst_pkChrSyncOwned; // 내가 SyncOwner인 자들
|
||||
|
||||
PIXEL_POSITION m_posDest;
|
||||
PIXEL_POSITION m_posStart;
|
||||
|
@ -874,7 +873,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
bool m_bStaminaConsume;
|
||||
// End
|
||||
|
||||
// Quickslot 관련
|
||||
// Quickslot 관련
|
||||
public:
|
||||
void SyncQuickslot(BYTE bType, BYTE bOldPos, BYTE bNewPos);
|
||||
bool GetQuickslot(BYTE pos, TQuickslot ** ppSlot);
|
||||
|
@ -903,7 +902,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
void LoadAffect(DWORD dwCount, TPacketAffectElement * pElements);
|
||||
void SaveAffect();
|
||||
|
||||
// Affect loading이 끝난 상태인가?
|
||||
// Affect loading이 끝난 상태인가?
|
||||
bool IsLoadedAffect() const { return m_bIsLoadedAffect; }
|
||||
|
||||
bool IsGoodAffect(BYTE bAffectType) const;
|
||||
|
@ -929,25 +928,25 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
void DenyToParty(LPCHARACTER member);
|
||||
void AcceptToParty(LPCHARACTER member);
|
||||
|
||||
/// 자신의 파티에 다른 character 를 초대한다.
|
||||
/// 자신의 파티에 다른 character 를 초대한다.
|
||||
/**
|
||||
* @param pchInvitee 초대할 대상 character. 파티에 참여 가능한 상태이어야 한다.
|
||||
* @param pchInvitee 초대할 대상 character. 파티에 참여 가능한 상태이어야 한다.
|
||||
*
|
||||
* 양측 character 의 상태가 파티에 초대하고 초대받을 수 있는 상태가 아니라면 초대하는 캐릭터에게 해당하는 채팅 메세지를 전송한다.
|
||||
* 양측 character 의 상태가 파티에 초대하고 초대받을 수 있는 상태가 아니라면 초대하는 캐릭터에게 해당하는 채팅 메세지를 전송한다.
|
||||
*/
|
||||
void PartyInvite(LPCHARACTER pchInvitee);
|
||||
|
||||
/// 초대했던 character 의 수락을 처리한다.
|
||||
/// 초대했던 character 의 수락을 처리한다.
|
||||
/**
|
||||
* @param pchInvitee 파티에 참여할 character. 파티에 참여가능한 상태이어야 한다.
|
||||
* @param pchInvitee 파티에 참여할 character. 파티에 참여가능한 상태이어야 한다.
|
||||
*
|
||||
* pchInvitee 가 파티에 가입할 수 있는 상황이 아니라면 해당하는 채팅 메세지를 전송한다.
|
||||
* pchInvitee 가 파티에 가입할 수 있는 상황이 아니라면 해당하는 채팅 메세지를 전송한다.
|
||||
*/
|
||||
void PartyInviteAccept(LPCHARACTER pchInvitee);
|
||||
|
||||
/// 초대했던 character 의 초대 거부를 처리한다.
|
||||
/// 초대했던 character 의 초대 거부를 처리한다.
|
||||
/**
|
||||
* @param [in] dwPID 초대 했던 character 의 PID
|
||||
* @param [in] dwPID 초대 했던 character 의 PID
|
||||
*/
|
||||
void PartyInviteDeny(DWORD dwPID);
|
||||
|
||||
|
@ -960,45 +959,45 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
|
||||
protected:
|
||||
|
||||
/// 파티에 가입한다.
|
||||
/// 파티에 가입한다.
|
||||
/**
|
||||
* @param pkLeader 가입할 파티의 리더
|
||||
* @param pkLeader 가입할 파티의 리더
|
||||
*/
|
||||
void PartyJoin(LPCHARACTER pkLeader);
|
||||
|
||||
/**
|
||||
* 파티 가입을 할 수 없을 경우의 에러코드.
|
||||
* Error code 는 시간에 의존적인가에 따라 변경가능한(mutable) type 과 정적(static) type 으로 나뉜다.
|
||||
* Error code 의 값이 PERR_SEPARATOR 보다 낮으면 변경가능한 type 이고 높으면 정적 type 이다.
|
||||
* 파티 가입을 할 수 없을 경우의 에러코드.
|
||||
* Error code 는 시간에 의존적인가에 따라 변경가능한(mutable) type 과 정적(static) type 으로 나뉜다.
|
||||
* Error code 의 값이 PERR_SEPARATOR 보다 낮으면 변경가능한 type 이고 높으면 정적 type 이다.
|
||||
*/
|
||||
enum PartyJoinErrCode {
|
||||
PERR_NONE = 0, ///< 처리성공
|
||||
PERR_SERVER, ///< 서버문제로 파티관련 처리 불가
|
||||
PERR_DUNGEON, ///< 캐릭터가 던전에 있음
|
||||
PERR_OBSERVER, ///< 관전모드임
|
||||
PERR_LVBOUNDARY, ///< 상대 캐릭터와 레벨차이가 남
|
||||
PERR_LOWLEVEL, ///< 상대파티의 최고레벨보다 30레벨 낮음
|
||||
PERR_HILEVEL, ///< 상대파티의 최저레벨보다 30레벨 높음
|
||||
PERR_ALREADYJOIN, ///< 파티가입 대상 캐릭터가 이미 파티중
|
||||
PERR_PARTYISFULL, ///< 파티인원 제한 초과
|
||||
PERR_NONE = 0, ///< 처리성공
|
||||
PERR_SERVER, ///< 서버문제로 파티관련 처리 불가
|
||||
PERR_DUNGEON, ///< 캐릭터가 던전에 있음
|
||||
PERR_OBSERVER, ///< 관전모드임
|
||||
PERR_LVBOUNDARY, ///< 상대 캐릭터와 레벨차이가 남
|
||||
PERR_LOWLEVEL, ///< 상대파티의 최고레벨보다 30레벨 낮음
|
||||
PERR_HILEVEL, ///< 상대파티의 최저레벨보다 30레벨 높음
|
||||
PERR_ALREADYJOIN, ///< 파티가입 대상 캐릭터가 이미 파티중
|
||||
PERR_PARTYISFULL, ///< 파티인원 제한 초과
|
||||
PERR_SEPARATOR, ///< Error type separator.
|
||||
PERR_DIFFEMPIRE, ///< 상대 캐릭터와 다른 제국임
|
||||
PERR_MAX ///< Error code 최고치. 이 앞에 Error code 를 추가한다.
|
||||
PERR_DIFFEMPIRE, ///< 상대 캐릭터와 다른 제국임
|
||||
PERR_MAX ///< Error code 최고치. 이 앞에 Error code 를 추가한다.
|
||||
};
|
||||
|
||||
/// 파티 가입이나 결성 가능한 조건을 검사한다.
|
||||
/// 파티 가입이나 결성 가능한 조건을 검사한다.
|
||||
/**
|
||||
* @param pchLeader 파티의 leader 이거나 초대한 character
|
||||
* @param pchGuest 초대받는 character
|
||||
* @return 모든 PartyJoinErrCode 가 반환될 수 있다.
|
||||
* @param pchLeader 파티의 leader 이거나 초대한 character
|
||||
* @param pchGuest 초대받는 character
|
||||
* @return 모든 PartyJoinErrCode 가 반환될 수 있다.
|
||||
*/
|
||||
static PartyJoinErrCode IsPartyJoinableCondition(const LPCHARACTER pchLeader, const LPCHARACTER pchGuest);
|
||||
|
||||
/// 파티 가입이나 결성 가능한 동적인 조건을 검사한다.
|
||||
/// 파티 가입이나 결성 가능한 동적인 조건을 검사한다.
|
||||
/**
|
||||
* @param pchLeader 파티의 leader 이거나 초대한 character
|
||||
* @param pchGuest 초대받는 character
|
||||
* @return mutable type 의 code 만 반환한다.
|
||||
* @param pchLeader 파티의 leader 이거나 초대한 character
|
||||
* @param pchGuest 초대받는 character
|
||||
* @return mutable type 의 code 만 반환한다.
|
||||
*/
|
||||
static PartyJoinErrCode IsPartyJoinableMutableCondition(const LPCHARACTER pchLeader, const LPCHARACTER pchGuest);
|
||||
|
||||
|
@ -1007,11 +1006,11 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
LPEVENT m_pkPartyRequestEvent;
|
||||
|
||||
/**
|
||||
* 파티초청 Event map.
|
||||
* key: 초대받은 캐릭터의 PID
|
||||
* value: event의 pointer
|
||||
* 파티초청 Event map.
|
||||
* key: 초대받은 캐릭터의 PID
|
||||
* value: event의 pointer
|
||||
*
|
||||
* 초대한 캐릭터들에 대한 event map.
|
||||
* 초대한 캐릭터들에 대한 event map.
|
||||
*/
|
||||
typedef std::map< DWORD, LPEVENT > EventMap;
|
||||
EventMap m_PartyInviteEventMap;
|
||||
|
@ -1045,7 +1044,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Item related
|
||||
public:
|
||||
bool CanHandleItem(bool bSkipRefineCheck = false, bool bSkipObserver = false); // 아이템 관련 행위를 할 수 있는가?
|
||||
bool CanHandleItem(bool bSkipRefineCheck = false, bool bSkipObserver = false); // 아이템 관련 행위를 할 수 있는가?
|
||||
|
||||
bool IsItemLoaded() const { return m_bItemLoaded; }
|
||||
void SetItemLoaded() { m_bItemLoaded = true; }
|
||||
|
@ -1060,14 +1059,14 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
LPITEM GetWear(BYTE bCell) const;
|
||||
|
||||
// MYSHOP_PRICE_LIST
|
||||
void UseSilkBotary(void); /// 비단 보따리 아이템의 사용
|
||||
void UseSilkBotary(void); /// 비단 보따리 아이템의 사용
|
||||
|
||||
/// DB 캐시로 부터 받아온 가격정보 리스트를 유저에게 전송하고 보따리 아이템 사용을 처리한다.
|
||||
/// DB 캐시로 부터 받아온 가격정보 리스트를 유저에게 전송하고 보따리 아이템 사용을 처리한다.
|
||||
/**
|
||||
* @param [in] p 가격정보 리스트 패킷
|
||||
* @param [in] p 가격정보 리스트 패킷
|
||||
*
|
||||
* 접속한 후 처음 비단 보따리 아이템 사용 시 UseSilkBotary 에서 DB 캐시로 가격정보 리스트를 요청하고
|
||||
* 응답받은 시점에 이 함수에서 실제 비단보따리 사용을 처리한다.
|
||||
* 접속한 후 처음 비단 보따리 아이템 사용 시 UseSilkBotary 에서 DB 캐시로 가격정보 리스트를 요청하고
|
||||
* 응답받은 시점에 이 함수에서 실제 비단보따리 사용을 처리한다.
|
||||
*/
|
||||
void UseSilkBotaryReal(const TPacketMyshopPricelistHeader* p);
|
||||
// END_OF_MYSHOP_PRICE_LIST
|
||||
|
@ -1113,10 +1112,10 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
bool EquipItem(LPITEM item, int iCandidateCell = -1);
|
||||
bool UnequipItem(LPITEM item);
|
||||
|
||||
// 현재 item을 착용할 수 있는 지 확인하고, 불가능 하다면 캐릭터에게 이유를 알려주는 함수
|
||||
// 현재 item을 착용할 수 있는 지 확인하고, 불가능 하다면 캐릭터에게 이유를 알려주는 함수
|
||||
bool CanEquipNow(const LPITEM item, const TItemPos& srcCell = NPOS, const TItemPos& destCell = NPOS);
|
||||
|
||||
// 착용중인 item을 벗을 수 있는 지 확인하고, 불가능 하다면 캐릭터에게 이유를 알려주는 함수
|
||||
// 착용중인 item을 벗을 수 있는 지 확인하고, 불가능 하다면 캐릭터에게 이유를 알려주는 함수
|
||||
bool CanUnequipNow(const LPITEM item, const TItemPos& srcCell = NPOS, const TItemPos& destCell = NPOS);
|
||||
|
||||
bool SwapItem(BYTE bCell, BYTE bDestCell);
|
||||
|
@ -1148,14 +1147,14 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
|
||||
protected:
|
||||
|
||||
/// 한 아이템에 대한 가격정보를 전송한다.
|
||||
/// 한 아이템에 대한 가격정보를 전송한다.
|
||||
/**
|
||||
* @param [in] dwItemVnum 아이템 vnum
|
||||
* @param [in] dwItemPrice 아이템 가격
|
||||
* @param [in] dwItemVnum 아이템 vnum
|
||||
* @param [in] dwItemPrice 아이템 가격
|
||||
*/
|
||||
void SendMyShopPriceListCmd(DWORD dwItemVnum, DWORD dwItemPrice);
|
||||
|
||||
bool m_bNoOpenedShop; ///< 이번 접속 후 개인상점을 연 적이 있는지의 여부(열었던 적이 없다면 true)
|
||||
bool m_bNoOpenedShop; ///< 이번 접속 후 개인상점을 연 적이 있는지의 여부(열었던 적이 없다면 true)
|
||||
|
||||
bool m_bItemLoaded;
|
||||
int m_iRefineAdditionalCell;
|
||||
|
@ -1169,7 +1168,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
void SetGold(INT gold) { m_points.gold = gold; }
|
||||
bool DropGold(INT gold);
|
||||
INT GetAllowedGold() const;
|
||||
void GiveGold(INT iAmount); // 파티가 있으면 파티 분배, 로그 등의 처리
|
||||
void GiveGold(INT iAmount); // 파티가 있으면 파티 분배, 로그 등의 처리
|
||||
// End of Money
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1235,9 +1234,9 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
bool CanFight() const;
|
||||
|
||||
bool CanBeginFight() const;
|
||||
void BeginFight(LPCHARACTER pkVictim); // pkVictimr과 싸우기 시작한다. (강제적임, 시작할 수 있나 체크하려면 CanBeginFight을 사용)
|
||||
void BeginFight(LPCHARACTER pkVictim); // pkVictimr과 싸우기 시작한다. (강제적임, 시작할 수 있나 체크하려면 CanBeginFight을 사용)
|
||||
|
||||
bool CounterAttack(LPCHARACTER pkChr); // 반격하기 (몬스터만 사용)
|
||||
bool CounterAttack(LPCHARACTER pkChr); // 반격하기 (몬스터만 사용)
|
||||
|
||||
bool IsStun() const;
|
||||
void Stun();
|
||||
|
@ -1267,7 +1266,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
void UpdateAlignment(int iAmount);
|
||||
int GetAlignment() const;
|
||||
|
||||
//선악치 얻기
|
||||
//선악치 얻기
|
||||
int GetRealAlignment() const;
|
||||
void ShowAlignment(bool bShow);
|
||||
|
||||
|
@ -1316,7 +1315,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
|
||||
DWORD m_dwFlyTargetID;
|
||||
std::vector<DWORD> m_vec_dwFlyTargets;
|
||||
TDamageMap m_map_kDamage; // 어떤 캐릭터가 나에게 얼마만큼의 데미지를 주었는가?
|
||||
TDamageMap m_map_kDamage; // 어떤 캐릭터가 나에게 얼마만큼의 데미지를 주었는가?
|
||||
// AttackLog m_kAttackLog;
|
||||
DWORD m_dwKillerPID;
|
||||
|
||||
|
@ -1339,8 +1338,8 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
BYTE GetDropMetinStonePct() const { return m_bDropMetinStonePct; }
|
||||
|
||||
protected:
|
||||
LPCHARACTER m_pkChrStone; // 나를 스폰한 돌
|
||||
CHARACTER_SET m_set_pkChrSpawnedBy; // 내가 스폰한 놈들
|
||||
LPCHARACTER m_pkChrStone; // 나를 스폰한 돌
|
||||
CHARACTER_SET m_set_pkChrSpawnedBy; // 내가 스폰한 놈들
|
||||
DWORD m_dwDropMetinStone;
|
||||
BYTE m_bDropMetinStonePct;
|
||||
// End of Stone
|
||||
|
@ -1398,7 +1397,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
|
||||
private:
|
||||
bool m_bDisableCooltime;
|
||||
DWORD m_dwLastSkillTime; ///< 마지막으로 skill 을 쓴 시간(millisecond).
|
||||
DWORD m_dwLastSkillTime; ///< 마지막으로 skill 을 쓴 시간(millisecond).
|
||||
// End of Skill
|
||||
|
||||
// MOB_SKILL
|
||||
|
@ -1455,10 +1454,10 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
// AI related
|
||||
public:
|
||||
void AssignTriggers(const TMobTable * table);
|
||||
LPCHARACTER GetVictim() const; // 공격할 대상 리턴
|
||||
LPCHARACTER GetVictim() const; // 공격할 대상 리턴
|
||||
void SetVictim(LPCHARACTER pkVictim);
|
||||
LPCHARACTER GetNearestVictim(LPCHARACTER pkChr);
|
||||
LPCHARACTER GetProtege() const; // 보호해야 할 대상 리턴
|
||||
LPCHARACTER GetProtege() const; // 보호해야 할 대상 리턴
|
||||
|
||||
bool Follow(LPCHARACTER pkChr, float fMinimumDistance = 150.0f);
|
||||
bool Return();
|
||||
|
@ -1482,8 +1481,8 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Target
|
||||
protected:
|
||||
LPCHARACTER m_pkChrTarget; // 내 타겟
|
||||
CHARACTER_SET m_set_pkChrTargetedBy; // 나를 타겟으로 가지고 있는 사람들
|
||||
LPCHARACTER m_pkChrTarget; // 내 타겟
|
||||
CHARACTER_SET m_set_pkChrTargetedBy; // 나를 타겟으로 가지고 있는 사람들
|
||||
|
||||
public:
|
||||
void SetTarget(LPCHARACTER pkChrTarget);
|
||||
|
@ -1504,19 +1503,19 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
void ChangeSafeboxSize(BYTE bSize);
|
||||
void CloseSafebox();
|
||||
|
||||
/// 창고 열기 요청
|
||||
/// 창고 열기 요청
|
||||
/**
|
||||
* @param [in] pszPassword 1자 이상 6자 이하의 창고 비밀번호
|
||||
* @param [in] pszPassword 1자 이상 6자 이하의 창고 비밀번호
|
||||
*
|
||||
* DB 에 창고열기를 요청한다.
|
||||
* 창고는 중복으로 열지 못하며, 최근 창고를 닫은 시간으로 부터 10초 이내에는 열 지 못한다.
|
||||
* DB 에 창고열기를 요청한다.
|
||||
* 창고는 중복으로 열지 못하며, 최근 창고를 닫은 시간으로 부터 10초 이내에는 열 지 못한다.
|
||||
*/
|
||||
void ReqSafeboxLoad(const char* pszPassword);
|
||||
|
||||
/// 창고 열기 요청의 취소
|
||||
/// 창고 열기 요청의 취소
|
||||
/**
|
||||
* ReqSafeboxLoad 를 호출하고 CloseSafebox 하지 않았을 때 이 함수를 호출하면 창고를 열 수 있다.
|
||||
* 창고열기의 요청이 DB 서버에서 실패응답을 받았을 경우 이 함수를 사용해서 요청을 할 수 있게 해준다.
|
||||
* ReqSafeboxLoad 를 호출하고 CloseSafebox 하지 않았을 때 이 함수를 호출하면 창고를 열 수 있다.
|
||||
* 창고열기의 요청이 DB 서버에서 실패응답을 받았을 경우 이 함수를 사용해서 요청을 할 수 있게 해준다.
|
||||
*/
|
||||
void CancelSafeboxLoad( void ) { m_bOpeningSafebox = false; }
|
||||
|
||||
|
@ -1534,7 +1533,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
CSafebox * m_pkSafebox;
|
||||
int m_iSafeboxSize;
|
||||
int m_iSafeboxLoadTime;
|
||||
bool m_bOpeningSafebox; ///< 창고가 열기 요청 중이거나 열려있는가 여부, true 일 경우 열기요청이거나 열려있음.
|
||||
bool m_bOpeningSafebox; ///< 창고가 열기 요청 중이거나 열려있는가 여부, true 일 경우 열기요청이거나 열려있음.
|
||||
|
||||
CSafebox * m_pkMall;
|
||||
int m_iMallLoadTime;
|
||||
|
@ -1568,7 +1567,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
|
||||
void HorseSummon(bool bSummon, bool bFromFar = false, DWORD dwVnum = 0, const char* name = 0);
|
||||
|
||||
LPCHARACTER GetHorse() const { return m_chHorse; } // 현재 소환중인 말
|
||||
LPCHARACTER GetHorse() const { return m_chHorse; } // 현재 소환중인 말
|
||||
LPCHARACTER GetRider() const; // rider on horse
|
||||
void SetRider(LPCHARACTER ch);
|
||||
|
||||
|
@ -1630,7 +1629,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Resists & Proofs
|
||||
public:
|
||||
bool CannotMoveByAffect() const; // 특정 효과에 의해 움직일 수 없는 상태인가?
|
||||
bool CannotMoveByAffect() const; // 특정 효과에 의해 움직일 수 없는 상태인가?
|
||||
bool IsImmune(DWORD dwImmuneFlag);
|
||||
void SetImmuneFlag(DWORD dw) { m_pointsInstant.dwImmuneFlag = dw; }
|
||||
|
||||
|
@ -1670,7 +1669,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
void UpdateStateMachine(DWORD dwPulse);
|
||||
void SetNextStatePulse(int iPulseNext);
|
||||
|
||||
// 캐릭터 인스턴스 업데이트 함수. 기존엔 이상한 상속구조로 CFSM::Update 함수를 호출하거나 UpdateStateMachine 함수를 사용했는데, 별개의 업데이트 함수 추가함.
|
||||
// 캐릭터 인스턴스 업데이트 함수. 기존엔 이상한 상속구조로 CFSM::Update 함수를 호출하거나 UpdateStateMachine 함수를 사용했는데, 별개의 업데이트 함수 추가함.
|
||||
void UpdateCharacter(DWORD dwPulse);
|
||||
|
||||
protected:
|
||||
|
@ -1740,9 +1739,9 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
int m_aiPremiumTimes[PREMIUM_MAX_NUM];
|
||||
|
||||
// CHANGE_ITEM_ATTRIBUTES
|
||||
static const DWORD msc_dwDefaultChangeItemAttrCycle; ///< 디폴트 아이템 속성변경 가능 주기
|
||||
static const char msc_szLastChangeItemAttrFlag[]; ///< 최근 아이템 속성을 변경한 시간의 Quest Flag 이름
|
||||
static const char msc_szChangeItemAttrCycleFlag[]; ///< 아이템 속성병경 가능 주기의 Quest Flag 이름
|
||||
static const DWORD msc_dwDefaultChangeItemAttrCycle; ///< 디폴트 아이템 속성변경 가능 주기
|
||||
static const char msc_szLastChangeItemAttrFlag[]; ///< 최근 아이템 속성을 변경한 시간의 Quest Flag 이름
|
||||
static const char msc_szChangeItemAttrCycleFlag[]; ///< 아이템 속성병경 가능 주기의 Quest Flag 이름
|
||||
// END_OF_CHANGE_ITEM_ATTRIBUTES
|
||||
|
||||
// NEW_HAIR_STYLE_ADD
|
||||
|
@ -1814,7 +1813,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
int GetMyShopTime() const { return m_iMyShopTime; }
|
||||
void SetMyShopTime() { m_iMyShopTime = thecore_pulse(); }
|
||||
|
||||
// Hack 방지를 위한 체크.
|
||||
// Hack 방지를 위한 체크.
|
||||
bool IsHack(bool bSendMsg = true, bool bCheckShopOwner = true, int limittime = g_nPortalLimitTime);
|
||||
|
||||
// MONARCH
|
||||
|
@ -1864,9 +1863,9 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
bool IsSiegeNPC() const;
|
||||
|
||||
private:
|
||||
//중국 전용
|
||||
//18세 미만 전용
|
||||
//3시간 : 50 % 5 시간 0%
|
||||
//중국 전용
|
||||
//18세 미만 전용
|
||||
//3시간 : 50 % 5 시간 0%
|
||||
e_overtime m_eOverTime;
|
||||
|
||||
public:
|
||||
|
@ -1942,7 +1941,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
|
||||
typedef std::map <BYTE, CBuffOnAttributes*> TMapBuffOnAttrs;
|
||||
TMapBuffOnAttrs m_map_buff_on_attrs;
|
||||
// 무적 : 원활한 테스트를 위하여.
|
||||
// 무적 : 원활한 테스트를 위하여.
|
||||
public:
|
||||
void SetArmada() { cannot_dead = true; }
|
||||
void ResetArmada() { cannot_dead = false; }
|
||||
|
@ -1957,7 +1956,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
bool IsPet() { return m_bIsPet; }
|
||||
#endif
|
||||
|
||||
//최종 데미지 보정.
|
||||
//최종 데미지 보정.
|
||||
private:
|
||||
float m_fAttMul;
|
||||
float m_fDamMul;
|
||||
|
@ -1970,7 +1969,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
private:
|
||||
bool IsValidItemPosition(TItemPos Pos) const;
|
||||
|
||||
//독일 선물 기능 패킷 임시 저장
|
||||
//독일 선물 기능 패킷 임시 저장
|
||||
private:
|
||||
unsigned int itemAward_vnum = 0;
|
||||
char itemAward_cmd[20] = "";
|
||||
|
@ -1984,10 +1983,10 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
//void SetItemAward_flag(bool flag) { itemAward_flag = flag; }
|
||||
|
||||
public:
|
||||
//용혼석
|
||||
//용혼석
|
||||
|
||||
// 캐릭터의 affect, quest가 load 되기 전에 DragonSoul_Initialize를 호출하면 안된다.
|
||||
// affect가 가장 마지막에 로드되어 LoadAffect에서 호출함.
|
||||
// 캐릭터의 affect, quest가 load 되기 전에 DragonSoul_Initialize를 호출하면 안된다.
|
||||
// affect가 가장 마지막에 로드되어 LoadAffect에서 호출함.
|
||||
void DragonSoul_Initialize();
|
||||
|
||||
bool DragonSoul_IsQualified() const;
|
||||
|
@ -1998,17 +1997,17 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
bool DragonSoul_ActivateDeck(int deck_idx);
|
||||
|
||||
void DragonSoul_DeactivateAll();
|
||||
// 반드시 ClearItem 전에 불러야 한다.
|
||||
// 왜냐하면....
|
||||
// 용혼석 하나 하나를 deactivate할 때마다 덱에 active인 용혼석이 있는지 확인하고,
|
||||
// active인 용혼석이 하나도 없다면, 캐릭터의 용혼석 affect와, 활성 상태를 제거한다.
|
||||
// 반드시 ClearItem 전에 불러야 한다.
|
||||
// 왜냐하면....
|
||||
// 용혼석 하나 하나를 deactivate할 때마다 덱에 active인 용혼석이 있는지 확인하고,
|
||||
// active인 용혼석이 하나도 없다면, 캐릭터의 용혼석 affect와, 활성 상태를 제거한다.
|
||||
//
|
||||
// 하지만 ClearItem 시, 캐릭터가 착용하고 있는 모든 아이템을 unequip하는 바람에,
|
||||
// 용혼석 Affect가 제거되고, 결국 로그인 시, 용혼석이 활성화되지 않는다.
|
||||
// (Unequip할 때에는 로그아웃 상태인지, 아닌지 알 수 없다.)
|
||||
// 용혼석만 deactivate시키고 캐릭터의 용혼석 덱 활성 상태는 건드리지 않는다.
|
||||
// 하지만 ClearItem 시, 캐릭터가 착용하고 있는 모든 아이템을 unequip하는 바람에,
|
||||
// 용혼석 Affect가 제거되고, 결국 로그인 시, 용혼석이 활성화되지 않는다.
|
||||
// (Unequip할 때에는 로그아웃 상태인지, 아닌지 알 수 없다.)
|
||||
// 용혼석만 deactivate시키고 캐릭터의 용혼석 덱 활성 상태는 건드리지 않는다.
|
||||
void DragonSoul_CleanUp();
|
||||
// 용혼석 강화창
|
||||
// 용혼석 강화창
|
||||
public:
|
||||
bool DragonSoul_RefineWindow_Open(LPENTITY pEntity);
|
||||
bool DragonSoul_RefineWindow_Close();
|
||||
|
@ -2016,8 +2015,8 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
bool DragonSoul_RefineWindow_CanRefine();
|
||||
|
||||
private:
|
||||
// SyncPosition을 악용하여 타유저를 이상한 곳으로 보내는 핵 방어하기 위하여,
|
||||
// SyncPosition이 일어날 때를 기록.
|
||||
// SyncPosition을 악용하여 타유저를 이상한 곳으로 보내는 핵 방어하기 위하여,
|
||||
// SyncPosition이 일어날 때를 기록.
|
||||
timeval m_tvLastSyncTime;
|
||||
int m_iSyncHackCount;
|
||||
public:
|
||||
|
|
|
@ -84,13 +84,13 @@ EVENTFUNC(affect_event)
|
|||
if (!ch->UpdateAffect())
|
||||
return 0;
|
||||
else
|
||||
return passes_per_sec; // 1초
|
||||
return passes_per_sec; // 1초
|
||||
}
|
||||
|
||||
bool CHARACTER::UpdateAffect()
|
||||
{
|
||||
// affect_event 에서 처리할 일은 아니지만, 1초짜리 이벤트에서 처리하는 것이
|
||||
// 이것 뿐이라 여기서 물약 처리를 한다.
|
||||
// affect_event 에서 처리할 일은 아니지만, 1초짜리 이벤트에서 처리하는 것이
|
||||
// 이것 뿐이라 여기서 물약 처리를 한다.
|
||||
if (GetPoint(POINT_HP_RECOVERY) > 0)
|
||||
{
|
||||
if (GetMaxHP() <= GetHP())
|
||||
|
@ -146,7 +146,7 @@ bool CHARACTER::UpdateAffect()
|
|||
AutoRecoveryItemProcess( AFFECT_AUTO_HP_RECOVERY );
|
||||
AutoRecoveryItemProcess( AFFECT_AUTO_SP_RECOVERY );
|
||||
|
||||
// 스테미나 회복
|
||||
// 스테미나 회복
|
||||
if (GetMaxStamina() > GetStamina())
|
||||
{
|
||||
int iSec = (get_dword_time() - GetStopTime()) / 3000;
|
||||
|
@ -155,7 +155,7 @@ bool CHARACTER::UpdateAffect()
|
|||
}
|
||||
|
||||
|
||||
// ProcessAffect는 affect가 없으면 true를 리턴한다.
|
||||
// ProcessAffect는 affect가 없으면 true를 리턴한다.
|
||||
if (ProcessAffect())
|
||||
if (GetPoint(POINT_HP_RECOVERY) == 0 && GetPoint(POINT_SP_RECOVERY) == 0 && GetStamina() == GetMaxStamina())
|
||||
{
|
||||
|
@ -226,7 +226,7 @@ int CHARACTER::ProcessAffect()
|
|||
CAffect *pkAff = NULL;
|
||||
|
||||
//
|
||||
// 프리미엄 처리
|
||||
// 프리미엄 처리
|
||||
//
|
||||
for (int i = 0; i <= PREMIUM_MAX_NUM; ++i)
|
||||
{
|
||||
|
@ -300,8 +300,8 @@ int CHARACTER::ProcessAffect()
|
|||
}
|
||||
|
||||
// AFFECT_DURATION_BUG_FIX
|
||||
// 무한 효과 아이템도 시간을 줄인다.
|
||||
// 시간을 매우 크게 잡기 때문에 상관 없을 것이라 생각됨.
|
||||
// 무한 효과 아이템도 시간을 줄인다.
|
||||
// 시간을 매우 크게 잡기 때문에 상관 없을 것이라 생각됨.
|
||||
if ( --pkAff->lDuration <= 0 )
|
||||
{
|
||||
bEnd = true;
|
||||
|
@ -470,7 +470,7 @@ void CHARACTER::LoadAffect(DWORD dwCount, TPacketAffectElement * pElements)
|
|||
|
||||
for (DWORD i = 0; i < dwCount; ++i, ++pElements)
|
||||
{
|
||||
// 무영진은 로드하지않는다.
|
||||
// 무영진은 로드하지않는다.
|
||||
if (pElements->dwType == SKILL_MUYEONG)
|
||||
continue;
|
||||
|
||||
|
@ -524,7 +524,7 @@ void CHARACTER::LoadAffect(DWORD dwCount, TPacketAffectElement * pElements)
|
|||
|
||||
m_bIsLoadedAffect = true;
|
||||
|
||||
// 용혼석 셋팅 로드 및 초기화
|
||||
// 용혼석 셋팅 로드 및 초기화
|
||||
DragonSoul_Initialize();
|
||||
}
|
||||
|
||||
|
@ -533,7 +533,7 @@ bool CHARACTER::AddAffect(DWORD dwType, BYTE bApplyOn, int lApplyValue, DWORD dw
|
|||
// CHAT_BLOCK
|
||||
if (dwType == AFFECT_BLOCK_CHAT && lDuration > 1)
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("운영자 제제로 채팅이 금지 되었습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Your chat has been blocked by a GM."));
|
||||
}
|
||||
// END_OF_CHAT_BLOCK
|
||||
|
||||
|
@ -562,10 +562,10 @@ bool CHARACTER::AddAffect(DWORD dwType, BYTE bApplyOn, int lApplyValue, DWORD dw
|
|||
}
|
||||
}
|
||||
|
||||
// 이미 있는 효과를 덮어 쓰는 처리
|
||||
// 이미 있는 효과를 덮어 쓰는 처리
|
||||
if (pkAff && bOverride)
|
||||
{
|
||||
ComputeAffect(pkAff, false); // 일단 효과를 삭제하고
|
||||
ComputeAffect(pkAff, false); // 일단 효과를 삭제하고
|
||||
|
||||
if (GetDesc())
|
||||
SendAffectRemovePacket(GetDesc(), GetPlayerID(), pkAff->dwType, pkAff->bApplyOn);
|
||||
|
@ -573,9 +573,9 @@ bool CHARACTER::AddAffect(DWORD dwType, BYTE bApplyOn, int lApplyValue, DWORD dw
|
|||
else
|
||||
{
|
||||
//
|
||||
// 새 에펙를 추가
|
||||
// 새 에펙를 추가
|
||||
//
|
||||
// NOTE: 따라서 같은 type 으로도 여러 에펙트를 붙을 수 있다.
|
||||
// NOTE: 따라서 같은 type 으로도 여러 에펙트를 붙을 수 있다.
|
||||
//
|
||||
pkAff = CAffect::Acquire();
|
||||
m_list_pkAffect.push_back(pkAff);
|
||||
|
@ -677,15 +677,15 @@ bool CHARACTER::RemoveAffect(CAffect * pkAff)
|
|||
|
||||
ComputeAffect(pkAff, false);
|
||||
|
||||
// 백기 버그 수정.
|
||||
// 백기 버그는 버프 스킬 시전->둔갑->백기 사용(AFFECT_REVIVE_INVISIBLE) 후 바로 공격 할 경우에 발생한다.
|
||||
// 원인은 둔갑을 시전하는 시점에, 버프 스킬 효과를 무시하고 둔갑 효과만 적용되게 되어있는데,
|
||||
// 백기 사용 후 바로 공격하면 RemoveAffect가 불리게 되고, ComputePoints하면서 둔갑 효과 + 버프 스킬 효과가 된다.
|
||||
// ComputePoints에서 둔갑 상태면 버프 스킬 효과 안 먹히도록 하면 되긴 하는데,
|
||||
// ComputePoints는 광범위하게 사용되고 있어서 큰 변화를 주는 것이 꺼려진다.(어떤 side effect가 발생할지 알기 힘들다.)
|
||||
// 따라서 AFFECT_REVIVE_INVISIBLE가 RemoveAffect로 삭제되는 경우만 수정한다.
|
||||
// 시간이 다 되어 백기 효과가 풀리는 경우는 버그가 발생하지 않으므로 그와 똑같이 함.
|
||||
// (ProcessAffect를 보면 시간이 다 되어서 Affect가 삭제되는 경우, ComputePoints를 부르지 않는다.)
|
||||
// 백기 버그 수정.
|
||||
// 백기 버그는 버프 스킬 시전->둔갑->백기 사용(AFFECT_REVIVE_INVISIBLE) 후 바로 공격 할 경우에 발생한다.
|
||||
// 원인은 둔갑을 시전하는 시점에, 버프 스킬 효과를 무시하고 둔갑 효과만 적용되게 되어있는데,
|
||||
// 백기 사용 후 바로 공격하면 RemoveAffect가 불리게 되고, ComputePoints하면서 둔갑 효과 + 버프 스킬 효과가 된다.
|
||||
// ComputePoints에서 둔갑 상태면 버프 스킬 효과 안 먹히도록 하면 되긴 하는데,
|
||||
// ComputePoints는 광범위하게 사용되고 있어서 큰 변화를 주는 것이 꺼려진다.(어떤 side effect가 발생할지 알기 힘들다.)
|
||||
// 따라서 AFFECT_REVIVE_INVISIBLE가 RemoveAffect로 삭제되는 경우만 수정한다.
|
||||
// 시간이 다 되어 백기 효과가 풀리는 경우는 버그가 발생하지 않으므로 그와 똑같이 함.
|
||||
// (ProcessAffect를 보면 시간이 다 되어서 Affect가 삭제되는 경우, ComputePoints를 부르지 않는다.)
|
||||
if (AFFECT_REVIVE_INVISIBLE != pkAff->dwType)
|
||||
{
|
||||
ComputePoints();
|
||||
|
@ -713,7 +713,7 @@ bool CHARACTER::RemoveAffect(DWORD dwType)
|
|||
// CHAT_BLOCK
|
||||
if (dwType == AFFECT_BLOCK_CHAT)
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("채팅 금지가 풀렸습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Your chat block has been lifted."));
|
||||
}
|
||||
// END_OF_CHAT_BLOCK
|
||||
|
||||
|
@ -795,41 +795,41 @@ bool CHARACTER::IsGoodAffect(BYTE bAffectType) const
|
|||
void CHARACTER::RemoveBadAffect()
|
||||
{
|
||||
SPDLOG_DEBUG("RemoveBadAffect {}", GetName());
|
||||
// 독
|
||||
// 독
|
||||
RemovePoison();
|
||||
RemoveFire();
|
||||
|
||||
// 스턴 : Value%로 상대방을 5초간 머리 위에 별이 돌아간다. (때리면 1/2 확률로 풀림) AFF_STUN
|
||||
// 스턴 : Value%로 상대방을 5초간 머리 위에 별이 돌아간다. (때리면 1/2 확률로 풀림) AFF_STUN
|
||||
RemoveAffect(AFFECT_STUN);
|
||||
|
||||
// 슬로우 : Value%로 상대방의 공속/이속 모두 느려진다. 수련도에 따라 달라짐 기술로 사용 한 경우에 AFF_SLOW
|
||||
// 슬로우 : Value%로 상대방의 공속/이속 모두 느려진다. 수련도에 따라 달라짐 기술로 사용 한 경우에 AFF_SLOW
|
||||
RemoveAffect(AFFECT_SLOW);
|
||||
|
||||
// 투속마령
|
||||
// 투속마령
|
||||
RemoveAffect(SKILL_TUSOK);
|
||||
|
||||
// 저주
|
||||
// 저주
|
||||
//RemoveAffect(SKILL_CURSE);
|
||||
|
||||
// 파법술
|
||||
// 파법술
|
||||
//RemoveAffect(SKILL_PABUP);
|
||||
|
||||
// 기절 : Value%로 상대방을 기절시킨다. 2초 AFF_FAINT
|
||||
// 기절 : Value%로 상대방을 기절시킨다. 2초 AFF_FAINT
|
||||
//RemoveAffect(AFFECT_FAINT);
|
||||
|
||||
// 다리묶임 : Value%로 상대방의 이동속도를 떨어트린다. 5초간 -40 AFF_WEB
|
||||
// 다리묶임 : Value%로 상대방의 이동속도를 떨어트린다. 5초간 -40 AFF_WEB
|
||||
//RemoveAffect(AFFECT_WEB);
|
||||
|
||||
// 잠들기 : Value%로 상대방을 10초간 잠재운다. (때리면 풀림) AFF_SLEEP
|
||||
// 잠들기 : Value%로 상대방을 10초간 잠재운다. (때리면 풀림) AFF_SLEEP
|
||||
//RemoveAffect(AFFECT_SLEEP);
|
||||
|
||||
// 저주 : Value%로 상대방의 공등/방등 모두 떨어트린다. 수련도에 따라 달라짐 기술로 사용 한 경우에 AFF_CURSE
|
||||
// 저주 : Value%로 상대방의 공등/방등 모두 떨어트린다. 수련도에 따라 달라짐 기술로 사용 한 경우에 AFF_CURSE
|
||||
//RemoveAffect(AFFECT_CURSE);
|
||||
|
||||
// 마비 : Value%로 상대방을 4초간 마비시킨다. AFF_PARA
|
||||
// 마비 : Value%로 상대방을 4초간 마비시킨다. AFF_PARA
|
||||
//RemoveAffect(AFFECT_PARALYZE);
|
||||
|
||||
// 부동박부 : 무당 기술
|
||||
// 부동박부 : 무당 기술
|
||||
//RemoveAffect(SKILL_BUDONG);
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,12 +9,12 @@
|
|||
|
||||
/*
|
||||
Return Value
|
||||
0 : 알 수 없는 에러 or 쿼리 에러
|
||||
1 : 동일한 제국으로 바꾸려고함
|
||||
2 : 길드 가입한 캐릭터가 있음
|
||||
3 : 결혼한 캐릭터가 있음
|
||||
0 : 알 수 없는 에러 or 쿼리 에러
|
||||
1 : 동일한 제국으로 바꾸려고함
|
||||
2 : 길드 가입한 캐릭터가 있음
|
||||
3 : 결혼한 캐릭터가 있음
|
||||
|
||||
999 : 제국 이동 성공
|
||||
999 : 제국 이동 성공
|
||||
*/
|
||||
int CHARACTER::ChangeEmpire(BYTE empire)
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ int CHARACTER::ChangeEmpire(BYTE empire)
|
|||
memset(dwPID, 0, sizeof(dwPID));
|
||||
|
||||
{
|
||||
// 1. 내 계정의 모든 pid를 얻어 온다
|
||||
// 1. 내 계정의 모든 pid를 얻어 온다
|
||||
snprintf(szQuery, sizeof(szQuery),
|
||||
"SELECT id, pid1, pid2, pid3, pid4 FROM player_index%s WHERE pid1=%u OR pid2=%u OR pid3=%u OR pid4=%u AND empire=%u",
|
||||
get_table_postfix(), GetPlayerID(), GetPlayerID(), GetPlayerID(), GetPlayerID(), GetEmpire());
|
||||
|
@ -51,8 +51,8 @@ int CHARACTER::ChangeEmpire(BYTE empire)
|
|||
const int loop = 4;
|
||||
|
||||
{
|
||||
// 2. 각 캐릭터의 길드 정보를 얻어온다.
|
||||
// 한 캐릭터라도 길드에 가입 되어 있다면, 제국 이동을 할 수 없다.
|
||||
// 2. 각 캐릭터의 길드 정보를 얻어온다.
|
||||
// 한 캐릭터라도 길드에 가입 되어 있다면, 제국 이동을 할 수 없다.
|
||||
DWORD dwGuildID[4];
|
||||
CGuild * pGuild[4];
|
||||
SQLMsg * pMsg = NULL;
|
||||
|
@ -91,8 +91,8 @@ int CHARACTER::ChangeEmpire(BYTE empire)
|
|||
}
|
||||
|
||||
{
|
||||
// 3. 각 캐릭터의 결혼 정보를 얻어온다.
|
||||
// 한 캐릭터라도 결혼 상태라면 제국 이동을 할 수 없다.
|
||||
// 3. 각 캐릭터의 결혼 정보를 얻어온다.
|
||||
// 한 캐릭터라도 결혼 상태라면 제국 이동을 할 수 없다.
|
||||
for (int i = 0; i < loop; ++i)
|
||||
{
|
||||
if (marriage::CManager::instance().IsEngagedOrMarried(dwPID[i]) == true)
|
||||
|
@ -101,7 +101,7 @@ int CHARACTER::ChangeEmpire(BYTE empire)
|
|||
}
|
||||
|
||||
{
|
||||
// 4. db의 제국 정보를 업데이트 한다.
|
||||
// 4. db의 제국 정보를 업데이트 한다.
|
||||
snprintf(szQuery, sizeof(szQuery), "UPDATE player_index%s SET empire=%u WHERE pid1=%u OR pid2=%u OR pid3=%u OR pid4=%u AND empire=%u",
|
||||
get_table_postfix(), empire, GetPlayerID(), GetPlayerID(), GetPlayerID(), GetPlayerID(), GetEmpire());
|
||||
|
||||
|
@ -109,7 +109,7 @@ int CHARACTER::ChangeEmpire(BYTE empire)
|
|||
|
||||
if (msg->Get()->uiAffectedRows > 0)
|
||||
{
|
||||
// 5. 제국 변경 이력을 추가한다.
|
||||
// 5. 제국 변경 이력을 추가한다.
|
||||
SetChangeEmpireCount();
|
||||
|
||||
return 999;
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
#include "DragonSoul.h"
|
||||
#include "log.h"
|
||||
|
||||
// 용혼석 초기화
|
||||
// 용혼석 on/off는 Affect로 저장되기 때문에,
|
||||
// 용혼석 Affect가 있다면 덱에 있는 용혼석을 activate해야한다.
|
||||
// 또한 용혼석 사용 자격은 QuestFlag로 저장해 놓았기 때문에,
|
||||
// 퀘스트 Flag에서 용혼석 사용 자격을 읽어온다.
|
||||
// 용혼석 초기화
|
||||
// 용혼석 on/off는 Affect로 저장되기 때문에,
|
||||
// 용혼석 Affect가 있다면 덱에 있는 용혼석을 activate해야한다.
|
||||
// 또한 용혼석 사용 자격은 QuestFlag로 저장해 놓았기 때문에,
|
||||
// 퀘스트 Flag에서 용혼석 사용 자격을 읽어온다.
|
||||
|
||||
// 캐릭터의 affect, quest가 load 되기 전에 DragonSoul_Initialize를 호출하면 안된다.
|
||||
// affect가 가장 마지막에 로드되어 LoadAffect에서 호출함.
|
||||
// 캐릭터의 affect, quest가 load 되기 전에 DragonSoul_Initialize를 호출하면 안된다.
|
||||
// affect가 가장 마지막에 로드되어 LoadAffect에서 호출함.
|
||||
void CHARACTER::DragonSoul_Initialize()
|
||||
{
|
||||
for (int i = INVENTORY_MAX_NUM + WEAR_MAX_NUM; i < DRAGON_SOUL_EQUIP_SLOT_END; i++)
|
||||
|
@ -55,7 +55,7 @@ void CHARACTER::DragonSoul_GiveQualification()
|
|||
}
|
||||
AddAffect(AFFECT_DRAGON_SOUL_QUALIFIED, APPLY_NONE, 0, AFF_NONE, INFINITE_AFFECT_DURATION, 0, false, false);
|
||||
//SetQuestFlag("dragon_soul.is_qualified", 1);
|
||||
//// 자격있다면 POINT_DRAGON_SOUL_IS_QUALIFIED는 무조건 1
|
||||
//// 자격있다면 POINT_DRAGON_SOUL_IS_QUALIFIED는 무조건 1
|
||||
//PointChange(POINT_DRAGON_SOUL_IS_QUALIFIED, 1 - GetPoint(POINT_DRAGON_SOUL_IS_QUALIFIED));
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ bool CHARACTER::DragonSoul_ActivateDeck(int deck_idx)
|
|||
|
||||
if (!DragonSoul_IsQualified())
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용혼석 상자가 활성화되지 않았습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Dragon Soul Alchemy is not active"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -142,4 +142,4 @@ bool CHARACTER::DragonSoul_RefineWindow_Close()
|
|||
bool CHARACTER::DragonSoul_RefineWindow_CanRefine()
|
||||
{
|
||||
return NULL != m_pointsInstant.m_pDragonSoulRefineWindowOpener;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,22 +17,22 @@ bool CHARACTER::StartRiding()
|
|||
{
|
||||
if (IsDead() == true)
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("쓰러진 상태에서는 말에 탈 수 없습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot ride a Horse while downed."));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsPolymorphed())
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("변신 상태에서는 말에 탈 수 없습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot ride a Horse while you are transformed."));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 턱시도 입은 상태의 말 타기 금지
|
||||
// 턱시도 입은 상태의 말 타기 금지
|
||||
LPITEM armor = GetWear(WEAR_BODY);
|
||||
|
||||
if (armor && (armor->GetVnum() >= 11901 && armor->GetVnum() <= 11904))
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("예복을 입은 상태에서 말을 탈 수 없습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot ride while you are wearing a Wedding Dress or a Tuxedo."));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -48,16 +48,16 @@ bool CHARACTER::StartRiding()
|
|||
if (false == CHorseRider::StartRiding())
|
||||
{
|
||||
if (GetHorseLevel() <= 0)
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말을 소유하고 있지 않습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You do not have a Horse."));
|
||||
else if (GetHorseHealth() <= 0)
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말이 죽어있는 상태 입니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Your Horse is dead."));
|
||||
else if (GetHorseStamina() <= 0)
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말의 스테미너가 부족하여 말을 탈 수 없습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Your Horse's endurance is too low."));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 소환한 말 없애고
|
||||
// 소환한 말 없애고
|
||||
HorseSummon(false);
|
||||
|
||||
MountVnum(dwMountVnum);
|
||||
|
@ -78,7 +78,7 @@ bool CHARACTER::StopRiding()
|
|||
DWORD dwOldVnum = GetMountVnum();
|
||||
MountVnum(0);
|
||||
|
||||
// [NOTE] 말에서 내릴 땐 자기가 탔던걸 소환하도록 수정
|
||||
// [NOTE] 말에서 내릴 땐 자기가 탔던걸 소환하도록 수정
|
||||
HorseSummon(true, false, dwOldVnum);
|
||||
}
|
||||
else
|
||||
|
@ -139,14 +139,14 @@ void CHARACTER::HorseSummon(bool bSummon, bool bFromFar, DWORD dwVnum, const cha
|
|||
{
|
||||
if ( bSummon )
|
||||
{
|
||||
//NOTE : summon했는데 이미 horse가 있으면 아무것도 안한다.
|
||||
//NOTE : summon했는데 이미 horse가 있으면 아무것도 안한다.
|
||||
if( m_chHorse != NULL )
|
||||
return;
|
||||
|
||||
if (GetHorseLevel() <= 0)
|
||||
return;
|
||||
|
||||
// 무언가를 타고 있다면 실패
|
||||
// 무언가를 타고 있다면 실패
|
||||
if (IsRiding())
|
||||
return;
|
||||
|
||||
|
@ -177,16 +177,16 @@ void CHARACTER::HorseSummon(bool bSummon, bool bFromFar, DWORD dwVnum, const cha
|
|||
|
||||
if (!m_chHorse)
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말 소환에 실패하였습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Calling the Horse has failed."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetHorseHealth() <= 0)
|
||||
{
|
||||
// 죽은거처럼 있게 하는 처리
|
||||
// 죽은거처럼 있게 하는 처리
|
||||
m_chHorse->SetPosition(POS_DEAD);
|
||||
|
||||
// 일정시간있다 사라지게 하자.
|
||||
// 일정시간있다 사라지게 하자.
|
||||
char_event_info* info = AllocEventInfo<char_event_info>();
|
||||
info->ch = this;
|
||||
m_chHorse->m_pkDeadEvent = event_create(horse_dead_event, info, PASSES_PER_SEC(60));
|
||||
|
@ -203,7 +203,7 @@ void CHARACTER::HorseSummon(bool bSummon, bool bFromFar, DWORD dwVnum, const cha
|
|||
else
|
||||
{
|
||||
m_chHorse->m_stName = GetName();
|
||||
m_chHorse->m_stName += LC_TEXT("님의 말");
|
||||
m_chHorse->m_stName += LC_TEXT("'s Horse");
|
||||
}
|
||||
|
||||
if (!m_chHorse->Show(GetMapIndex(), x, y, GetZ()))
|
||||
|
@ -239,7 +239,7 @@ void CHARACTER::HorseSummon(bool bSummon, bool bFromFar, DWORD dwVnum, const cha
|
|||
}
|
||||
else
|
||||
{
|
||||
// 멀어지면서 사라지는 처리 하기
|
||||
// 멀어지면서 사라지는 처리 하기
|
||||
chHorse->SetNowWalking(false);
|
||||
float fx, fy;
|
||||
chHorse->SetRotation(GetDegreeFromPositionXY(chHorse->GetX(), chHorse->GetY(), GetX(), GetY())+180);
|
||||
|
@ -310,7 +310,7 @@ void CHARACTER::SendHorseInfo()
|
|||
3: 70% < ~ <= 100%
|
||||
2: 30% < ~ <= 70%
|
||||
1: 0% < ~ <= 30%
|
||||
0: 사망
|
||||
0: 사망
|
||||
|
||||
STM
|
||||
|
||||
|
@ -343,8 +343,8 @@ STM
|
|||
{
|
||||
ChatPacket(CHAT_TYPE_COMMAND, "horse_state %d %d %d", GetHorseLevel(), iHealthGrade, iStaminaGrade);
|
||||
|
||||
// FIX : 클라이언트에 "말 상태 버프" 아이콘을 표시하지 않을 목적으로 함수 초입에 return함으로써 아래 코드를 무시한다면
|
||||
// 말을 무한대로 소환하는 무시무시한 버그가 생김.. 정확한 원인은 파악 안해봐서 모름.
|
||||
// FIX : 클라이언트에 "말 상태 버프" 아이콘을 표시하지 않을 목적으로 함수 초입에 return함으로써 아래 코드를 무시한다면
|
||||
// 말을 무한대로 소환하는 무시무시한 버그가 생김.. 정확한 원인은 파악 안해봐서 모름.
|
||||
m_bSendHorseLevel = GetHorseLevel();
|
||||
m_bSendHorseHealthGrade = iHealthGrade;
|
||||
m_bSendHorseStaminaGrade = iStaminaGrade;
|
||||
|
@ -366,7 +366,7 @@ bool CHARACTER::CanUseHorseSkill()
|
|||
if (GetMountVnum() >= 20209 && GetMountVnum() <= 20212)
|
||||
return true;
|
||||
|
||||
//라마단 흑마
|
||||
//라마단 흑마
|
||||
if (CMobVnumHelper::IsRamadanBlackHorse(GetMountVnum()))
|
||||
return true;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -114,7 +114,7 @@ void CHARACTER_MANAGER::DestroyCharacter(LPCHARACTER ch, const char* file, size_
|
|||
return; // prevent duplicated destrunction
|
||||
}
|
||||
|
||||
// 던전에 소속된 몬스터는 던전에서도 삭제하도록.
|
||||
// 던전에 소속된 몬스터는 던전에서도 삭제하도록.
|
||||
if (ch->IsNPC() && !ch->IsPet() && ch->GetRider() == NULL)
|
||||
{
|
||||
if (ch->GetDungeon())
|
||||
|
@ -230,7 +230,7 @@ LPCHARACTER CHARACTER_MANAGER::FindPC(const char * name)
|
|||
|
||||
LPCHARACTER CHARACTER_MANAGER::SpawnMobRandomPosition(DWORD dwVnum, int lMapIndex)
|
||||
{
|
||||
// 왜구 스폰할지말지를 결정할 수 있게함
|
||||
// 왜구 스폰할지말지를 결정할 수 있게함
|
||||
{
|
||||
if (dwVnum == 5001 && !quest::CQuestManager::instance().GetEventFlag("japan_regen"))
|
||||
{
|
||||
|
@ -239,7 +239,7 @@ LPCHARACTER CHARACTER_MANAGER::SpawnMobRandomPosition(DWORD dwVnum, int lMapInde
|
|||
}
|
||||
}
|
||||
|
||||
// 해태를 스폰할지 말지를 결정할 수 있게 함
|
||||
// 해태를 스폰할지 말지를 결정할 수 있게 함
|
||||
{
|
||||
if (dwVnum == 5002 && !quest::CQuestManager::instance().GetEventFlag("newyear_mob"))
|
||||
{
|
||||
|
@ -248,7 +248,7 @@ LPCHARACTER CHARACTER_MANAGER::SpawnMobRandomPosition(DWORD dwVnum, int lMapInde
|
|||
}
|
||||
}
|
||||
|
||||
// 광복절 이벤트
|
||||
// 광복절 이벤트
|
||||
{
|
||||
if (dwVnum == 5004 && !quest::CQuestManager::instance().GetEventFlag("independence_day"))
|
||||
{
|
||||
|
@ -448,7 +448,7 @@ LPCHARACTER CHARACTER_MANAGER::SpawnMobRange(DWORD dwVnum, int lMapIndex, int sx
|
|||
if (!pkMob)
|
||||
return NULL;
|
||||
|
||||
if (pkMob->m_table.bType == CHAR_TYPE_STONE) // 돌은 무조건 SPAWN 모션이 있다.
|
||||
if (pkMob->m_table.bType == CHAR_TYPE_STONE) // 돌은 무조건 SPAWN 모션이 있다.
|
||||
bSpawnMotion = true;
|
||||
|
||||
int i = 16;
|
||||
|
@ -512,7 +512,7 @@ bool CHARACTER_MANAGER::SpawnMoveGroup(DWORD dwVnum, int lMapIndex, int sx, int
|
|||
|
||||
if (!tch)
|
||||
{
|
||||
if (i == 0) // 못만든 몬스터가 대장일 경우에는 그냥 실패
|
||||
if (i == 0) // 못만든 몬스터가 대장일 경우에는 그냥 실패
|
||||
return false;
|
||||
|
||||
continue;
|
||||
|
@ -596,7 +596,7 @@ LPCHARACTER CHARACTER_MANAGER::SpawnGroup(DWORD dwVnum, int lMapIndex, int sx, i
|
|||
|
||||
if (!tch)
|
||||
{
|
||||
if (i == 0) // 못만든 몬스터가 대장일 경우에는 그냥 실패
|
||||
if (i == 0) // 못만든 몬스터가 대장일 경우에는 그냥 실패
|
||||
return NULL;
|
||||
|
||||
continue;
|
||||
|
@ -652,11 +652,11 @@ void CHARACTER_MANAGER::Update(int iPulse)
|
|||
|
||||
BeginPendingDestroy();
|
||||
|
||||
// PC 캐릭터 업데이트
|
||||
// PC 캐릭터 업데이트
|
||||
{
|
||||
if (!m_map_pkPCChr.empty())
|
||||
{
|
||||
// 컨테이너 복사
|
||||
// 컨테이너 복사
|
||||
CHARACTER_VECTOR v;
|
||||
v.reserve(m_map_pkPCChr.size());
|
||||
#ifdef __GNUC__
|
||||
|
@ -680,7 +680,7 @@ void CHARACTER_MANAGER::Update(int iPulse)
|
|||
// for_each_pc(bind2nd(mem_fun(&CHARACTER::UpdateCharacter), iPulse));
|
||||
}
|
||||
|
||||
// 몬스터 업데이트
|
||||
// 몬스터 업데이트
|
||||
{
|
||||
if (!m_set_pkChrState.empty())
|
||||
{
|
||||
|
@ -695,7 +695,7 @@ void CHARACTER_MANAGER::Update(int iPulse)
|
|||
}
|
||||
}
|
||||
|
||||
// 산타 따로 업데이트
|
||||
// 산타 따로 업데이트
|
||||
{
|
||||
CharacterVectorInteractor i;
|
||||
|
||||
|
@ -706,7 +706,7 @@ void CHARACTER_MANAGER::Update(int iPulse)
|
|||
}
|
||||
}
|
||||
|
||||
// 1시간에 한번씩 몹 사냥 개수 기록
|
||||
// 1시간에 한번씩 몹 사냥 개수 기록
|
||||
if (0 == (iPulse % PASSES_PER_SEC(3600)))
|
||||
{
|
||||
for (itertype(m_map_dwMobKillCount) it = m_map_dwMobKillCount.begin(); it != m_map_dwMobKillCount.end(); ++it)
|
||||
|
@ -715,11 +715,11 @@ void CHARACTER_MANAGER::Update(int iPulse)
|
|||
m_map_dwMobKillCount.clear();
|
||||
}
|
||||
|
||||
// 테스트 서버에서는 60초마다 캐릭터 개수를 센다
|
||||
// 테스트 서버에서는 60초마다 캐릭터 개수를 센다
|
||||
if (test_server && 0 == (iPulse % PASSES_PER_SEC(60)))
|
||||
SPDLOG_TRACE("CHARACTER COUNT vid {} pid {}", m_map_pkChrByVID.size(), m_map_pkChrByPID.size());
|
||||
|
||||
// 지연된 DestroyCharacter 하기
|
||||
// 지연된 DestroyCharacter 하기
|
||||
FlushPendingDestroy();
|
||||
}
|
||||
|
||||
|
@ -835,7 +835,7 @@ void CHARACTER_MANAGER::RegisterRaceNumMap(LPCHARACTER ch)
|
|||
{
|
||||
DWORD dwVnum = ch->GetRaceNum();
|
||||
|
||||
if (m_set_dwRegisteredRaceNum.find(dwVnum) != m_set_dwRegisteredRaceNum.end()) // 등록된 번호 이면
|
||||
if (m_set_dwRegisteredRaceNum.find(dwVnum) != m_set_dwRegisteredRaceNum.end()) // 등록된 번호 이면
|
||||
{
|
||||
SPDLOG_TRACE("RegisterRaceNumMap {} {}", ch->GetName(), dwVnum);
|
||||
m_map_pkChrByRaceNum[dwVnum].insert(ch);
|
||||
|
@ -859,7 +859,7 @@ bool CHARACTER_MANAGER::GetCharactersByRaceNum(DWORD dwRaceNum, CharacterVectorI
|
|||
if (it == m_map_pkChrByRaceNum.end())
|
||||
return false;
|
||||
|
||||
// 컨테이너 복사
|
||||
// 컨테이너 복사
|
||||
i = it->second;
|
||||
return true;
|
||||
}
|
||||
|
@ -1056,8 +1056,8 @@ void CHARACTER_MANAGER::SendScriptToMap(int lMapIndex, const std::string & s)
|
|||
|
||||
bool CHARACTER_MANAGER::BeginPendingDestroy()
|
||||
{
|
||||
// Begin 이 후에 Begin을 또 하는 경우에 Flush 하지 않는 기능 지원을 위해
|
||||
// 이미 시작되어있으면 false 리턴 처리
|
||||
// Begin 이 후에 Begin을 또 하는 경우에 Flush 하지 않는 기능 지원을 위해
|
||||
// 이미 시작되어있으면 false 리턴 처리
|
||||
if (m_bUsePendingDestroy)
|
||||
return false;
|
||||
|
||||
|
@ -1069,7 +1069,7 @@ void CHARACTER_MANAGER::FlushPendingDestroy()
|
|||
{
|
||||
using namespace std;
|
||||
|
||||
m_bUsePendingDestroy = false; // 플래그를 먼저 설정해야 실제 Destroy 처리가 됨
|
||||
m_bUsePendingDestroy = false; // 플래그를 먼저 설정해야 실제 Destroy 처리가 됨
|
||||
|
||||
if (!m_set_pkChrPendingDestroy.empty())
|
||||
{
|
||||
|
|
|
@ -24,7 +24,7 @@ class CHARACTER_MANAGER : public singleton<CHARACTER_MANAGER>
|
|||
|
||||
void Destroy();
|
||||
|
||||
void GracefulShutdown(); // 정상적 셧다운할 때 사용. PC를 모두 저장시키고 Destroy 한다.
|
||||
void GracefulShutdown(); // 정상적 셧다운할 때 사용. PC를 모두 저장시키고 Destroy 한다.
|
||||
|
||||
DWORD AllocVID();
|
||||
|
||||
|
@ -56,11 +56,11 @@ class CHARACTER_MANAGER : public singleton<CHARACTER_MANAGER>
|
|||
bool AddToStateList(LPCHARACTER ch);
|
||||
void RemoveFromStateList(LPCHARACTER ch);
|
||||
|
||||
// DelayedSave: 어떠한 루틴 내에서 저장을 해야 할 짓을 많이 하면 저장
|
||||
// 쿼리가 너무 많아지므로 "저장을 한다" 라고 표시만 해두고 잠깐
|
||||
// (예: 1 frame) 후에 저장시킨다.
|
||||
// DelayedSave: 어떠한 루틴 내에서 저장을 해야 할 짓을 많이 하면 저장
|
||||
// 쿼리가 너무 많아지므로 "저장을 한다" 라고 표시만 해두고 잠깐
|
||||
// (예: 1 frame) 후에 저장시킨다.
|
||||
void DelayedSave(LPCHARACTER ch);
|
||||
bool FlushDelayedSave(LPCHARACTER ch); // Delayed 리스트에 있다면 지우고 저장한다. 끊김 처리시 사용 됨.
|
||||
bool FlushDelayedSave(LPCHARACTER ch); // Delayed 리스트에 있다면 지우고 저장한다. 끊김 처리시 사용 됨.
|
||||
void ProcessDelayedSave();
|
||||
|
||||
template<class Func> Func for_each_pc(Func f);
|
||||
|
@ -124,7 +124,7 @@ class CHARACTER_MANAGER : public singleton<CHARACTER_MANAGER>
|
|||
NAME_MAP m_map_pkPCChr;
|
||||
|
||||
char dummy1[1024]; // memory barrier
|
||||
CHARACTER_SET m_set_pkChrState; // FSM이 돌아가고 있는 놈들
|
||||
CHARACTER_SET m_set_pkChrState; // FSM이 돌아가고 있는 놈들
|
||||
CHARACTER_SET m_set_pkChrForDelayedSave;
|
||||
CHARACTER_SET m_set_pkChrMonsterLog;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
/////////////////////////////////////////////////////////////////////////////
|
||||
// QUICKSLOT HANDLING
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
void CHARACTER::SyncQuickslot(BYTE bType, BYTE bOldPos, BYTE bNewPos) // bNewPos == 255 면 DELETE
|
||||
void CHARACTER::SyncQuickslot(BYTE bType, BYTE bOldPos, BYTE bNewPos) // bNewPos == 255 면 DELETE
|
||||
{
|
||||
if (bOldPos == bNewPos)
|
||||
return;
|
||||
|
@ -121,7 +121,7 @@ bool CHARACTER::SwapQuickslot(BYTE a, BYTE b)
|
|||
if (a >= QUICKSLOT_MAX_NUM || b >= QUICKSLOT_MAX_NUM)
|
||||
return false;
|
||||
|
||||
// 퀵 슬롯 자리를 서로 바꾼다.
|
||||
// 퀵 슬롯 자리를 서로 바꾼다.
|
||||
quickslot = m_quickslot[a];
|
||||
|
||||
m_quickslot[a] = m_quickslot[b];
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "affect.h"
|
||||
#include "locale_service.h"
|
||||
|
||||
// 독
|
||||
// 독
|
||||
const int poison_damage_rate[MOB_RANK_MAX_NUM] =
|
||||
{
|
||||
80, 50, 40, 30, 25, 1
|
||||
|
@ -135,7 +135,7 @@ EVENTFUNC(fire_event)
|
|||
|
||||
/*
|
||||
|
||||
LEVEL에 의한..
|
||||
LEVEL에 의한..
|
||||
|
||||
+8 0%
|
||||
+7 5%
|
||||
|
@ -184,7 +184,7 @@ void CHARACTER::AttackedByPoison(LPCHARACTER pkAttacker)
|
|||
if (m_pkPoisonEvent)
|
||||
return;
|
||||
|
||||
if (m_bHasPoisoned && !IsPC()) // 몬스터는 독이 한번만 걸린다.
|
||||
if (m_bHasPoisoned && !IsPC()) // 몬스터는 독이 한번만 걸린다.
|
||||
return;
|
||||
|
||||
if (pkAttacker && pkAttacker->GetLevel() < GetLevel())
|
||||
|
@ -201,7 +201,7 @@ void CHARACTER::AttackedByPoison(LPCHARACTER pkAttacker)
|
|||
/*if (IsImmune(IMMUNE_POISON))
|
||||
return;*/
|
||||
|
||||
// 독 내성 굴림 실패, 독에 걸렸다!
|
||||
// 독 내성 굴림 실패, 독에 걸렸다!
|
||||
m_bHasPoisoned = true;
|
||||
|
||||
AddAffect(AFFECT_POISON, POINT_NONE, 0, AFF_POISON, POISON_LENGTH + 1, 0, true);
|
||||
|
|
|
@ -62,7 +62,7 @@ void CHARACTER::SetSkillNextReadTime(DWORD dwVnum, time_t time)
|
|||
|
||||
bool TSkillUseInfo::HitOnce(DWORD dwVnum)
|
||||
{
|
||||
// 쓰지도않았으면 때리지도 못한다.
|
||||
// 쓰지도않았으면 때리지도 못한다.
|
||||
if (!bUsed)
|
||||
return false;
|
||||
|
||||
|
@ -97,7 +97,7 @@ bool TSkillUseInfo::UseSkill(bool isGrandMaster, DWORD vid, DWORD dwCooltime, in
|
|||
this->isGrandMaster = isGrandMaster;
|
||||
DWORD dwCur = get_dword_time();
|
||||
|
||||
// 아직 쿨타임이 끝나지 않았다.
|
||||
// 아직 쿨타임이 끝나지 않았다.
|
||||
if (bUsed && dwNextSkillUsableTime > dwCur)
|
||||
{
|
||||
SPDLOG_DEBUG("cooltime is not over delta {}", dwNextSkillUsableTime - dwCur);
|
||||
|
@ -267,7 +267,7 @@ bool CHARACTER::LearnGrandMasterSkill(DWORD dwSkillVnum)
|
|||
|
||||
if (!IsLearnableSkill(dwSkillVnum))
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("수련할 수 없는 스킬입니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot train this skill."));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -280,9 +280,9 @@ bool CHARACTER::LearnGrandMasterSkill(DWORD dwSkillVnum)
|
|||
{
|
||||
if (FindAffect(AFFECT_SKILL_NO_BOOK_DELAY))
|
||||
{
|
||||
// 주안술서 사용중에는 시간 제한 무시
|
||||
// 주안술서 사용중에는 시간 제한 무시
|
||||
RemoveAffect(AFFECT_SKILL_NO_BOOK_DELAY);
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("주안술서를 통해 주화입마에서 빠져나왔습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have escaped the evil ghost curse with the help of an Exorcism Scroll."));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -293,19 +293,19 @@ bool CHARACTER::LearnGrandMasterSkill(DWORD dwSkillVnum)
|
|||
}
|
||||
*/
|
||||
|
||||
// bType이 0이면 처음부터 책으로 수련 가능
|
||||
// bType이 0이면 처음부터 책으로 수련 가능
|
||||
if (pkSk->dwType == 0)
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("그랜드 마스터 수련을 할 수 없는 스킬입니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot train this skill up to Grand Master level."));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetSkillMasterType(dwSkillVnum) != SKILL_GRAND_MASTER)
|
||||
{
|
||||
if (GetSkillMasterType(dwSkillVnum) > SKILL_GRAND_MASTER)
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("퍼펙트 마스터된 스킬입니다. 더 이상 수련 할 수 없습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You already are a Master of this skill. You cannot train this skill any further."));
|
||||
else
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("이 스킬은 아직 그랜드 마스터 수련을 할 경지에 이르지 않았습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Your Skill is not high enough to become a Grand Master."));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -316,7 +316,7 @@ bool CHARACTER::LearnGrandMasterSkill(DWORD dwSkillVnum)
|
|||
strTrainSkill = os.str();
|
||||
}
|
||||
|
||||
// 여기서 확률을 계산합니다.
|
||||
// 여기서 확률을 계산합니다.
|
||||
BYTE bLastLevel = GetSkillLevel(dwSkillVnum);
|
||||
|
||||
int idx = std::min(9, GetSkillLevel(dwSkillVnum) - 30);
|
||||
|
@ -386,15 +386,15 @@ bool CHARACTER::LearnGrandMasterSkill(DWORD dwSkillVnum)
|
|||
|
||||
if (bLastLevel == GetSkillLevel(dwSkillVnum))
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("크윽, 기가 역류하고 있어! 이거 설마 주화입마인가!? 젠장!"));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("수련이 실패로 끝났습니다. 다시 도전해주시기 바랍니다."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("That did not work. Damn!"));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Training has failed. Please try again later."));
|
||||
LogManager::instance().CharLog(this, dwSkillVnum, "GM_READ_FAIL", "");
|
||||
return false;
|
||||
}
|
||||
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("몸에서 뭔가 힘이 터져 나오는 기분이야!"));
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("뜨거운 무엇이 계속 용솟음치고 있어! 이건, 이것은!"));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("더 높은 경지의 수련을 성공적으로 끝내셨습니다."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("My body is full of energy!"));
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("The training seems to be working already..."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You successfully finished your training with the book."));
|
||||
LogManager::instance().CharLog(this, dwSkillVnum, "GM_READ_SUCCESS", "");
|
||||
return true;
|
||||
}
|
||||
|
@ -421,7 +421,7 @@ bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb)
|
|||
|
||||
if (!IsLearnableSkill(dwSkillVnum))
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("수련할 수 없는 스킬입니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot train this skill."));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -433,20 +433,20 @@ bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb)
|
|||
|
||||
if ( GetExp() < need_exp )
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("경험치가 부족하여 책을 읽을 수 없습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot read this due to your lack of experience."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// bType이 0이면 처음부터 책으로 수련 가능
|
||||
// bType이 0이면 처음부터 책으로 수련 가능
|
||||
if (pkSk->dwType != 0)
|
||||
{
|
||||
if (GetSkillMasterType(dwSkillVnum) != SKILL_MASTER)
|
||||
{
|
||||
if (GetSkillMasterType(dwSkillVnum) > SKILL_MASTER)
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("이 스킬은 책으로 더이상 수련할 수 없습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot train this skill with a Book."));
|
||||
else
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("이 스킬은 아직 책으로 수련할 경지에 이르지 않았습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This skill's level is not high enough to be trained with a Book."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -457,9 +457,9 @@ bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb)
|
|||
{
|
||||
if (FindAffect(AFFECT_SKILL_NO_BOOK_DELAY))
|
||||
{
|
||||
// 주안술서 사용중에는 시간 제한 무시
|
||||
// 주안술서 사용중에는 시간 제한 무시
|
||||
RemoveAffect(AFFECT_SKILL_NO_BOOK_DELAY);
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("주안술서를 통해 주화입마에서 빠져나왔습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have escaped the evil ghost curse with the help of an Exorcism Scroll."));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -469,7 +469,7 @@ bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb)
|
|||
}
|
||||
}
|
||||
|
||||
// 여기서 확률을 계산합니다.
|
||||
// 여기서 확률을 계산합니다.
|
||||
BYTE bLastLevel = GetSkillLevel(dwSkillVnum);
|
||||
|
||||
if (bProb != 0)
|
||||
|
@ -527,13 +527,13 @@ bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb)
|
|||
|
||||
if (Random::get(1, 100) > percent)
|
||||
{
|
||||
// 책읽기에 성공
|
||||
// 책읽기에 성공
|
||||
if (read_count >= need_bookcount)
|
||||
{
|
||||
SkillLevelUp(dwSkillVnum, SKILL_UP_BY_BOOK);
|
||||
pPC->SetFlag(flag, 0);
|
||||
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("책으로 더 높은 경지의 수련을 성공적으로 끝내셨습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have successfully finished your training with the Book."));
|
||||
LogManager::instance().CharLog(this, dwSkillVnum, "READ_SUCCESS", "");
|
||||
return true;
|
||||
}
|
||||
|
@ -544,27 +544,27 @@ bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb)
|
|||
switch (Random::get(1, 3))
|
||||
{
|
||||
case 1:
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("어느정도 이 기술에 대해 이해가 되었지만 조금 부족한듯 한데.."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("I'm making progress, but I still haven't understood everything."));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("드디어 끝이 보이는 건가... 이 기술은 이해하기가 너무 힘들어.."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("These instructions are difficult to understand. I have to carry on studying."));
|
||||
break;
|
||||
|
||||
case 3:
|
||||
default:
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("열심히 하는 배움을 가지는 것만이 기술을 배울수 있는 유일한 길이다.."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("I understand this chapter. But I've got to carry on working hard."));
|
||||
break;
|
||||
}
|
||||
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d 권을 더 읽어야 수련을 완료 할 수 있습니다."), need_bookcount - read_count);
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have to read %d more skill books to improve this skill."), need_bookcount - read_count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 사용자의 퀘스트 정보 로드 실패
|
||||
// 사용자의 퀘스트 정보 로드 실패
|
||||
}
|
||||
}
|
||||
// INTERNATIONAL_VERSION
|
||||
|
@ -602,15 +602,15 @@ bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb)
|
|||
|
||||
if (bLastLevel != GetSkillLevel(dwSkillVnum))
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("몸에서 뭔가 힘이 터져 나오는 기분이야!"));
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("뜨거운 무엇이 계속 용솟음치고 있어! 이건, 이것은!"));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("책으로 더 높은 경지의 수련을 성공적으로 끝내셨습니다."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("My body is full of energy!"));
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("The training seems to be working already..."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You have successfully finished your training with the Book."));
|
||||
LogManager::instance().CharLog(this, dwSkillVnum, "READ_SUCCESS", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("크윽, 기가 역류하고 있어! 이거 설마 주화입마인가!? 젠장!"));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("수련이 실패로 끝났습니다. 다시 도전해주시기 바랍니다."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("That did not work. Damn!"));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Training has failed. Please try again later."));
|
||||
LogManager::instance().CharLog(this, dwSkillVnum, "READ_FAIL", "");
|
||||
}
|
||||
|
||||
|
@ -694,7 +694,7 @@ void CHARACTER::SkillLevelUp(DWORD dwVnum, BYTE bMethod)
|
|||
|
||||
if (IsPolymorphed())
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("둔갑 중에는 능력을 올릴 수 없습니다."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot change your status while you are transformed."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -721,7 +721,7 @@ void CHARACTER::SkillLevelUp(DWORD dwVnum, BYTE bMethod)
|
|||
if (!IsLearnableSkill(dwVnum))
|
||||
return;
|
||||
|
||||
// 그랜드 마스터는 퀘스트로만 수행가능
|
||||
// 그랜드 마스터는 퀘스트로만 수행가능
|
||||
if (pkSk->dwType != 0)
|
||||
{
|
||||
switch (GetSkillMasterType(pkSk->dwVnum))
|
||||
|
@ -738,7 +738,7 @@ void CHARACTER::SkillLevelUp(DWORD dwVnum, BYTE bMethod)
|
|||
|
||||
if (bMethod == SKILL_UP_BY_POINT)
|
||||
{
|
||||
// 마스터가 아닌 상태에서만 수련가능
|
||||
// 마스터가 아닌 상태에서만 수련가능
|
||||
if (GetSkillMasterType(pkSk->dwVnum) != SKILL_NORMAL)
|
||||
return;
|
||||
|
||||
|
@ -747,7 +747,7 @@ void CHARACTER::SkillLevelUp(DWORD dwVnum, BYTE bMethod)
|
|||
}
|
||||
else if (bMethod == SKILL_UP_BY_BOOK)
|
||||
{
|
||||
if (pkSk->dwType != 0) // 직업에 속하지 않았거나 포인트로 올릴수 없는 스킬은 처음부터 책으로 배울 수 있다.
|
||||
if (pkSk->dwType != 0) // 직업에 속하지 않았거나 포인트로 올릴수 없는 스킬은 처음부터 책으로 배울 수 있다.
|
||||
if (GetSkillMasterType(pkSk->dwVnum) != SKILL_MASTER)
|
||||
return;
|
||||
}
|
||||
|
@ -801,11 +801,11 @@ void CHARACTER::SkillLevelUp(DWORD dwVnum, BYTE bMethod)
|
|||
|
||||
if (pkSk->dwType != 0)
|
||||
{
|
||||
// 갑자기 그레이드 업하는 코딩
|
||||
// 갑자기 그레이드 업하는 코딩
|
||||
switch (GetSkillMasterType(pkSk->dwVnum))
|
||||
{
|
||||
case SKILL_NORMAL:
|
||||
// 번섭은 스킬 업그레이드 17~20 사이 랜덤 마스터 수련
|
||||
// 번섭은 스킬 업그레이드 17~20 사이 랜덤 마스터 수련
|
||||
if (GetSkillLevel(pkSk->dwVnum) >= 17)
|
||||
{
|
||||
if (GetQuestFlag("reset_scroll.force_to_master_skill") > 0)
|
||||
|
@ -863,7 +863,7 @@ void CHARACTER::ResetSkill()
|
|||
if (NULL == m_pSkillLevels)
|
||||
return;
|
||||
|
||||
// 보조 스킬은 리셋시키지 않는다
|
||||
// 보조 스킬은 리셋시키지 않는다
|
||||
std::vector<std::pair<DWORD, TPlayerSkill> > vec;
|
||||
size_t count = sizeof(s_adwSubSkillVnums) / sizeof(s_adwSubSkillVnums[0]);
|
||||
|
||||
|
@ -994,7 +994,7 @@ EVENTFUNC(ChainLightningEvent)
|
|||
|
||||
SPDLOG_DEBUG("chainlighting event {}", pkChr->GetName());
|
||||
|
||||
if (pkChrVictim->GetParty()) // 파티 먼저
|
||||
if (pkChrVictim->GetParty()) // 파티 먼저
|
||||
{
|
||||
pkTarget = pkChrVictim->GetParty()->GetNextOwnership(NULL, pkChrVictim->GetX(), pkChrVictim->GetY());
|
||||
if (pkTarget == pkChrVictim || !Random::get(0, 2) || pkChr->GetChainLightingExcept().find(pkTarget) != pkChr->GetChainLightingExcept().end())
|
||||
|
@ -1090,7 +1090,7 @@ struct FuncSplashDamage
|
|||
}
|
||||
|
||||
if (m_pkChr->IsPC())
|
||||
// 길드 스킬은 쿨타임 처리를 하지 않는다.
|
||||
// 길드 스킬은 쿨타임 처리를 하지 않는다.
|
||||
if (!(m_pkSk->dwVnum >= GUILD_SKILL_START && m_pkSk->dwVnum <= GUILD_SKILL_END))
|
||||
if (!m_bDisableCooltime && m_pInfo && !m_pInfo->HitOnce(m_pkSk->dwVnum) && m_pkSk->dwVnum != SKILL_MUYEONG)
|
||||
{
|
||||
|
@ -1159,7 +1159,7 @@ struct FuncSplashDamage
|
|||
m_pkSk->SetPointVar("chain", m_pkChr->GetChainLightningIndex());
|
||||
m_pkChr->IncChainLightningIndex();
|
||||
|
||||
bool bUnderEunhyung = m_pkChr->GetAffectedEunhyung() > 0; // 이건 왜 여기서 하지??
|
||||
bool bUnderEunhyung = m_pkChr->GetAffectedEunhyung() > 0; // 이건 왜 여기서 하지??
|
||||
|
||||
m_pkSk->SetPointVar("ek", m_pkChr->GetAffectedEunhyung()*1./100);
|
||||
//m_pkChr->ClearAffectedEunhyung();
|
||||
|
@ -1178,7 +1178,7 @@ struct FuncSplashDamage
|
|||
|
||||
if (test_server && iAmount == 0 && m_pkSk->bPointOn != POINT_NONE)
|
||||
{
|
||||
m_pkChr->ChatPacket(CHAT_TYPE_INFO, "효과가 없습니다. 스킬 공식을 확인하세요");
|
||||
m_pkChr->ChatPacket(CHAT_TYPE_INFO, "Not working, check the skill formula");
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
iAmount = -iAmount;
|
||||
|
@ -1241,11 +1241,11 @@ struct FuncSplashDamage
|
|||
|
||||
if (m_pkChr->IsPC() && m_pkChr->m_SkillUseInfo[m_pkSk->dwVnum].GetMainTargetVID() != (DWORD) pkChrVictim->GetVID())
|
||||
{
|
||||
// 데미지 감소
|
||||
// 데미지 감소
|
||||
iDam = (int) (iDam * m_pkSk->kSplashAroundDamageAdjustPoly.Eval());
|
||||
}
|
||||
|
||||
// TODO 스킬에 따른 데미지 타입 기록해야한다.
|
||||
// TODO 스킬에 따른 데미지 타입 기록해야한다.
|
||||
EDamageType dt = DAMAGE_TYPE_NONE;
|
||||
|
||||
switch (m_pkSk->bSkillAttrType)
|
||||
|
@ -1268,7 +1268,7 @@ struct FuncSplashDamage
|
|||
|
||||
case WEAPON_TWO_HANDED:
|
||||
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_TWOHAND)) / 100;
|
||||
// 양손검 페널티 10%
|
||||
// 양손검 페널티 10%
|
||||
//iDam = iDam * 95 / 100;
|
||||
|
||||
break;
|
||||
|
@ -1293,8 +1293,8 @@ struct FuncSplashDamage
|
|||
|
||||
case SKILL_ATTR_TYPE_RANGE:
|
||||
dt = DAMAGE_TYPE_RANGE;
|
||||
// 으아아아악
|
||||
// 예전에 적용안했던 버그가 있어서 방어력 계산을 다시하면 유저가 난리남
|
||||
// 으아아아악
|
||||
// 예전에 적용안했던 버그가 있어서 방어력 계산을 다시하면 유저가 난리남
|
||||
//iDam -= pkChrVictim->GetPoint(POINT_DEF_GRADE);
|
||||
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_BOW)) / 100;
|
||||
break;
|
||||
|
@ -1302,8 +1302,8 @@ struct FuncSplashDamage
|
|||
case SKILL_ATTR_TYPE_MAGIC:
|
||||
dt = DAMAGE_TYPE_MAGIC;
|
||||
iDam = CalcAttBonus(m_pkChr, pkChrVictim, iDam);
|
||||
// 으아아아악
|
||||
// 예전에 적용안했던 버그가 있어서 방어력 계산을 다시하면 유저가 난리남
|
||||
// 으아아아악
|
||||
// 예전에 적용안했던 버그가 있어서 방어력 계산을 다시하면 유저가 난리남
|
||||
//iDam -= pkChrVictim->GetPoint(POINT_MAGIC_DEF_GRADE);
|
||||
iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_MAGIC)) / 100;
|
||||
break;
|
||||
|
@ -1314,13 +1314,13 @@ struct FuncSplashDamage
|
|||
}
|
||||
|
||||
//
|
||||
// 20091109 독일 스킬 속성 요청 작업
|
||||
// 기존 스킬 테이블에 SKILL_FLAG_WIND, SKILL_FLAG_ELEC, SKILL_FLAG_FIRE를 가진 스킬이
|
||||
// 전혀 없었으므로 몬스터의 RESIST_WIND, RESIST_ELEC, RESIST_FIRE도 사용되지 않고 있었다.
|
||||
// 20091109 독일 스킬 속성 요청 작업
|
||||
// 기존 스킬 테이블에 SKILL_FLAG_WIND, SKILL_FLAG_ELEC, SKILL_FLAG_FIRE를 가진 스킬이
|
||||
// 전혀 없었으므로 몬스터의 RESIST_WIND, RESIST_ELEC, RESIST_FIRE도 사용되지 않고 있었다.
|
||||
//
|
||||
// PvP와 PvE밸런스 분리를 위해 의도적으로 NPC만 적용하도록 했으며 기존 밸런스와 차이점을
|
||||
// 느끼지 못하기 위해 mob_proto의 RESIST_MAGIC을 RESIST_WIND, RESIST_ELEC, RESIST_FIRE로
|
||||
// 복사하였다.
|
||||
// PvP와 PvE밸런스 분리를 위해 의도적으로 NPC만 적용하도록 했으며 기존 밸런스와 차이점을
|
||||
// 느끼지 못하기 위해 mob_proto의 RESIST_MAGIC을 RESIST_WIND, RESIST_ELEC, RESIST_FIRE로
|
||||
// 복사하였다.
|
||||
//
|
||||
if (pkChrVictim->IsNPC())
|
||||
{
|
||||
|
@ -1627,7 +1627,7 @@ EVENTFUNC(skill_gwihwan_event)
|
|||
{
|
||||
PIXEL_POSITION pos;
|
||||
|
||||
// 성공
|
||||
// 성공
|
||||
if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(ch->GetMapIndex(), ch->GetEmpire(), pos))
|
||||
{
|
||||
SPDLOG_DEBUG("Recall: {} {} {} -> {} {}", ch->GetName(), ch->GetX(), ch->GetY(), pos.x, pos.y);
|
||||
|
@ -1641,8 +1641,8 @@ EVENTFUNC(skill_gwihwan_event)
|
|||
}
|
||||
else
|
||||
{
|
||||
//실패
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("귀환에 실패하였습니다."));
|
||||
//실패
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Teleportation has failed."));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1666,11 +1666,11 @@ int CHARACTER::ComputeSkillAtPosition(DWORD dwVnum, const PIXEL_POSITION& posTar
|
|||
SPDLOG_TRACE("ComputeSkillAtPosition {} vnum {} x {} y {} level {}",
|
||||
GetName(), dwVnum, posTarget.x, posTarget.y, bSkillLevel);
|
||||
|
||||
// 나에게 쓰는 스킬은 내 위치를 쓴다.
|
||||
// 나에게 쓰는 스킬은 내 위치를 쓴다.
|
||||
//if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY))
|
||||
// posTarget = GetXYZ();
|
||||
|
||||
// 스플래쉬가 아닌 스킬은 주위이면 이상하다
|
||||
// 스플래쉬가 아닌 스킬은 주위이면 이상하다
|
||||
if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
|
||||
return BATTLE_NONE;
|
||||
|
||||
|
@ -1754,7 +1754,7 @@ int CHARACTER::ComputeSkillAtPosition(DWORD dwVnum, const PIXEL_POSITION& posTar
|
|||
|
||||
if (test_server && iAmount == 0 && pkSk->bPointOn != POINT_NONE)
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_INFO, "효과가 없습니다. 스킬 공식을 확인하세요");
|
||||
ChatPacket(CHAT_TYPE_INFO, "Not working, check the skill formula");
|
||||
}
|
||||
|
||||
if (IS_SET(pkSk->dwFlag, SKILL_FLAG_REMOVE_BAD_AFFECT))
|
||||
|
@ -1769,7 +1769,7 @@ int CHARACTER::ComputeSkillAtPosition(DWORD dwVnum, const PIXEL_POSITION& posTar
|
|||
if (IS_SET(pkSk->dwFlag, SKILL_FLAG_ATTACK | SKILL_FLAG_USE_MELEE_DAMAGE | SKILL_FLAG_USE_MAGIC_DAMAGE))
|
||||
{
|
||||
//
|
||||
// 공격 스킬일 경우
|
||||
// 공격 스킬일 경우
|
||||
//
|
||||
bool bAdded = false;
|
||||
|
||||
|
@ -1794,7 +1794,7 @@ int CHARACTER::ComputeSkillAtPosition(DWORD dwVnum, const PIXEL_POSITION& posTar
|
|||
int iDur = (int) pkSk->kDurationPoly.Eval();
|
||||
|
||||
if (IsPC())
|
||||
if (!(dwVnum >= GUILD_SKILL_START && dwVnum <= GUILD_SKILL_END)) // 길드 스킬은 쿨타임 처리를 하지 않는다.
|
||||
if (!(dwVnum >= GUILD_SKILL_START && dwVnum <= GUILD_SKILL_END)) // 길드 스킬은 쿨타임 처리를 하지 않는다.
|
||||
if (!m_bDisableCooltime && !m_SkillUseInfo[dwVnum].HitOnce(dwVnum) && dwVnum != SKILL_MUYEONG)
|
||||
{
|
||||
return BATTLE_NONE;
|
||||
|
@ -1884,7 +1884,7 @@ int CHARACTER::ComputeSkillAtPosition(DWORD dwVnum, const PIXEL_POSITION& posTar
|
|||
if (iDur > 0)
|
||||
{
|
||||
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
|
||||
// AffectFlag가 없거나, toggle 하는 것이 아니라면..
|
||||
// AffectFlag가 없거나, toggle 하는 것이 아니라면..
|
||||
pkSk->kDurationSPCostPoly.SetVar("k", k/*bSkillLevel*/);
|
||||
|
||||
AddAffect(pkSk->dwVnum,
|
||||
|
@ -1939,13 +1939,13 @@ int CHARACTER::ComputeSkillAtPosition(DWORD dwVnum, const PIXEL_POSITION& posTar
|
|||
}
|
||||
}
|
||||
|
||||
// bSkillLevel 인자가 0이 아닐 경우에는 m_abSkillLevels를 사용하지 않고 강제로
|
||||
// bSkillLevel로 계산한다.
|
||||
// bSkillLevel 인자가 0이 아닐 경우에는 m_abSkillLevels를 사용하지 않고 강제로
|
||||
// bSkillLevel로 계산한다.
|
||||
int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel)
|
||||
{
|
||||
const bool bCanUseHorseSkill = CanUseHorseSkill();
|
||||
|
||||
// 말을 타고있지만 스킬은 사용할 수 없는 상태라면 return
|
||||
// 말을 타고있지만 스킬은 사용할 수 없는 상태라면 return
|
||||
if (false == bCanUseHorseSkill && true == IsRiding())
|
||||
return BATTLE_NONE;
|
||||
|
||||
|
@ -1967,7 +1967,7 @@ int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel
|
|||
return BATTLE_NONE;
|
||||
|
||||
|
||||
// 상대방에게 쓰는 것이 아니면 나에게 써야 한다.
|
||||
// 상대방에게 쓰는 것이 아니면 나에게 써야 한다.
|
||||
if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY))
|
||||
pkVictim = this;
|
||||
|
||||
|
@ -2093,7 +2093,7 @@ int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel
|
|||
|
||||
if (test_server && iAmount == 0 && pkSk->bPointOn != POINT_NONE)
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_INFO, "효과가 없습니다. 스킬 공식을 확인하세요");
|
||||
ChatPacket(CHAT_TYPE_INFO, "Not working, check the skill formula");
|
||||
}
|
||||
// END_OF_ADD_GRANDMASTER_SKILL
|
||||
|
||||
|
@ -2135,7 +2135,7 @@ int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel
|
|||
|
||||
|
||||
if (IsPC())
|
||||
if (!(dwVnum >= GUILD_SKILL_START && dwVnum <= GUILD_SKILL_END)) // 길드 스킬은 쿨타임 처리를 하지 않는다.
|
||||
if (!(dwVnum >= GUILD_SKILL_START && dwVnum <= GUILD_SKILL_END)) // 길드 스킬은 쿨타임 처리를 하지 않는다.
|
||||
if (!m_bDisableCooltime && !m_SkillUseInfo[dwVnum].HitOnce(dwVnum) && dwVnum != SKILL_MUYEONG)
|
||||
{
|
||||
return BATTLE_NONE;
|
||||
|
@ -2248,7 +2248,7 @@ int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel
|
|||
if (iDur > 0)
|
||||
{
|
||||
iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
|
||||
// AffectFlag가 없거나, toggle 하는 것이 아니라면..
|
||||
// AffectFlag가 없거나, toggle 하는 것이 아니라면..
|
||||
pkSk->kDurationSPCostPoly.SetVar("k", k/*bSkillLevel*/);
|
||||
|
||||
if (pkSk->bPointOn2 != POINT_NONE)
|
||||
|
@ -2421,14 +2421,14 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste
|
|||
return false;
|
||||
|
||||
if (GetHorseLevel() <= 0)
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말이 없습니다. 마굿간 경비병을 찾아가세요."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("No Horse here. Ask the Stable Boy."));
|
||||
else
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말 소환 아이템을 사용하세요."));
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Please use an item to call a Horse."));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 말을 타고있지만 스킬은 사용할 수 없는 상태라면 return false
|
||||
// 말을 타고있지만 스킬은 사용할 수 없는 상태라면 return false
|
||||
if (false == bCanUseHorseSkill && true == IsRiding())
|
||||
return false;
|
||||
|
||||
|
@ -2474,7 +2474,7 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste
|
|||
}
|
||||
|
||||
m_SkillUseInfo[dwVnum].SetMainTargetVID(pkVictim->GetVID());
|
||||
// DASH 상태의 탄환격은 공격기술
|
||||
// DASH 상태의 탄환격은 공격기술
|
||||
ComputeSkill(dwVnum, pkVictim);
|
||||
RemoveAffect(dwVnum);
|
||||
return true;
|
||||
|
@ -2492,7 +2492,7 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste
|
|||
return true;
|
||||
}
|
||||
|
||||
// Toggle 할 때는 SP를 쓰지 않음 (SelfOnly로 구분)
|
||||
// Toggle 할 때는 SP를 쓰지 않음 (SelfOnly로 구분)
|
||||
if ((0 != pkSk->dwAffectFlag || pkSk->dwVnum == SKILL_MUYEONG) && (pkSk->dwFlag & SKILL_FLAG_TOGGLE) && RemoveAffect(pkSk->dwVnum))
|
||||
{
|
||||
return true;
|
||||
|
@ -2506,7 +2506,7 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste
|
|||
pkSk->SetPointVar("k", k);
|
||||
pkSk->kSplashAroundDamageAdjustPoly.SetVar("k", k);
|
||||
|
||||
// 쿨타임 체크
|
||||
// 쿨타임 체크
|
||||
pkSk->kCooldownPoly.SetVar("k", k);
|
||||
int iCooltime = (int) pkSk->kCooldownPoly.Eval();
|
||||
int lMaxHit = pkSk->lMaxHit ? pkSk->lMaxHit : -1;
|
||||
|
@ -2560,7 +2560,7 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste
|
|||
return false;
|
||||
|
||||
if (test_server)
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s SP소모: %d"), pkSk->szName, iNeededSP);
|
||||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s FP-Consumption: %d"), pkSk->szName, iNeededSP);
|
||||
|
||||
PointChange(POINT_SP, -iNeededSP);
|
||||
}
|
||||
|
@ -2570,7 +2570,7 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste
|
|||
|
||||
if (pkSk->dwVnum == SKILL_MUYEONG || pkSk->IsChargeSkill() && !IsAffectFlag(AFF_TANHWAN_DASH) && !pkVictim)
|
||||
{
|
||||
// 처음 사용하는 무영진은 자신에게 Affect를 붙인다.
|
||||
// 처음 사용하는 무영진은 자신에게 Affect를 붙인다.
|
||||
pkVictim = this;
|
||||
}
|
||||
|
||||
|
@ -2643,7 +2643,7 @@ int CHARACTER::GetSkillMasterType(DWORD dwVnum) const
|
|||
|
||||
int CHARACTER::GetSkillPower(DWORD dwVnum, BYTE bLevel) const
|
||||
{
|
||||
// 인어반지 아이템
|
||||
// 인어반지 아이템
|
||||
if (dwVnum >= SKILL_LANGUAGE1 && dwVnum <= SKILL_LANGUAGE3 && IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE))
|
||||
{
|
||||
return 100;
|
||||
|
@ -2745,41 +2745,41 @@ void CHARACTER::SkillLearnWaitMoreTimeMessage(DWORD ms)
|
|||
//const char* str = "";
|
||||
//
|
||||
if (ms < 3 * 60)
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("몸 속이 뜨겁군. 하지만 아주 편안해. 이대로 기를 안정시키자."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("I am burning inside, but it is calming down my body. My Chi has to stabilise."));
|
||||
else if (ms < 5 * 60)
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("그래, 천천히. 좀더 천천히, 그러나 막힘 없이 빠르게!"));
|
||||
else if (ms < 10 * 60) // 10분
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("그래, 이 느낌이야. 체내에 기가 아주 충만해."));
|
||||
else if (ms < 30 * 60) // 30분
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("A little slow, but steady... Without stopping!"));
|
||||
else if (ms < 10 * 60) // 10분
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("Yes, that feels great. My body is full of Chi."));
|
||||
else if (ms < 30 * 60) // 30분
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("다 읽었다! 이제 비급에 적혀있는 대로 전신에 기를 돌리기만 하면,"));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("그것으로 수련은 끝난 거야!"));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("I have read it! Now the Chi will spread through my body."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("The training is completed."));
|
||||
}
|
||||
else if (ms < 1 * 3600) // 1시간
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("이제 책의 마지막 장이야! 수련의 끝이 눈에 보이고 있어!"));
|
||||
else if (ms < 2 * 3600) // 2시간
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("얼마 안 남았어! 조금만 더!"));
|
||||
else if (ms < 1 * 3600) // 1시간
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("I am on the last page of the book. The training is nearly finished!"));
|
||||
else if (ms < 2 * 3600) // 2시간
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("Nearly finished! Just a little bit more to go!"));
|
||||
else if (ms < 3 * 3600)
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("좋았어! 조금만 더 읽으면 끝이다!"));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("Eureka! I have nearly finished reading it!"));
|
||||
else if (ms < 6 * 3600)
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("책장도 이제 얼마 남지 않았군."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("뭔가 몸 안에 힘이 생기는 기분인 걸."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("Only a few more pages and then I'll have read everything."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("I feel refreshed."));
|
||||
}
|
||||
else if (ms < 12 * 3600)
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("이제 좀 슬슬 가닥이 잡히는 것 같은데."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("좋아, 이 기세로 계속 나간다!"));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("Now I understand it!"));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("Okay I have to stay concentrated!"));
|
||||
}
|
||||
else if (ms < 18 * 3600)
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("아니 어떻게 된 게 종일 읽어도 머리에 안 들어오냐."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("공부하기 싫어지네."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("I keep reading the same line over and over again."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("I do not want to learn any more."));
|
||||
}
|
||||
else //if (ms < 2 * 86400)
|
||||
{
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("생각만큼 읽기가 쉽지가 않군. 이해도 어렵고 내용도 난해해."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("이래서야 공부가 안된다구."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("It is a lot more complicated and more difficult to understand than I thought."));
|
||||
ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("It's hard for me to concentrate. I should take a break."));
|
||||
}
|
||||
/*
|
||||
str = "30%";
|
||||
|
@ -3138,10 +3138,10 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
|
|||
|
||||
static DWORD s_anMotion2SkillVnumList[MOTION_MAX_NUM][SKILL_LIST_MAX_COUNT] =
|
||||
{
|
||||
// 스킬수 무사스킬ID 자객스킬ID 수라스킬ID 무당스킬ID
|
||||
// 스킬수 무사스킬ID 자객스킬ID 수라스킬ID 무당스킬ID
|
||||
{ 0, 0, 0, 0, 0 }, // 0
|
||||
|
||||
// 1번 직군 기본 스킬
|
||||
// 1번 직군 기본 스킬
|
||||
{ 4, 1, 31, 61, 91 }, // 1
|
||||
{ 4, 2, 32, 62, 92 }, // 2
|
||||
{ 4, 3, 33, 63, 93 }, // 3
|
||||
|
@ -3150,9 +3150,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
|
|||
{ 4, 6, 36, 66, 96 }, // 6
|
||||
{ 0, 0, 0, 0, 0 }, // 7
|
||||
{ 0, 0, 0, 0, 0 }, // 8
|
||||
// 1번 직군 기본 스킬 끝
|
||||
// 1번 직군 기본 스킬 끝
|
||||
|
||||
// 여유분
|
||||
// 여유분
|
||||
{ 0, 0, 0, 0, 0 }, // 9
|
||||
{ 0, 0, 0, 0, 0 }, // 10
|
||||
{ 0, 0, 0, 0, 0 }, // 11
|
||||
|
@ -3160,9 +3160,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
|
|||
{ 0, 0, 0, 0, 0 }, // 13
|
||||
{ 0, 0, 0, 0, 0 }, // 14
|
||||
{ 0, 0, 0, 0, 0 }, // 15
|
||||
// 여유분 끝
|
||||
// 여유분 끝
|
||||
|
||||
// 2번 직군 기본 스킬
|
||||
// 2번 직군 기본 스킬
|
||||
{ 4, 16, 46, 76, 106 }, // 16
|
||||
{ 4, 17, 47, 77, 107 }, // 17
|
||||
{ 4, 18, 48, 78, 108 }, // 18
|
||||
|
@ -3171,14 +3171,14 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
|
|||
{ 4, 21, 51, 81, 111 }, // 21
|
||||
{ 0, 0, 0, 0, 0 }, // 22
|
||||
{ 0, 0, 0, 0, 0 }, // 23
|
||||
// 2번 직군 기본 스킬 끝
|
||||
// 2번 직군 기본 스킬 끝
|
||||
|
||||
// 여유분
|
||||
// 여유분
|
||||
{ 0, 0, 0, 0, 0 }, // 24
|
||||
{ 0, 0, 0, 0, 0 }, // 25
|
||||
// 여유분 끝
|
||||
// 여유분 끝
|
||||
|
||||
// 1번 직군 마스터 스킬
|
||||
// 1번 직군 마스터 스킬
|
||||
{ 4, 1, 31, 61, 91 }, // 26
|
||||
{ 4, 2, 32, 62, 92 }, // 27
|
||||
{ 4, 3, 33, 63, 93 }, // 28
|
||||
|
@ -3187,9 +3187,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
|
|||
{ 4, 6, 36, 66, 96 }, // 31
|
||||
{ 0, 0, 0, 0, 0 }, // 32
|
||||
{ 0, 0, 0, 0, 0 }, // 33
|
||||
// 1번 직군 마스터 스킬 끝
|
||||
// 1번 직군 마스터 스킬 끝
|
||||
|
||||
// 여유분
|
||||
// 여유분
|
||||
{ 0, 0, 0, 0, 0 }, // 34
|
||||
{ 0, 0, 0, 0, 0 }, // 35
|
||||
{ 0, 0, 0, 0, 0 }, // 36
|
||||
|
@ -3197,9 +3197,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
|
|||
{ 0, 0, 0, 0, 0 }, // 38
|
||||
{ 0, 0, 0, 0, 0 }, // 39
|
||||
{ 0, 0, 0, 0, 0 }, // 40
|
||||
// 여유분 끝
|
||||
// 여유분 끝
|
||||
|
||||
// 2번 직군 마스터 스킬
|
||||
// 2번 직군 마스터 스킬
|
||||
{ 4, 16, 46, 76, 106 }, // 41
|
||||
{ 4, 17, 47, 77, 107 }, // 42
|
||||
{ 4, 18, 48, 78, 108 }, // 43
|
||||
|
@ -3208,14 +3208,14 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
|
|||
{ 4, 21, 51, 81, 111 }, // 46
|
||||
{ 0, 0, 0, 0, 0 }, // 47
|
||||
{ 0, 0, 0, 0, 0 }, // 48
|
||||
// 2번 직군 마스터 스킬 끝
|
||||
// 2번 직군 마스터 스킬 끝
|
||||
|
||||
// 여유분
|
||||
// 여유분
|
||||
{ 0, 0, 0, 0, 0 }, // 49
|
||||
{ 0, 0, 0, 0, 0 }, // 50
|
||||
// 여유분 끝
|
||||
// 여유분 끝
|
||||
|
||||
// 1번 직군 그랜드 마스터 스킬
|
||||
// 1번 직군 그랜드 마스터 스킬
|
||||
{ 4, 1, 31, 61, 91 }, // 51
|
||||
{ 4, 2, 32, 62, 92 }, // 52
|
||||
{ 4, 3, 33, 63, 93 }, // 53
|
||||
|
@ -3224,9 +3224,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
|
|||
{ 4, 6, 36, 66, 96 }, // 56
|
||||
{ 0, 0, 0, 0, 0 }, // 57
|
||||
{ 0, 0, 0, 0, 0 }, // 58
|
||||
// 1번 직군 그랜드 마스터 스킬 끝
|
||||
// 1번 직군 그랜드 마스터 스킬 끝
|
||||
|
||||
// 여유분
|
||||
// 여유분
|
||||
{ 0, 0, 0, 0, 0 }, // 59
|
||||
{ 0, 0, 0, 0, 0 }, // 60
|
||||
{ 0, 0, 0, 0, 0 }, // 61
|
||||
|
@ -3234,9 +3234,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
|
|||
{ 0, 0, 0, 0, 0 }, // 63
|
||||
{ 0, 0, 0, 0, 0 }, // 64
|
||||
{ 0, 0, 0, 0, 0 }, // 65
|
||||
// 여유분 끝
|
||||
// 여유분 끝
|
||||
|
||||
// 2번 직군 그랜드 마스터 스킬
|
||||
// 2번 직군 그랜드 마스터 스킬
|
||||
{ 4, 16, 46, 76, 106 }, // 66
|
||||
{ 4, 17, 47, 77, 107 }, // 67
|
||||
{ 4, 18, 48, 78, 108 }, // 68
|
||||
|
@ -3245,14 +3245,14 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
|
|||
{ 4, 21, 51, 81, 111 }, // 71
|
||||
{ 0, 0, 0, 0, 0 }, // 72
|
||||
{ 0, 0, 0, 0, 0 }, // 73
|
||||
// 2번 직군 그랜드 마스터 스킬 끝
|
||||
// 2번 직군 그랜드 마스터 스킬 끝
|
||||
|
||||
//여유분
|
||||
//여유분
|
||||
{ 0, 0, 0, 0, 0 }, // 74
|
||||
{ 0, 0, 0, 0, 0 }, // 75
|
||||
// 여유분 끝
|
||||
// 여유분 끝
|
||||
|
||||
// 1번 직군 퍼펙트 마스터 스킬
|
||||
// 1번 직군 퍼펙트 마스터 스킬
|
||||
{ 4, 1, 31, 61, 91 }, // 76
|
||||
{ 4, 2, 32, 62, 92 }, // 77
|
||||
{ 4, 3, 33, 63, 93 }, // 78
|
||||
|
@ -3261,9 +3261,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
|
|||
{ 4, 6, 36, 66, 96 }, // 81
|
||||
{ 0, 0, 0, 0, 0 }, // 82
|
||||
{ 0, 0, 0, 0, 0 }, // 83
|
||||
// 1번 직군 퍼펙트 마스터 스킬 끝
|
||||
// 1번 직군 퍼펙트 마스터 스킬 끝
|
||||
|
||||
// 여유분
|
||||
// 여유분
|
||||
{ 0, 0, 0, 0, 0 }, // 84
|
||||
{ 0, 0, 0, 0, 0 }, // 85
|
||||
{ 0, 0, 0, 0, 0 }, // 86
|
||||
|
@ -3271,9 +3271,9 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
|
|||
{ 0, 0, 0, 0, 0 }, // 88
|
||||
{ 0, 0, 0, 0, 0 }, // 89
|
||||
{ 0, 0, 0, 0, 0 }, // 90
|
||||
// 여유분 끝
|
||||
// 여유분 끝
|
||||
|
||||
// 2번 직군 퍼펙트 마스터 스킬
|
||||
// 2번 직군 퍼펙트 마스터 스킬
|
||||
{ 4, 16, 46, 76, 106 }, // 91
|
||||
{ 4, 17, 47, 77, 107 }, // 92
|
||||
{ 4, 18, 48, 78, 108 }, // 93
|
||||
|
@ -3282,23 +3282,23 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
|
|||
{ 4, 21, 51, 81, 111 }, // 96
|
||||
{ 0, 0, 0, 0, 0 }, // 97
|
||||
{ 0, 0, 0, 0, 0 }, // 98
|
||||
// 2번 직군 퍼펙트 마스터 스킬 끝
|
||||
// 2번 직군 퍼펙트 마스터 스킬 끝
|
||||
|
||||
// 여유분
|
||||
// 여유분
|
||||
{ 0, 0, 0, 0, 0 }, // 99
|
||||
{ 0, 0, 0, 0, 0 }, // 100
|
||||
// 여유분 끝
|
||||
// 여유분 끝
|
||||
|
||||
// 길드 스킬
|
||||
// 길드 스킬
|
||||
{ 1, 152, 0, 0, 0}, // 101
|
||||
{ 1, 153, 0, 0, 0}, // 102
|
||||
{ 1, 154, 0, 0, 0}, // 103
|
||||
{ 1, 155, 0, 0, 0}, // 104
|
||||
{ 1, 156, 0, 0, 0}, // 105
|
||||
{ 1, 157, 0, 0, 0}, // 106
|
||||
// 길드 스킬 끝
|
||||
// 길드 스킬 끝
|
||||
|
||||
// 여유분
|
||||
// 여유분
|
||||
{ 0, 0, 0, 0, 0}, // 107
|
||||
{ 0, 0, 0, 0, 0}, // 108
|
||||
{ 0, 0, 0, 0, 0}, // 109
|
||||
|
@ -3313,13 +3313,13 @@ bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
|
|||
{ 0, 0, 0, 0, 0}, // 118
|
||||
{ 0, 0, 0, 0, 0}, // 119
|
||||
{ 0, 0, 0, 0, 0}, // 120
|
||||
// 여유분 끝
|
||||
// 여유분 끝
|
||||
|
||||
// 승마 스킬
|
||||
// 승마 스킬
|
||||
{ 2, 137, 140, 0, 0}, // 121
|
||||
{ 1, 138, 0, 0, 0}, // 122
|
||||
{ 1, 139, 0, 0, 0}, // 123
|
||||
// 승마 스킬 끝
|
||||
// 승마 스킬 끝
|
||||
};
|
||||
|
||||
if (dwMotionIndex >= MOTION_MAX_NUM)
|
||||
|
@ -3473,7 +3473,7 @@ bool CHARACTER::CanUseSkill(DWORD dwSkillVnum) const
|
|||
|
||||
if (true == IsRiding())
|
||||
{
|
||||
//마운트 탈것중 고급말만 스킬 사용가능
|
||||
//마운트 탈것중 고급말만 스킬 사용가능
|
||||
if(GetMountVnum())
|
||||
{
|
||||
if( GetMountVnum() < 20209 && GetMountVnum() > 20212)
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace
|
|||
!pkChr->IsAffectFlag(AFF_WAR_FLAG2) &&
|
||||
!pkChr->IsAffectFlag(AFF_WAR_FLAG3))
|
||||
{
|
||||
// 우리편 깃발일 경우
|
||||
// 우리편 깃발일 경우
|
||||
if ((DWORD) m_pkChr->GetPoint(POINT_STAT) == pkChr->GetGuild()->GetID())
|
||||
{
|
||||
CWarMap * pMap = pkChr->GetWarMap();
|
||||
|
@ -72,8 +72,8 @@ namespace
|
|||
if (!pMap || !pMap->GetTeamIndex(pkChr->GetGuild()->GetID(), idx))
|
||||
return;
|
||||
|
||||
// 우리편 기지에 깃발이 없을 때만 깃발을 뽑는다. 안그러면 기지에 있는 깃발을
|
||||
// 가만히 두고 싶은데도 뽑힐수가 있으므로..
|
||||
// 우리편 기지에 깃발이 없을 때만 깃발을 뽑는다. 안그러면 기지에 있는 깃발을
|
||||
// 가만히 두고 싶은데도 뽑힐수가 있으므로..
|
||||
if (!pMap->IsFlagOnBase(idx))
|
||||
{
|
||||
m_pkChrFind = pkChr;
|
||||
|
@ -82,7 +82,7 @@ namespace
|
|||
}
|
||||
else
|
||||
{
|
||||
// 상대편 깃발인 경우 무조건 뽑는다.
|
||||
// 상대편 깃발인 경우 무조건 뽑는다.
|
||||
m_pkChrFind = pkChr;
|
||||
m_iMinDistance = iDist;
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ namespace
|
|||
//pkChr->RemoveAffect(AFFECT_WAR_FLAG);
|
||||
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("%s 길드가 %s 길드의 깃발을 빼앗았습니다!"), pMap->GetGuild(idx)->GetName(), pMap->GetGuild(idx_opp)->GetName());
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("The guild %s's flag has been stolen by player %s."), pMap->GetGuild(idx)->GetName(), pMap->GetGuild(idx_opp)->GetName());
|
||||
pMap->Notice(buf);
|
||||
}
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ namespace
|
|||
|
||||
LPCHARACTER pkChr = (LPCHARACTER) ent;
|
||||
|
||||
// 일단 PC 공격안함
|
||||
// 일단 PC 공격안함
|
||||
if (pkChr->IsPC())
|
||||
return;
|
||||
|
||||
|
@ -202,7 +202,7 @@ namespace
|
|||
pkChr->IsAffectFlag(AFF_REVIVE_INVISIBLE))
|
||||
return;
|
||||
|
||||
// 왜구는 패스
|
||||
// 왜구는 패스
|
||||
if (pkChr->GetRaceNum() == 5001)
|
||||
return;
|
||||
|
||||
|
@ -285,7 +285,7 @@ void CHARACTER::CowardEscape()
|
|||
for (int iDistIdx = 2; iDistIdx >= 0; --iDistIdx)
|
||||
for (int iTryCount = 0; iTryCount < 8; ++iTryCount)
|
||||
{
|
||||
SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
|
||||
SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
|
||||
|
||||
float fx, fy;
|
||||
float fDist = Random::get(iDist[iDistIdx], iDist[iDistIdx+1]);
|
||||
|
@ -367,7 +367,7 @@ void CHARACTER::StateIdle()
|
|||
}
|
||||
else if (IsWarp() || IsGoto())
|
||||
{
|
||||
// 워프는 이벤트로 처리
|
||||
// 워프는 이벤트로 처리
|
||||
m_dwStateDuration = 60 * passes_per_sec;
|
||||
return;
|
||||
}
|
||||
|
@ -375,7 +375,7 @@ void CHARACTER::StateIdle()
|
|||
if (IsPC())
|
||||
return;
|
||||
|
||||
// NPC 처리
|
||||
// NPC 처리
|
||||
if (!IsMonster())
|
||||
{
|
||||
__StateIdle_NPC();
|
||||
|
@ -506,7 +506,7 @@ void CHARACTER::__StateIdle_NPC()
|
|||
MonsterChat(MONSTER_CHAT_WAIT);
|
||||
m_dwStateDuration = PASSES_PER_SEC(5);
|
||||
|
||||
// 펫 시스템의 Idle 처리는 기존 거의 모든 종류의 캐릭터들이 공유해서 사용하는 상태머신이 아닌 CPetActor::Update에서 처리함.
|
||||
// 펫 시스템의 Idle 처리는 기존 거의 모든 종류의 캐릭터들이 공유해서 사용하는 상태머신이 아닌 CPetActor::Update에서 처리함.
|
||||
if (IsPet())
|
||||
return;
|
||||
else if (IsGuardNPC())
|
||||
|
@ -531,21 +531,21 @@ void CHARACTER::__StateIdle_NPC()
|
|||
}
|
||||
else
|
||||
{
|
||||
if (GetRaceNum() == xmas::MOB_SANTA_VNUM) // 산타
|
||||
if (GetRaceNum() == xmas::MOB_SANTA_VNUM) // 산타
|
||||
{
|
||||
if (get_dword_time() > m_dwPlayStartTime)
|
||||
{
|
||||
int next_warp_time = 2 * 1000; // 2초
|
||||
int next_warp_time = 2 * 1000; // 2초
|
||||
|
||||
m_dwPlayStartTime = get_dword_time() + next_warp_time;
|
||||
|
||||
// 시간이 넘었으니 워프합시다.
|
||||
// 시간이 넘었으니 워프합시다.
|
||||
/*
|
||||
* 산타용
|
||||
* 산타용
|
||||
const int WARP_MAP_INDEX_NUM = 4;
|
||||
static const int c_lWarpMapIndexs[WARP_MAP_INDEX_NUM] = {61, 62, 63, 64};
|
||||
*/
|
||||
// 신선자 노해용
|
||||
// 신선자 노해용
|
||||
const int WARP_MAP_INDEX_NUM = 7;
|
||||
static const int c_lWarpMapIndexs[WARP_MAP_INDEX_NUM] = { 61, 62, 63, 64, 3, 23, 43 };
|
||||
int lNextMapIndex;
|
||||
|
@ -553,7 +553,7 @@ void CHARACTER::__StateIdle_NPC()
|
|||
|
||||
if (map_allow_find(lNextMapIndex))
|
||||
{
|
||||
// 이곳입니다.
|
||||
// 이곳입니다.
|
||||
M2_DESTROY_CHARACTER(this);
|
||||
int iNextSpawnDelay = 0;
|
||||
if (LC_IsYMIR())
|
||||
|
@ -565,7 +565,7 @@ void CHARACTER::__StateIdle_NPC()
|
|||
}
|
||||
else
|
||||
{
|
||||
// 다른 서버 입니다.
|
||||
// 다른 서버 입니다.
|
||||
TPacketGGXmasWarpSanta p;
|
||||
p.bHeader = HEADER_GG_XMAS_WARP_SANTA;
|
||||
p.bChannel = g_bChannel;
|
||||
|
@ -579,7 +579,7 @@ void CHARACTER::__StateIdle_NPC()
|
|||
if (!IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOMOVE))
|
||||
{
|
||||
//
|
||||
// 이 곳 저 곳 이동한다.
|
||||
// 이 곳 저 곳 이동한다.
|
||||
//
|
||||
LPCHARACTER pkChrProtege = GetProtege();
|
||||
|
||||
|
@ -594,14 +594,14 @@ void CHARACTER::__StateIdle_NPC()
|
|||
|
||||
if (!Random::get(0, 6))
|
||||
{
|
||||
SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
|
||||
SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
|
||||
|
||||
float fx, fy;
|
||||
float fDist = Random::get(200, 400);
|
||||
|
||||
GetDeltaByDegree(GetRotation(), fDist, &fx, &fy);
|
||||
|
||||
// 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다.
|
||||
// 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다.
|
||||
if (!(SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx, GetY() + (int) fy)
|
||||
&& SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx / 2, GetY() + (int) fy / 2)))
|
||||
return;
|
||||
|
@ -627,7 +627,7 @@ void CHARACTER::__StateIdle_Monster()
|
|||
|
||||
if (IsCoward())
|
||||
{
|
||||
// 겁쟁이 몬스터는 도망만 다닙니다.
|
||||
// 겁쟁이 몬스터는 도망만 다닙니다.
|
||||
if (!IsDead())
|
||||
CowardEscape();
|
||||
|
||||
|
@ -653,16 +653,16 @@ void CHARACTER::__StateIdle_Monster()
|
|||
|
||||
if (!victim || victim->IsBuilding())
|
||||
{
|
||||
// 돌 보호 처리
|
||||
// 돌 보호 처리
|
||||
if (m_pkChrStone)
|
||||
{
|
||||
victim = m_pkChrStone->GetNearestVictim(m_pkChrStone);
|
||||
}
|
||||
// 선공 몬스터 처리
|
||||
// 선공 몬스터 처리
|
||||
else if (!no_wander && IsAggressive())
|
||||
{
|
||||
if (GetMapIndex() == 61 && quest::CQuestManager::instance().GetEventFlag("xmas_tree"));
|
||||
// 서한산에서 나무가 있으면 선공하지않는다.
|
||||
// 서한산에서 나무가 있으면 선공하지않는다.
|
||||
else
|
||||
victim = FindVictim(this, m_pkMobData->m_table.wAggressiveSight);
|
||||
}
|
||||
|
@ -683,40 +683,40 @@ void CHARACTER::__StateIdle_Monster()
|
|||
|
||||
LPCHARACTER pkChrProtege = GetProtege();
|
||||
|
||||
// 보호할 것(돌, 파티장)에게로 부터 멀다면 따라간다.
|
||||
// 보호할 것(돌, 파티장)에게로 부터 멀다면 따라간다.
|
||||
if (pkChrProtege)
|
||||
{
|
||||
if (DISTANCE_APPROX(GetX() - pkChrProtege->GetX(), GetY() - pkChrProtege->GetY()) > 1000)
|
||||
{
|
||||
if (Follow(pkChrProtege, Random::get(150, 400)))
|
||||
{
|
||||
MonsterLog("[IDLE] 리더로부터 너무 멀리 떨어졌다! 복귀한다.");
|
||||
MonsterLog("[IDLE] You're too far from the leader! Return to the leader.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 그냥 왔다리 갔다리 한다.
|
||||
// 그냥 왔다리 갔다리 한다.
|
||||
//
|
||||
if (!no_wander && !IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOMOVE))
|
||||
{
|
||||
if (!Random::get(0, 6))
|
||||
{
|
||||
SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
|
||||
SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
|
||||
|
||||
float fx, fy;
|
||||
float fDist = Random::get(300, 700);
|
||||
|
||||
GetDeltaByDegree(GetRotation(), fDist, &fx, &fy);
|
||||
|
||||
// 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다.
|
||||
// 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다.
|
||||
if (!(SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx, GetY() + (int) fy)
|
||||
&& SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx/2, GetY() + (int) fy/2)))
|
||||
return;
|
||||
|
||||
// NOTE: 몬스터가 IDLE 상태에서 주변을 서성거릴 때, 현재 무조건 뛰어가게 되어 있음. (절대로 걷지 않음)
|
||||
// 그래픽 팀에서 몬스터가 걷는 모습도 보고싶다고 해서 임시로 특정확률로 걷거나 뛰게 함. (게임의 전반적인 느낌이 틀려지기 때문에 일단 테스트 모드에서만 작동)
|
||||
// NOTE: 몬스터가 IDLE 상태에서 주변을 서성거릴 때, 현재 무조건 뛰어가게 되어 있음. (절대로 걷지 않음)
|
||||
// 그래픽 팀에서 몬스터가 걷는 모습도 보고싶다고 해서 임시로 특정확률로 걷거나 뛰게 함. (게임의 전반적인 느낌이 틀려지기 때문에 일단 테스트 모드에서만 작동)
|
||||
if (g_test_server)
|
||||
{
|
||||
if (Random::get(0, 100) < 60)
|
||||
|
@ -745,13 +745,13 @@ bool __CHARACTER_GotoNearTarget(LPCHARACTER self, LPCHARACTER victim)
|
|||
{
|
||||
case BATTLE_TYPE_RANGE:
|
||||
case BATTLE_TYPE_MAGIC:
|
||||
// 마법사나 궁수는 공격 거리의 80%까지 가서 공격을 시작한다.
|
||||
// 마법사나 궁수는 공격 거리의 80%까지 가서 공격을 시작한다.
|
||||
if (self->Follow(victim, self->GetMobAttackRange() * 8 / 10))
|
||||
return true;
|
||||
break;
|
||||
|
||||
default:
|
||||
// 나머지는 90%?
|
||||
// 나머지는 90%?
|
||||
if (self->Follow(victim, self->GetMobAttackRange() * 9 / 10))
|
||||
return true;
|
||||
}
|
||||
|
@ -781,7 +781,7 @@ void CHARACTER::StateMove()
|
|||
LPCHARACTER victim = GetExchange()->GetCompany()->GetOwner();
|
||||
int iDist = DISTANCE_APPROX(GetX() - victim->GetX(), GetY() - victim->GetY());
|
||||
|
||||
// 거리 체크
|
||||
// 거리 체크
|
||||
if (iDist >= EXCHANGE_MAX_DISTANCE)
|
||||
{
|
||||
GetExchange()->Cancel();
|
||||
|
@ -789,17 +789,17 @@ void CHARACTER::StateMove()
|
|||
}
|
||||
}
|
||||
|
||||
// 스테미나가 0 이상이어야 한다.
|
||||
// 스테미나가 0 이상이어야 한다.
|
||||
if (IsPC())
|
||||
{
|
||||
if (IsWalking() && GetStamina() < GetMaxStamina())
|
||||
{
|
||||
// 5초 후 부터 스테미너 증가
|
||||
// 5초 후 부터 스테미너 증가
|
||||
if (get_dword_time() - GetWalkStartTime() > 5000)
|
||||
PointChange(POINT_STAMINA, GetMaxStamina() / 1);
|
||||
}
|
||||
|
||||
// 전투 중이면서 뛰는 중이면
|
||||
// 전투 중이면서 뛰는 중이면
|
||||
if (!IsWalking() && !IsRiding())
|
||||
if ((get_dword_time() - GetLastAttackTime()) < 20000)
|
||||
{
|
||||
|
@ -817,7 +817,7 @@ void CHARACTER::StateMove()
|
|||
|
||||
if (GetStamina() <= 0)
|
||||
{
|
||||
// 스테미나가 모자라 걸어야함
|
||||
// 스테미나가 모자라 걸어야함
|
||||
SetStamina(0);
|
||||
SetNowWalking(true);
|
||||
StopStaminaConsume();
|
||||
|
@ -838,7 +838,7 @@ void CHARACTER::StateMove()
|
|||
|
||||
if (g_test_server)
|
||||
{
|
||||
// 몬스터가 적을 쫓아가는 것이면 무조건 뛰어간다.
|
||||
// 몬스터가 적을 쫓아가는 것이면 무조건 뛰어간다.
|
||||
SetNowWalking(false);
|
||||
}
|
||||
}
|
||||
|
@ -847,10 +847,10 @@ void CHARACTER::StateMove()
|
|||
{
|
||||
LPCHARACTER victim = GetVictim();
|
||||
|
||||
// 거대 거북
|
||||
// 거대 거북
|
||||
if (GetRaceNum() == 2191 && Random::get(1, 20) == 1 && get_dword_time() - m_pkMobInst->m_dwLastWarpTime > 1000)
|
||||
{
|
||||
// 워프 테스트
|
||||
// 워프 테스트
|
||||
float fx, fy;
|
||||
GetDeltaByDegree(victim->GetRotation(), 400, &fx, &fy);
|
||||
int new_x = victim->GetX() + (int)fx;
|
||||
|
@ -864,7 +864,7 @@ void CHARACTER::StateMove()
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO 방향전환을 해서 덜 바보가 되자!
|
||||
// TODO 방향전환을 해서 덜 바보가 되자!
|
||||
if (Random::get(0, 3) == 0)
|
||||
{
|
||||
if (__CHARACTER_GotoNearTarget(this, victim))
|
||||
|
@ -877,7 +877,7 @@ void CHARACTER::StateMove()
|
|||
{
|
||||
if (IsPC())
|
||||
{
|
||||
SPDLOG_DEBUG("도착 {} {} {}", GetName(), x, y);
|
||||
SPDLOG_DEBUG("Arrival {} {} {}", GetName(), x, y);
|
||||
GotoState(m_stateIdle);
|
||||
StopStaminaConsume();
|
||||
}
|
||||
|
@ -886,7 +886,7 @@ void CHARACTER::StateMove()
|
|||
if (GetVictim() && !IsCoward())
|
||||
{
|
||||
if (!IsState(m_stateBattle))
|
||||
MonsterLog("[BATTLE] 근처에 왔으니 공격시작 %s", GetVictim()->GetName());
|
||||
MonsterLog("[BATTLE] Now that you're nearby, start attacking %s", GetVictim()->GetName());
|
||||
|
||||
GotoState(m_stateBattle);
|
||||
m_dwStateDuration = 1;
|
||||
|
@ -894,7 +894,7 @@ void CHARACTER::StateMove()
|
|||
else
|
||||
{
|
||||
if (!IsState(m_stateIdle))
|
||||
MonsterLog("[IDLE] 대상이 없으니 쉬자");
|
||||
MonsterLog("[IDLE] No target, let's take a break");
|
||||
|
||||
GotoState(m_stateIdle);
|
||||
|
||||
|
@ -1005,7 +1005,7 @@ void CHARACTER::StateBattle()
|
|||
{
|
||||
if (!GetParty())
|
||||
{
|
||||
// 서몬해서 채워둘 파티를 만들어 둡니다.
|
||||
// 서몬해서 채워둘 파티를 만들어 둡니다.
|
||||
CPartyManager::instance().CreateParty(this);
|
||||
}
|
||||
|
||||
|
@ -1014,8 +1014,8 @@ void CHARACTER::StateBattle()
|
|||
|
||||
if (bPct && pParty->CountMemberByVnum(GetSummonVnum()) < SUMMON_MONSTER_COUNT)
|
||||
{
|
||||
MonsterLog("부하 몬스터 소환!");
|
||||
// 모자라는 녀석을 불러내 채웁시다.
|
||||
MonsterLog("Summon Subordinate Monsters!");
|
||||
// 모자라는 녀석을 불러내 채웁시다.
|
||||
int sx = GetX() - 300;
|
||||
int sy = GetY() - 300;
|
||||
int ex = GetX() + 300;
|
||||
|
@ -1035,12 +1035,12 @@ void CHARACTER::StateBattle()
|
|||
|
||||
float fDist = DISTANCE_APPROX(GetX() - victim->GetX(), GetY() - victim->GetY());
|
||||
|
||||
if (fDist >= 4000.0f) // 40미터 이상 멀어지면 포기
|
||||
if (fDist >= 4000.0f) // 40미터 이상 멀어지면 포기
|
||||
{
|
||||
MonsterLog("타겟이 멀어서 포기");
|
||||
MonsterLog("Give up because the target is far away");
|
||||
SetVictim(NULL);
|
||||
|
||||
// 보호할 것(돌, 파티장) 주변으로 간다.
|
||||
// 보호할 것(돌, 파티장) 주변으로 간다.
|
||||
if (pkChrProtege)
|
||||
if (DISTANCE_APPROX(GetX() - pkChrProtege->GetX(), GetY() - pkChrProtege->GetY()) > 1000)
|
||||
Follow(pkChrProtege, Random::get(150, 400));
|
||||
|
@ -1059,7 +1059,7 @@ void CHARACTER::StateBattle()
|
|||
|
||||
if (2493 == m_pkMobData->m_table.dwVnum)
|
||||
{
|
||||
// 수룡(2493) 특수 처리
|
||||
// 수룡(2493) 특수 처리
|
||||
m_dwStateDuration = BlueDragon_StateBattle(this);
|
||||
return;
|
||||
}
|
||||
|
@ -1067,7 +1067,7 @@ void CHARACTER::StateBattle()
|
|||
DWORD dwCurTime = get_dword_time();
|
||||
DWORD dwDuration = CalculateDuration(GetLimitPoint(POINT_ATT_SPEED), 2000);
|
||||
|
||||
if ((dwCurTime - m_dwLastAttackTime) < dwDuration) // 2초 마다 공격해야 한다.
|
||||
if ((dwCurTime - m_dwLastAttackTime) < dwDuration) // 2초 마다 공격해야 한다.
|
||||
{
|
||||
m_dwStateDuration = std::max<int>(1, (passes_per_sec * (dwDuration - (dwCurTime - m_dwLastAttackTime)) / 1000));
|
||||
return;
|
||||
|
@ -1084,7 +1084,7 @@ void CHARACTER::StateBattle()
|
|||
SetGodSpeed(true);
|
||||
|
||||
//
|
||||
// 몹 스킬 처리
|
||||
// 몹 스킬 처리
|
||||
//
|
||||
if (HasMobSkill())
|
||||
{
|
||||
|
@ -1109,11 +1109,11 @@ void CHARACTER::StateBattle()
|
|||
}
|
||||
}
|
||||
|
||||
if (!Attack(victim)) // 공격 실패라면? 왜 실패했지? TODO
|
||||
if (!Attack(victim)) // 공격 실패라면? 왜 실패했지? TODO
|
||||
m_dwStateDuration = passes_per_sec / 2;
|
||||
else
|
||||
{
|
||||
// 적을 바라보게 만든다.
|
||||
// 적을 바라보게 만든다.
|
||||
SetRotationToXY(victim->GetX(), victim->GetY());
|
||||
|
||||
SendMovePacket(FUNC_ATTACK, 0, GetX(), GetY(), 0, dwCurTime);
|
||||
|
@ -1152,7 +1152,7 @@ void CHARACTER::StateFlag()
|
|||
|
||||
pMap->RemoveFlag(idx);
|
||||
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("%s 길드의 깃발을 %s 님이 획득하였습니다."), pMap->GetGuild(idx)->GetName(), f.m_pkChrFind->GetName());
|
||||
snprintf(buf, sizeof(buf), LC_TEXT("%s has captured the flag of %s!"), pMap->GetGuild(idx)->GetName(), f.m_pkChrFind->GetName());
|
||||
pMap->Notice(buf);
|
||||
}
|
||||
|
||||
|
@ -1166,15 +1166,15 @@ void CHARACTER::StateFlagBase()
|
|||
|
||||
void CHARACTER::StateHorse()
|
||||
{
|
||||
float START_FOLLOW_DISTANCE = 400.0f; // 이 거리 이상 떨어지면 쫓아가기 시작함
|
||||
float START_RUN_DISTANCE = 700.0f; // 이 거리 이상 떨어지면 뛰어서 쫓아감.
|
||||
int MIN_APPROACH = 150; // 최소 접근 거리
|
||||
int MAX_APPROACH = 300; // 최대 접근 거리
|
||||
float START_FOLLOW_DISTANCE = 400.0f; // 이 거리 이상 떨어지면 쫓아가기 시작함
|
||||
float START_RUN_DISTANCE = 700.0f; // 이 거리 이상 떨어지면 뛰어서 쫓아감.
|
||||
int MIN_APPROACH = 150; // 최소 접근 거리
|
||||
int MAX_APPROACH = 300; // 최대 접근 거리
|
||||
|
||||
DWORD STATE_DURATION = (DWORD)PASSES_PER_SEC(0.5); // 상태 지속 시간
|
||||
DWORD STATE_DURATION = (DWORD)PASSES_PER_SEC(0.5); // 상태 지속 시간
|
||||
|
||||
bool bDoMoveAlone = true; // 캐릭터와 가까이 있을 때 혼자 여기저기 움직일건지 여부 -_-;
|
||||
bool bRun = true; // 뛰어야 하나?
|
||||
bool bDoMoveAlone = true; // 캐릭터와 가까이 있을 때 혼자 여기저기 움직일건지 여부 -_-;
|
||||
bool bRun = true; // 뛰어야 하나?
|
||||
|
||||
if (IsDead())
|
||||
return;
|
||||
|
@ -1183,7 +1183,7 @@ void CHARACTER::StateHorse()
|
|||
|
||||
LPCHARACTER victim = GetRider();
|
||||
|
||||
// ! 아님 // 대상이 없는 경우 소환자가 직접 나를 클리어할 것임
|
||||
// ! 아님 // 대상이 없는 경우 소환자가 직접 나를 클리어할 것임
|
||||
if (!victim)
|
||||
{
|
||||
M2_DESTROY_CHARACTER(this);
|
||||
|
@ -1197,7 +1197,7 @@ void CHARACTER::StateHorse()
|
|||
if (fDist >= START_FOLLOW_DISTANCE)
|
||||
{
|
||||
if (fDist > START_RUN_DISTANCE)
|
||||
SetNowWalking(!bRun); // NOTE: 함수 이름보고 멈추는건줄 알았는데 SetNowWalking(false) 하면 뛰는거임.. -_-;
|
||||
SetNowWalking(!bRun); // NOTE: 함수 이름보고 멈추는건줄 알았는데 SetNowWalking(false) 하면 뛰는거임.. -_-;
|
||||
|
||||
Follow(victim, Random::get(MIN_APPROACH, MAX_APPROACH));
|
||||
|
||||
|
@ -1208,14 +1208,14 @@ void CHARACTER::StateHorse()
|
|||
// wondering-.-
|
||||
m_dwLastAttackTime = get_dword_time() + Random::get(5000, 12000);
|
||||
|
||||
SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
|
||||
SetRotation(Random::get(0, 359)); // 방향은 랜덤으로 설정
|
||||
|
||||
float fx, fy;
|
||||
float fDist = Random::get(200, 400);
|
||||
|
||||
GetDeltaByDegree(GetRotation(), fDist, &fx, &fy);
|
||||
|
||||
// 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다.
|
||||
// 느슨한 못감 속성 체크; 최종 위치와 중간 위치가 갈수없다면 가지 않는다.
|
||||
if (!(SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx, GetY() + (int) fy)
|
||||
&& SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx/2, GetY() + (int) fy/2)))
|
||||
return;
|
||||
|
|
|
@ -162,7 +162,7 @@ ACMD(do_add_socket);
|
|||
|
||||
ACMD(do_inputall)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("명령어를 모두 입력하세요."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Please enter the Order in full length."));
|
||||
}
|
||||
|
||||
ACMD(do_show_arena_list);
|
||||
|
@ -182,7 +182,7 @@ ACMD(do_effect);
|
|||
ACMD(do_threeway_war_info );
|
||||
ACMD(do_threeway_war_myinfo );
|
||||
//
|
||||
//군주 전용기능
|
||||
//군주 전용기능
|
||||
ACMD(do_monarch_warpto);
|
||||
ACMD(do_monarch_transfer);
|
||||
ACMD(do_monarch_info);
|
||||
|
@ -191,7 +191,7 @@ ACMD(do_monarch_tax);
|
|||
ACMD(do_monarch_mob);
|
||||
ACMD(do_monarch_notice);
|
||||
|
||||
//군주 관리 기능
|
||||
//군주 관리 기능
|
||||
ACMD(do_rmcandidacy);
|
||||
ACMD(do_setmonarch);
|
||||
ACMD(do_rmmonarch);
|
||||
|
@ -199,10 +199,10 @@ ACMD(do_rmmonarch);
|
|||
ACMD(do_hair);
|
||||
//gift notify quest command
|
||||
ACMD(do_gift);
|
||||
// 큐브관련
|
||||
// 큐브관련
|
||||
ACMD(do_inventory);
|
||||
ACMD(do_cube);
|
||||
// 공성전
|
||||
// 공성전
|
||||
ACMD(do_siege);
|
||||
ACMD(do_temp);
|
||||
ACMD(do_frog);
|
||||
|
@ -230,7 +230,7 @@ ACMD(do_ride);
|
|||
ACMD(do_get_item_id_list);
|
||||
ACMD(do_set_socket);
|
||||
#ifdef __AUCTION__
|
||||
// temp_auction 임시
|
||||
// temp_auction 임시
|
||||
ACMD(do_get_auction_list);
|
||||
ACMD (do_get_my_auction_list);
|
||||
ACMD (do_get_my_purchase_list);
|
||||
|
@ -250,21 +250,21 @@ ACMD (do_cancel_sale);
|
|||
ACMD (do_rebid);
|
||||
ACMD (do_bid_cancel);
|
||||
#endif
|
||||
// 코스츔 상태보기 및 벗기
|
||||
// 코스츔 상태보기 및 벗기
|
||||
ACMD(do_costume);
|
||||
ACMD(do_set_stat);
|
||||
|
||||
// 무적
|
||||
// 무적
|
||||
ACMD (do_can_dead);
|
||||
|
||||
ACMD (do_full_set);
|
||||
// 직군과 레벨에 따른 최고 아이템
|
||||
// 직군과 레벨에 따른 최고 아이템
|
||||
ACMD (do_item_full_set);
|
||||
// 직군에 따른 최고 옵션의 속성 셋팅
|
||||
// 직군에 따른 최고 옵션의 속성 셋팅
|
||||
ACMD (do_attr_full_set);
|
||||
// 모든 스킬 마스터
|
||||
// 모든 스킬 마스터
|
||||
ACMD (do_all_skill_master);
|
||||
// 아이템 착용. icon이 없어 클라에서 확인 할 수 없는 아이템 착용을 위해 만듦.
|
||||
// 아이템 착용. icon이 없어 클라에서 확인 할 수 없는 아이템 착용을 위해 만듦.
|
||||
ACMD (do_use_item);
|
||||
ACMD (do_dragon_soul);
|
||||
ACMD (do_ds_list);
|
||||
|
@ -272,7 +272,7 @@ ACMD (do_clear_affect);
|
|||
|
||||
struct command_info cmd_info[] =
|
||||
{
|
||||
{ "!RESERVED!", NULL, 0, POS_DEAD, GM_IMPLEMENTOR }, /* 반드시 이 것이 처음이어야 한다. */
|
||||
{ "!RESERVED!", NULL, 0, POS_DEAD, GM_IMPLEMENTOR }, /* 반드시 이 것이 처음이어야 한다. */
|
||||
{ "who", do_who, 0, POS_DEAD, GM_IMPLEMENTOR },
|
||||
{ "war", do_war, 0, POS_DEAD, GM_PLAYER },
|
||||
{ "warp", do_warp, 0, POS_DEAD, GM_LOW_WIZARD },
|
||||
|
@ -293,7 +293,7 @@ struct command_info cmd_info[] =
|
|||
{ "item", do_item, 0, POS_DEAD, GM_GOD },
|
||||
|
||||
{ "mob", do_mob, 0, POS_DEAD, GM_HIGH_WIZARD },
|
||||
{ "mob_ld", do_mob_ld, 0, POS_DEAD, GM_HIGH_WIZARD }, /* 몹의 위치와 방향을 설정해 소환 /mob_ld vnum x y dir */
|
||||
{ "mob_ld", do_mob_ld, 0, POS_DEAD, GM_HIGH_WIZARD }, /* 몹의 위치와 방향을 설정해 소환 /mob_ld vnum x y dir */
|
||||
{ "ma", do_mob_aggresive, 0, POS_DEAD, GM_HIGH_WIZARD },
|
||||
{ "mc", do_mob_coward, 0, POS_DEAD, GM_HIGH_WIZARD },
|
||||
{ "mm", do_mob_map, 0, POS_DEAD, GM_HIGH_WIZARD },
|
||||
|
@ -391,8 +391,9 @@ struct command_info cmd_info[] =
|
|||
{ "delqf", do_delqf, 0, POS_DEAD, GM_LOW_WIZARD },
|
||||
{ "set_state", do_set_state, 0, POS_DEAD, GM_LOW_WIZARD },
|
||||
|
||||
{ "로그를보여줘", do_detaillog, 0, POS_DEAD, GM_LOW_WIZARD },
|
||||
{ "몬스터보여줘", do_monsterlog, 0, POS_DEAD, GM_LOW_WIZARD },
|
||||
// TODO: these can probably be removed
|
||||
{ "\xB7\xCE\xB1\xD7\xB8\xA6\xBA\xB8\xBF\xA9\xC1\xE0", do_detaillog, 0, POS_DEAD, GM_LOW_WIZARD },
|
||||
{ "\xB8\xF3\xBD\xBA\xC5\xCD\xBA\xB8\xBF\xA9\xC1\xE0", do_monsterlog, 0, POS_DEAD, GM_LOW_WIZARD },
|
||||
|
||||
{ "detaillog", do_detaillog, 0, POS_DEAD, GM_LOW_WIZARD },
|
||||
{ "monsterlog", do_monsterlog, 0, POS_DEAD, GM_LOW_WIZARD },
|
||||
|
@ -528,7 +529,7 @@ struct command_info cmd_info[] =
|
|||
{ "get_mob_count", do_get_mob_count, 0, POS_DEAD, GM_LOW_WIZARD },
|
||||
|
||||
{ "dice", do_dice, 0, POS_DEAD, GM_PLAYER },
|
||||
{ "주사위", do_dice, 0, POS_DEAD, GM_PLAYER },
|
||||
{ "\xC1\xD6\xBB\xE7\xC0\xA7", do_dice, 0, POS_DEAD, GM_PLAYER },
|
||||
{ "special_item", do_special_item, 0, POS_DEAD, GM_IMPLEMENTOR },
|
||||
|
||||
{ "click_mall", do_click_mall, 0, POS_DEAD, GM_PLAYER },
|
||||
|
@ -538,7 +539,7 @@ struct command_info cmd_info[] =
|
|||
{ "item_id_list", do_get_item_id_list, 0, POS_DEAD, GM_LOW_WIZARD },
|
||||
{ "set_socket", do_set_socket, 0, POS_DEAD, GM_LOW_WIZARD },
|
||||
#ifdef __AUCTION__
|
||||
// auction 임시
|
||||
// auction 임시
|
||||
{ "auction_list", do_get_auction_list, 0, POS_DEAD, GM_PLAYER },
|
||||
{ "my_auction_list", do_get_my_auction_list, 0, POS_DEAD, GM_PLAYER },
|
||||
{ "my_purchase_list", do_get_my_purchase_list, 0, POS_DEAD, GM_PLAYER },
|
||||
|
@ -578,7 +579,7 @@ struct command_info cmd_info[] =
|
|||
{ "ds_list", do_ds_list, 0, POS_DEAD, GM_PLAYER },
|
||||
{ "do_clear_affect", do_clear_affect, 0, POS_DEAD, GM_LOW_WIZARD},
|
||||
|
||||
{ "\n", NULL, 0, POS_DEAD, GM_IMPLEMENTOR } /* 반드시 이 것이 마지막이어야 한다. */
|
||||
{ "\n", NULL, 0, POS_DEAD, GM_IMPLEMENTOR } /* 반드시 이 것이 마지막이어야 한다. */
|
||||
};
|
||||
|
||||
void interpreter_set_privilege(const char *cmd, int lvl)
|
||||
|
@ -601,7 +602,7 @@ void double_dollar(const char *src, size_t src_len, char *dest, size_t dest_len)
|
|||
const char * tmp = src;
|
||||
size_t cur_len = 0;
|
||||
|
||||
// \0 넣을 자리 확보
|
||||
// \0 넣을 자리 확보
|
||||
dest_len -= 1;
|
||||
|
||||
while (src_len-- && *tmp)
|
||||
|
@ -636,7 +637,7 @@ void interpret_command(LPCHARACTER ch, const char * argument, size_t len)
|
|||
return ;
|
||||
}
|
||||
|
||||
char cmd[128 + 1]; // buffer overflow 문제가 생기지 않도록 일부러 길이를 짧게 잡음
|
||||
char cmd[128 + 1]; // buffer overflow 문제가 생기지 않도록 일부러 길이를 짧게 잡음
|
||||
char new_line[256 + 1];
|
||||
const char * line;
|
||||
int icmd;
|
||||
|
@ -653,7 +654,7 @@ void interpret_command(LPCHARACTER ch, const char * argument, size_t len)
|
|||
{
|
||||
if (cmd_info[icmd].command_pointer == do_cmd)
|
||||
{
|
||||
if (!strcmp(cmd_info[icmd].command, cmd)) // do_cmd는 모든 명령어를 쳐야 할 수 있다.
|
||||
if (!strcmp(cmd_info[icmd].command, cmd)) // do_cmd는 모든 명령어를 쳐야 할 수 있다.
|
||||
break;
|
||||
}
|
||||
else if (!strncmp(cmd_info[icmd].command, cmd, cmdlen))
|
||||
|
@ -665,24 +666,24 @@ void interpret_command(LPCHARACTER ch, const char * argument, size_t len)
|
|||
switch (ch->GetPosition())
|
||||
{
|
||||
case POS_MOUNTING:
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("탄 상태에서는 할 수 없습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot do this whilst sitting on a Horse."));
|
||||
break;
|
||||
|
||||
case POS_DEAD:
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("쓰러진 상태에서는 할 수 없습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot do that while you are lying on the ground."));
|
||||
break;
|
||||
|
||||
case POS_SLEEPING:
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("꿈속에서 어떻게요?"));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("In my Dreams? What?"));
|
||||
break;
|
||||
|
||||
case POS_RESTING:
|
||||
case POS_SITTING:
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("먼저 일어 나세요."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Get up first."));
|
||||
break;
|
||||
/*
|
||||
case POS_FIGHTING:
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("목숨을 걸고 전투 중 입니다. 집중 하세요."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You're in a fight for your life. Stay focused."));
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
|
@ -695,17 +696,17 @@ void interpret_command(LPCHARACTER ch, const char * argument, size_t len)
|
|||
|
||||
if (*cmd_info[icmd].command == '\n')
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("그런 명령어는 없습니다"));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This command does not exist."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd_info[icmd].gm_level && cmd_info[icmd].gm_level > ch->GetGMLevel())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("그런 명령어는 없습니다"));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This command does not exist."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp("phase", cmd_info[icmd].command, 5) != 0) // 히든 명령어 처리
|
||||
if (strncmp("phase", cmd_info[icmd].command, 5) != 0) // 히든 명령어 처리
|
||||
SPDLOG_DEBUG("COMMAND: {}: {}", ch->GetName(), cmd_info[icmd].command);
|
||||
|
||||
((*cmd_info[icmd].command_pointer) (ch, line, icmd, cmd_info[icmd].subcmd));
|
||||
|
|
|
@ -51,11 +51,11 @@ enum SCMD_XMAS
|
|||
};
|
||||
|
||||
extern void Shutdown(int iSec);
|
||||
extern void SendNotice(const char * c_pszBuf); // 이 게임서버에만 공지
|
||||
extern void SendLog(const char * c_pszBuf); // 운영자에게만 공지
|
||||
extern void BroadcastNotice(const char * c_pszBuf); // 전 서버에 공지
|
||||
extern void SendNoticeMap(const char* c_pszBuf, int nMapIndex, bool bBigFont); // 지정 맵에만 공지
|
||||
extern void SendMonarchNotice(BYTE bEmpire, const char * c_pszBuf); // 같은 제국에게 공지
|
||||
extern void SendNotice(const char * c_pszBuf); // 이 게임서버에만 공지
|
||||
extern void SendLog(const char * c_pszBuf); // 운영자에게만 공지
|
||||
extern void BroadcastNotice(const char * c_pszBuf); // 전 서버에 공지
|
||||
extern void SendNoticeMap(const char* c_pszBuf, int nMapIndex, bool bBigFont); // 지정 맵에만 공지
|
||||
extern void SendMonarchNotice(BYTE bEmpire, const char * c_pszBuf); // 같은 제국에게 공지
|
||||
|
||||
// LUA_ADD_BGM_INFO
|
||||
void CHARACTER_SetBGMVolumeEnable();
|
||||
|
|
|
@ -23,65 +23,65 @@ struct emotion_type_s
|
|||
int flag;
|
||||
float extra_delay;
|
||||
} emotion_types[] = {
|
||||
{ "키스", "french_kiss", NEED_PC | OTHER_SEX_ONLY | BOTH_DISARM, 2.0f },
|
||||
{ "뽀뽀", "kiss", NEED_PC | OTHER_SEX_ONLY | BOTH_DISARM, 1.5f },
|
||||
{ "따귀", "slap", NEED_PC | SELF_DISARM, 1.5f },
|
||||
{ "박수", "clap", 0, 1.0f },
|
||||
{ "와", "cheer1", 0, 1.0f },
|
||||
{ "만세", "cheer2", 0, 1.0f },
|
||||
{ "\xC5\xB0\xBD\xBA", "french_kiss", NEED_PC | OTHER_SEX_ONLY | BOTH_DISARM, 2.0f },
|
||||
{ "\xBB\xC7\xBB\xC7", "kiss", NEED_PC | OTHER_SEX_ONLY | BOTH_DISARM, 1.5f },
|
||||
{ "\xB5\xFB\xB1\xCD", "slap", NEED_PC | SELF_DISARM, 1.5f },
|
||||
{ "\xB9\xDA\xBC\xF6", "clap", 0, 1.0f },
|
||||
{ "\xBF\xCD", "cheer1", 0, 1.0f },
|
||||
{ "\xB8\xB8\xBC\xBC", "cheer2", 0, 1.0f },
|
||||
|
||||
// DANCE
|
||||
{ "댄스1", "dance1", 0, 1.0f },
|
||||
{ "댄스2", "dance2", 0, 1.0f },
|
||||
{ "댄스3", "dance3", 0, 1.0f },
|
||||
{ "댄스4", "dance4", 0, 1.0f },
|
||||
{ "댄스5", "dance5", 0, 1.0f },
|
||||
{ "댄스6", "dance6", 0, 1.0f },
|
||||
{ "\xB4\xED\xBD\xBA\1", "dance1", 0, 1.0f },
|
||||
{ "\xB4\xED\xBD\xBA\2", "dance2", 0, 1.0f },
|
||||
{ "\xB4\xED\xBD\xBA\3", "dance3", 0, 1.0f },
|
||||
{ "\xB4\xED\xBD\xBA\4", "dance4", 0, 1.0f },
|
||||
{ "\xB4\xED\xBD\xBA\5", "dance5", 0, 1.0f },
|
||||
{ "\xB4\xED\xBD\xBA\6", "dance6", 0, 1.0f },
|
||||
// END_OF_DANCE
|
||||
{ "축하", "congratulation", 0, 1.0f },
|
||||
{ "용서", "forgive", 0, 1.0f },
|
||||
{ "화남", "angry", 0, 1.0f },
|
||||
{ "유혹", "attractive", 0, 1.0f },
|
||||
{ "슬픔", "sad", 0, 1.0f },
|
||||
{ "브끄", "shy", 0, 1.0f },
|
||||
{ "응원", "cheerup", 0, 1.0f },
|
||||
{ "질투", "banter", 0, 1.0f },
|
||||
{ "기쁨", "joy", 0, 1.0f },
|
||||
{ "\xC3\xE0\xC7\xCF", "congratulation", 0, 1.0f },
|
||||
{ "\xBF\xEB\xBC\xAD", "forgive", 0, 1.0f },
|
||||
{ "\xC8\xAD\xB3\xB2", "angry", 0, 1.0f },
|
||||
{ "\xC0\xAF\xC8\xA4", "attractive", 0, 1.0f },
|
||||
{ "\xBD\xBD\xC7\xC4", "sad", 0, 1.0f },
|
||||
{ "\xBA\xEA\xB2\xF4", "shy", 0, 1.0f },
|
||||
{ "\xC0\xC0\xBF\xF8", "cheerup", 0, 1.0f },
|
||||
{ "\xC1\xFA\xC5\xF5", "banter", 0, 1.0f },
|
||||
{ "\xB1\xE2\xBB\xDD", "joy", 0, 1.0f },
|
||||
{ "\n", "\n", 0, 0.0f },
|
||||
/*
|
||||
//{ "키스", NEED_PC | OTHER_SEX_ONLY | BOTH_DISARM, MOTION_ACTION_FRENCH_KISS, 1.0f },
|
||||
{ "뽀뽀", NEED_PC | OTHER_SEX_ONLY | BOTH_DISARM, MOTION_ACTION_KISS, 1.0f },
|
||||
{ "껴안기", NEED_PC | OTHER_SEX_ONLY | BOTH_DISARM, MOTION_ACTION_SHORT_HUG, 1.0f },
|
||||
{ "포옹", NEED_PC | OTHER_SEX_ONLY | BOTH_DISARM, MOTION_ACTION_LONG_HUG, 1.0f },
|
||||
{ "어깨동무", NEED_PC | SELF_DISARM, MOTION_ACTION_PUT_ARMS_SHOULDER, 0.0f },
|
||||
{ "팔짱", NEED_PC | WOMAN_ONLY | SELF_DISARM, MOTION_ACTION_FOLD_ARM, 0.0f },
|
||||
{ "따귀", NEED_PC | SELF_DISARM, MOTION_ACTION_SLAP, 1.5f },
|
||||
//{ "\xC5\xB0\xBD\xBA", NEED_PC | OTHER_SEX_ONLY | BOTH_DISARM, MOTION_ACTION_FRENCH_KISS, 1.0f },
|
||||
{ "\xBB\xC7\xBB\xC7", NEED_PC | OTHER_SEX_ONLY | BOTH_DISARM, MOTION_ACTION_KISS, 1.0f },
|
||||
{ "\xB2\xB8\xBE\xC8\xB1\xE2", NEED_PC | OTHER_SEX_ONLY | BOTH_DISARM, MOTION_ACTION_SHORT_HUG, 1.0f },
|
||||
{ "\xC6\xF7\xBF\xCB", NEED_PC | OTHER_SEX_ONLY | BOTH_DISARM, MOTION_ACTION_LONG_HUG, 1.0f },
|
||||
{ "\xBE\xEE\xB1\xFA\xB5\xBF\xB9\xAB", NEED_PC | SELF_DISARM, MOTION_ACTION_PUT_ARMS_SHOULDER, 0.0f },
|
||||
{ "\xC6\xC8\xC2\xAF", NEED_PC | WOMAN_ONLY | SELF_DISARM, MOTION_ACTION_FOLD_ARM, 0.0f },
|
||||
{ "\xB5\xFB\xB1\xCD", NEED_PC | SELF_DISARM, MOTION_ACTION_SLAP, 1.5f },
|
||||
|
||||
{ "휘파람", 0, MOTION_ACTION_CHEER_01, 0.0f },
|
||||
{ "만세", 0, MOTION_ACTION_CHEER_02, 0.0f },
|
||||
{ "박수", 0, MOTION_ACTION_CHEER_03, 0.0f },
|
||||
{ "\xC8\xD6\xC6\xC4\xB6\xF7", 0, MOTION_ACTION_CHEER_01, 0.0f },
|
||||
{ "\xB8\xB8\xBC\xBC", 0, MOTION_ACTION_CHEER_02, 0.0f },
|
||||
{ "\xB9\xDA\xBC\xF6", 0, MOTION_ACTION_CHEER_03, 0.0f },
|
||||
|
||||
{ "호호", 0, MOTION_ACTION_LAUGH_01, 0.0f },
|
||||
{ "킥킥", 0, MOTION_ACTION_LAUGH_02, 0.0f },
|
||||
{ "우하하", 0, MOTION_ACTION_LAUGH_03, 0.0f },
|
||||
{ "\xC8\xA3\xC8\xA3", 0, MOTION_ACTION_LAUGH_01, 0.0f },
|
||||
{ "\xC5\xB1\xC5\xB1", 0, MOTION_ACTION_LAUGH_02, 0.0f },
|
||||
{ "\xBF\xEC\xC7\xCF\xC7\xCF", 0, MOTION_ACTION_LAUGH_03, 0.0f },
|
||||
|
||||
{ "엉엉", 0, MOTION_ACTION_CRY_01, 0.0f },
|
||||
{ "흑흑", 0, MOTION_ACTION_CRY_02, 0.0f },
|
||||
{ "\xBE\xFB\xBE\xFB", 0, MOTION_ACTION_CRY_01, 0.0f },
|
||||
{ "\xC8\xE6\xC8\xE6", 0, MOTION_ACTION_CRY_02, 0.0f },
|
||||
|
||||
{ "인사", 0, MOTION_ACTION_GREETING_01, 0.0f },
|
||||
{ "바이", 0, MOTION_ACTION_GREETING_02, 0.0f },
|
||||
{ "정중인사", 0, MOTION_ACTION_GREETING_03, 0.0f },
|
||||
{ "\xC0\xCE\xBB\xE7", 0, MOTION_ACTION_GREETING_01, 0.0f },
|
||||
{ "\xB9\xD9\xC0\xCC", 0, MOTION_ACTION_GREETING_02, 0.0f },
|
||||
{ "\xC1\xA4\xC1\xDF\xC0\xCE\xBB\xE7", 0, MOTION_ACTION_GREETING_03, 0.0f },
|
||||
|
||||
{ "비난", 0, MOTION_ACTION_INSULT_01, 0.0f },
|
||||
{ "모욕", SELF_DISARM, MOTION_ACTION_INSULT_02, 0.0f },
|
||||
{ "우웩", 0, MOTION_ACTION_INSULT_03, 0.0f },
|
||||
{ "\xBA\xF1\xB3\xAD", 0, MOTION_ACTION_INSULT_01, 0.0f },
|
||||
{ "\xB8\xF0\xBF\xE5", SELF_DISARM, MOTION_ACTION_INSULT_02, 0.0f },
|
||||
{ "\xBF\xEC\xC0\xA1", 0, MOTION_ACTION_INSULT_03, 0.0f },
|
||||
|
||||
{ "갸우뚱", 0, MOTION_ACTION_ETC_01, 0.0f },
|
||||
{ "끄덕끄덕", 0, MOTION_ACTION_ETC_02, 0.0f },
|
||||
{ "도리도리", 0, MOTION_ACTION_ETC_03, 0.0f },
|
||||
{ "긁적긁적", 0, MOTION_ACTION_ETC_04, 0.0f },
|
||||
{ "퉤", 0, MOTION_ACTION_ETC_05, 0.0f },
|
||||
{ "뿡", 0, MOTION_ACTION_ETC_06, 0.0f },
|
||||
{ "\xB0\xBC\xBF\xEC\xB6\xD7", 0, MOTION_ACTION_ETC_01, 0.0f },
|
||||
{ "\xB2\xF4\xB4\xF6\xB2\xF4\xB4\xF6", 0, MOTION_ACTION_ETC_02, 0.0f },
|
||||
{ "\xB5\xB5\xB8\xAE\xB5\xB5\xB8\xAE", 0, MOTION_ACTION_ETC_03, 0.0f },
|
||||
{ "\xB1\xDC\xC0\xFB\xB1\xDC\xC0\xFB", 0, MOTION_ACTION_ETC_04, 0.0f },
|
||||
{ "\xC6\xA1", 0, MOTION_ACTION_ETC_05, 0.0f },
|
||||
{ "\xBB\xD7", 0, MOTION_ACTION_ETC_06, 0.0f },
|
||||
*/
|
||||
};
|
||||
|
||||
|
@ -92,7 +92,7 @@ ACMD(do_emotion_allow)
|
|||
{
|
||||
if ( ch->GetArena() )
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련장에서 사용하실 수 없습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot use this in the duel arena."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -108,11 +108,11 @@ ACMD(do_emotion_allow)
|
|||
|
||||
bool CHARACTER_CanEmotion(CHARACTER& rch)
|
||||
{
|
||||
// 결혼식 맵에서는 사용할 수 있다.
|
||||
// 결혼식 맵에서는 사용할 수 있다.
|
||||
if (marriage::WeddingManager::instance().IsWeddingMap(rch.GetMapIndex()))
|
||||
return true;
|
||||
|
||||
// 열정의 가면 착용시 사용할 수 있다.
|
||||
// 열정의 가면 착용시 사용할 수 있다.
|
||||
if (rch.IsEquipUniqueItem(UNIQUE_ITEM_EMOTION_MASK))
|
||||
return true;
|
||||
|
||||
|
@ -128,7 +128,7 @@ ACMD(do_emotion)
|
|||
{
|
||||
if (ch->IsRiding())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말을 탄 상태에서 감정표현을 할 수 없습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot express emotions whilst riding a horse."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -150,13 +150,13 @@ ACMD(do_emotion)
|
|||
|
||||
if (!CHARACTER_CanEmotion(*ch))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("열정의 가면을 착용시에만 할 수 있습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can do this when you wear an Emotion Mask."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_SET(emotion_types[i].flag, WOMAN_ONLY) && SEX_MALE==GET_SEX(ch))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("여자만 할 수 있습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Only women can do this."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ ACMD(do_emotion)
|
|||
{
|
||||
if (!victim)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("그런 사람이 없습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This person does not exist."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ ACMD(do_emotion)
|
|||
|
||||
if (victim->IsRiding())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말을 탄 상대와 감정표현을 할 수 없습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot use emotions with a player who is riding on a Horse."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -192,13 +192,13 @@ ACMD(do_emotion)
|
|||
|
||||
if (distance < 10)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("너무 가까이 있습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You are too near."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (distance > 500)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("너무 멀리 있습니다"));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You are too far away."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -206,7 +206,7 @@ ACMD(do_emotion)
|
|||
{
|
||||
if (GET_SEX(ch)==GET_SEX(victim))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("이성간에만 할 수 있습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This action can only be done with another gender."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -223,13 +223,13 @@ ACMD(do_emotion)
|
|||
|
||||
if (0 == other || other != victim->GetPlayerID())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("이 행동은 상호동의 하에 가능 합니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You need your fellow player's approval for this."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("이 행동은 상호동의 하에 가능 합니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You need your fellow player's approval for this."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ ACMD(do_emotion)
|
|||
if (len < 0 || len >= (int) sizeof(chatbuf))
|
||||
len = sizeof(chatbuf) - 1;
|
||||
|
||||
++len; // \0 문자 포함
|
||||
++len; // \0 문자 포함
|
||||
|
||||
TPacketGCChat pack_chat;
|
||||
pack_chat.header = HEADER_GC_CHAT;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -261,44 +261,44 @@ bool CHARACTER_GoToName(LPCHARACTER ch, BYTE empire, int mapIndex, const char* g
|
|||
|
||||
/*
|
||||
= {
|
||||
{ "A1|영안읍성", 0, 1, 4693, 9642 },
|
||||
{ "A3|자양현", 0, 3, 3608, 8776 },
|
||||
{ "A1|\xBF\xB5\xBE\xC8\xC0\xBE\xBC\xBA", 0, 1, 4693, 9642 },
|
||||
{ "A3|\xC0\xDA\xBE\xE7\xC7\xF6", 0, 3, 3608, 8776 },
|
||||
|
||||
{ "B1|조안읍성", 0, 21, 557, 1579 },
|
||||
{ "B3|복정현", 0, 23, 1385, 2349 },
|
||||
{ "B1|\xC1\xB6\xBE\xC8\xC0\xBE\xBC\xBA", 0, 21, 557, 1579 },
|
||||
{ "B3|\xBA\xB9\xC1\xA4\xC7\xF6", 0, 23, 1385, 2349 },
|
||||
|
||||
{ "C1|평무읍성", 0, 41, 9696, 2784 },
|
||||
{ "C3|박라현", 0, 43, 8731, 2426 },
|
||||
{ "C1|\xC6\xF2\xB9\xAB\xC0\xBE\xBC\xBA", 0, 41, 9696, 2784 },
|
||||
{ "C3|\xB9\xDA\xB6\xF3\xC7\xF6", 0, 43, 8731, 2426 },
|
||||
|
||||
// Snow
|
||||
{ "Snow|서한산", 1, 61, 4342, 2906 },
|
||||
{ "Snow|서한산", 2, 61, 3752, 1749 },
|
||||
{ "Snow|서한산", 3, 61, 4918, 1736 },
|
||||
{ "Snow|\xBC\xAD\xC7\xD1\xBB\xEA", 1, 61, 4342, 2906 },
|
||||
{ "Snow|\xBC\xAD\xC7\xD1\xBB\xEA", 2, 61, 3752, 1749 },
|
||||
{ "Snow|\xBC\xAD\xC7\xD1\xBB\xEA", 3, 61, 4918, 1736 },
|
||||
|
||||
// Flame
|
||||
{ "Flame|도염화지|화염", 1, 62, 5994, 7563 },
|
||||
{ "Flame|도염화지|화염", 2, 62, 5978, 6222 },
|
||||
{ "Flame|도염화지|화염", 3, 62, 7307, 6898 },
|
||||
{ "Flame|\xB5\xB5\xBF\xB0\xC8\xAD\xC1\xF6|\xC8\xAD\xBF\xB0", 1, 62, 5994, 7563 },
|
||||
{ "Flame|\xB5\xB5\xBF\xB0\xC8\xAD\xC1\xF6|\xC8\xAD\xBF\xB0", 2, 62, 5978, 6222 },
|
||||
{ "Flame|\xB5\xB5\xBF\xB0\xC8\xAD\xC1\xF6|\xC8\xAD\xBF\xB0", 3, 62, 7307, 6898 },
|
||||
|
||||
// Desert
|
||||
{ "Desert|영비사막|사막", 1, 63, 2178, 6272 },
|
||||
{ "Desert|영비사막|사막", 2, 63, 2219, 5027 },
|
||||
{ "Desert|영비사막|사막", 3, 63, 3440, 5025 },
|
||||
{ "Desert|\xBF\xB5\xBA\xF1\xBB\xE7\xB8\xB7|\xBB\xE7\xB8\xB7", 1, 63, 2178, 6272 },
|
||||
{ "Desert|\xBF\xB5\xBA\xF1\xBB\xE7\xB8\xB7|\xBB\xE7\xB8\xB7", 2, 63, 2219, 5027 },
|
||||
{ "Desert|\xBF\xB5\xBA\xF1\xBB\xE7\xB8\xB7|\xBB\xE7\xB8\xB7", 3, 63, 3440, 5025 },
|
||||
|
||||
// Threeway
|
||||
{ "Three|승룡곡", 1, 64, 4021, 6739 },
|
||||
{ "Three|승룡곡", 2, 64, 2704, 7399 },
|
||||
{ "Three|승룡곡", 3, 64, 3213, 8080 },
|
||||
{ "Three|\xBD\xC2\xB7\xE6\xB0\xEE", 1, 64, 4021, 6739 },
|
||||
{ "Three|\xBD\xC2\xB7\xE6\xB0\xEE", 2, 64, 2704, 7399 },
|
||||
{ "Three|\xBD\xC2\xB7\xE6\xB0\xEE", 3, 64, 3213, 8080 },
|
||||
|
||||
// 밀교사원
|
||||
{ "Milgyo|밀교사원", 1, 65, 5536, 1436 },
|
||||
{ "Milgyo|밀교사원", 2, 65, 5536, 1436 },
|
||||
{ "Milgyo|밀교사원", 3, 65, 5536, 1436 },
|
||||
// 밀교사원
|
||||
{ "Milgyo|\xB9\xD0\xB1\xB3\xBB\xE7\xBF\xF8", 1, 65, 5536, 1436 },
|
||||
{ "Milgyo|\xB9\xD0\xB1\xB3\xBB\xE7\xBF\xF8", 2, 65, 5536, 1436 },
|
||||
{ "Milgyo|\xB9\xD0\xB1\xB3\xBB\xE7\xBF\xF8", 3, 65, 5536, 1436 },
|
||||
|
||||
// 사귀타워입구
|
||||
{ "사귀타워입구", 1, 65, 5905, 1108 },
|
||||
{ "사귀타워입구", 2, 65, 5905, 1108 },
|
||||
{ "사귀타워입구", 3, 65, 5905, 1108 },
|
||||
// 사귀타워입구
|
||||
{ "\xBB\xE7\xB1\xCD\xC5\xB8\xBF\xF6\xC0\xD4\xB1\xB8", 1, 65, 5905, 1108 },
|
||||
{ "\xBB\xE7\xB1\xCD\xC5\xB8\xBF\xF6\xC0\xD4\xB1\xB8", 2, 65, 5905, 1108 },
|
||||
{ "\xBB\xE7\xB1\xCD\xC5\xB8\xBF\xF6\xC0\xD4\xB1\xB8", 3, 65, 5905, 1108 },
|
||||
|
||||
{ NULL, 0, 0, 0, 0 },
|
||||
};
|
||||
|
@ -500,7 +500,7 @@ ACMD(do_item)
|
|||
M2_DESTROY_ITEM(item);
|
||||
if (!ch->DragonSoul_IsQualified())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "인벤이 활성화 되지 않음.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "Before you open the Cor Draconis, you have to complete the Dragon Stone quest and activate the Dragon Stone Alchemy.");
|
||||
}
|
||||
else
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "Not enough inventory space.");
|
||||
|
@ -841,7 +841,7 @@ struct FuncPurge
|
|||
|
||||
int iDist = DISTANCE_APPROX(pkChr->GetX() - m_pkGM->GetX(), pkChr->GetY() - m_pkGM->GetY());
|
||||
|
||||
if (!m_bAll && iDist >= 1000) // 10미터 이상에 있는 것들은 purge 하지 않는다.
|
||||
if (!m_bAll && iDist >= 1000) // 10미터 이상에 있는 것들은 purge 하지 않는다.
|
||||
return;
|
||||
|
||||
SPDLOG_DEBUG("PURGE: {} {}", pkChr->GetName(), iDist);
|
||||
|
@ -1215,7 +1215,7 @@ ACMD(do_monarch_notice)
|
|||
}
|
||||
else
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주만이 사용 가능한 기능입니다"));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This function can only be used by the emperor."));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1555,12 +1555,12 @@ ACMD(do_makeguild)
|
|||
|
||||
if (!check_name(cp.name))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("적합하지 않은 길드 이름 입니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This guild name is invalid."));
|
||||
return;
|
||||
}
|
||||
|
||||
gm.CreateGuild(cp);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("(%s) 길드가 생성되었습니다. [임시]"), cp.name);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("(%s) guild has been created. [Temporary]"), cp.name);
|
||||
}
|
||||
|
||||
ACMD(do_deleteguild)
|
||||
|
@ -1765,7 +1765,7 @@ LPCHARACTER chHori, chForge, chLib, chTemple, chTraining, chTree, chPortal, chBa
|
|||
|
||||
ACMD(do_b1)
|
||||
{
|
||||
//호리병 478 579
|
||||
//호리병 478 579
|
||||
chHori = CHARACTER_MANAGER::instance().SpawnMobRange(14017, ch->GetMapIndex(), 304222, 742858, 304222, 742858, true, false);
|
||||
chHori->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_BUILDING_CONSTRUCTION_SMALL, 65535, 0, true);
|
||||
chHori->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
|
||||
|
@ -1812,25 +1812,25 @@ ACMD(do_b2)
|
|||
|
||||
ACMD(do_b3)
|
||||
{
|
||||
// 포지 492 547
|
||||
// 포지 492 547
|
||||
chForge = CHARACTER_MANAGER::instance().SpawnMobRange(14003, ch->GetMapIndex(), 307500, 746300, 307500, 746300, true, false);
|
||||
chForge->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
|
||||
//높은탑 509 589 -> 도서관
|
||||
//높은탑 509 589 -> 도서관
|
||||
chLib = CHARACTER_MANAGER::instance().SpawnMobRange(14007, ch->GetMapIndex(), 307900, 744500, 307900, 744500, true, false);
|
||||
chLib->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
|
||||
//욕조 513 606 -> 힘의신전
|
||||
//욕조 513 606 -> 힘의신전
|
||||
chTemple = CHARACTER_MANAGER::instance().SpawnMobRange(14004, ch->GetMapIndex(), 307700, 741600, 307700, 741600, true, false);
|
||||
chTemple->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
|
||||
//권투장 490 625
|
||||
//권투장 490 625
|
||||
chTraining= CHARACTER_MANAGER::instance().SpawnMobRange(14010, ch->GetMapIndex(), 307100, 739500, 307100, 739500, true, false);
|
||||
chTraining->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
|
||||
//나무 466 614
|
||||
//나무 466 614
|
||||
chTree= CHARACTER_MANAGER::instance().SpawnMobRange(14013, ch->GetMapIndex(), 300800, 741600, 300800, 741600, true, false);
|
||||
chTree->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
|
||||
//포탈 439 615
|
||||
//포탈 439 615
|
||||
chPortal= CHARACTER_MANAGER::instance().SpawnMobRange(14001, ch->GetMapIndex(), 300900, 744500, 300900, 744500, true, false);
|
||||
chPortal->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
|
||||
// 구슬 436 600
|
||||
// 구슬 436 600
|
||||
chBall = CHARACTER_MANAGER::instance().SpawnMobRange(14012, ch->GetMapIndex(), 302500, 746600, 302500, 746600, true, false);
|
||||
chBall->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
|
||||
}
|
||||
|
@ -2069,7 +2069,7 @@ ACMD(do_reload)
|
|||
break;
|
||||
//END_RELOAD_ADMIN
|
||||
case 'c': // cube
|
||||
// 로컬 프로세스만 갱산한다.
|
||||
// 로컬 프로세스만 갱산한다.
|
||||
Cube_init ();
|
||||
break;
|
||||
}
|
||||
|
@ -2110,7 +2110,7 @@ ACMD(do_level)
|
|||
|
||||
ACMD(do_gwlist)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("현재 전쟁중인 길드 입니다"));
|
||||
ch->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("This guild is at war."));
|
||||
CGuildManager::instance().ShowGuildWarList(ch);
|
||||
}
|
||||
|
||||
|
@ -2168,7 +2168,7 @@ ACMD(do_guild_state)
|
|||
}
|
||||
else
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s: 존재하지 않는 길드 입니다."), arg1);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s: This guild does not exist."), arg1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2190,7 +2190,7 @@ struct FuncWeaken
|
|||
|
||||
int iDist = DISTANCE_APPROX(pkChr->GetX() - m_pkGM->GetX(), pkChr->GetY() - m_pkGM->GetY());
|
||||
|
||||
if (!m_bAll && iDist >= 1000) // 10미터 이상에 있는 것들은 purge 하지 않는다.
|
||||
if (!m_bAll && iDist >= 1000) // 10미터 이상에 있는 것들은 purge 하지 않는다.
|
||||
return;
|
||||
|
||||
if (pkChr->IsNPC())
|
||||
|
@ -2472,7 +2472,7 @@ ACMD(do_priv_empire)
|
|||
if (duration < 0)
|
||||
goto USAGE;
|
||||
|
||||
// 시간 단위로 변경
|
||||
// 시간 단위로 변경
|
||||
duration = duration * (60*60);
|
||||
|
||||
SPDLOG_DEBUG("_give_empire_privileage(empire={}, type={}, value={}, duration={}) by command",
|
||||
|
@ -2576,10 +2576,10 @@ ACMD(do_xmas)
|
|||
// BLOCK_CHAT
|
||||
ACMD(do_block_chat_list)
|
||||
{
|
||||
// GM이 아니거나 block_chat_privilege가 없는 사람은 명령어 사용 불가
|
||||
// GM이 아니거나 block_chat_privilege가 없는 사람은 명령어 사용 불가
|
||||
if (!ch || (ch->GetGMLevel() < GM_HIGH_WIZARD && ch->GetQuestFlag("chat_privilege.block") <= 0))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("그런 명령어는 없습니다"));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This command does not exist."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2642,10 +2642,10 @@ ACMD(do_vote_block_chat)
|
|||
|
||||
ACMD(do_block_chat)
|
||||
{
|
||||
// GM이 아니거나 block_chat_privilege가 없는 사람은 명령어 사용 불가
|
||||
// GM이 아니거나 block_chat_privilege가 없는 사람은 명령어 사용 불가
|
||||
if (ch && (ch->GetGMLevel() < GM_HIGH_WIZARD && ch->GetQuestFlag("chat_privilege.block") <= 0))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("그런 명령어는 없습니다"));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This command does not exist."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2667,8 +2667,8 @@ ACMD(do_block_chat)
|
|||
{
|
||||
if (ch)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "잘못된 형식의 시간입니다. h, m, s를 붙여서 지정해 주십시오.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "예) 10s, 10m, 1m 30s");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "The time is incorrectly formatted. Please specify it with an h, m, or s.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "Example) 10s, 10m, 1m 30s");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -2721,8 +2721,8 @@ ACMD(do_build)
|
|||
|
||||
CLand * pkLand = CManager::instance().FindLand(ch->GetMapIndex(), ch->GetX(), ch->GetY());
|
||||
|
||||
// NOTE: 조건 체크들은 클라이언트와 서버가 함께 하기 때문에 문제가 있을 때는
|
||||
// 메세지를 전송하지 않고 에러를 출력한다.
|
||||
// NOTE: 조건 체크들은 클라이언트와 서버가 함께 하기 때문에 문제가 있을 때는
|
||||
// 메세지를 전송하지 않고 에러를 출력한다.
|
||||
if (!pkLand)
|
||||
{
|
||||
SPDLOG_ERROR("{} trying to build on not buildable area.", ch->GetName());
|
||||
|
@ -2735,17 +2735,17 @@ ACMD(do_build)
|
|||
return;
|
||||
}
|
||||
|
||||
// 건설 권한 체크
|
||||
// 건설 권한 체크
|
||||
if (GMLevel == GM_PLAYER)
|
||||
{
|
||||
// 플레이어가 집을 지을 때는 땅이 내껀지 확인해야 한다.
|
||||
// 플레이어가 집을 지을 때는 땅이 내껀지 확인해야 한다.
|
||||
if ((!ch->GetGuild() || ch->GetGuild()->GetID() != pkLand->GetOwner()))
|
||||
{
|
||||
SPDLOG_ERROR("{} trying to build on not owned land.", ch->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
// 내가 길마인가?
|
||||
// 내가 길마인가?
|
||||
if (ch->GetGuild()->GetMasterPID() != ch->GetPlayerID())
|
||||
{
|
||||
SPDLOG_ERROR("{} trying to build while not the guild master.", ch->GetName());
|
||||
|
@ -2776,7 +2776,7 @@ ACMD(do_build)
|
|||
const TObjectProto * t = CManager::instance().GetObjectProto(dwVnum);
|
||||
if (!t)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("존재하지 않는 건물입니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The building does not exist."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2786,21 +2786,21 @@ ACMD(do_build)
|
|||
{
|
||||
if (pkLand->FindObjectByGroup(t->dwGroupVnum))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("같이 지을 수 없는 종류의 건물이 지어져 있습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This type of building can only be erected once."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 건물 종속성 체크 (이 건물이 지어져 있어야함)
|
||||
// 건물 종속성 체크 (이 건물이 지어져 있어야함)
|
||||
if (t->dwDependOnGroupVnum)
|
||||
{
|
||||
// const TObjectProto * dependent = CManager::instance().GetObjectProto(dwVnum);
|
||||
// if (dependent)
|
||||
{
|
||||
// 지어져있는가?
|
||||
// 지어져있는가?
|
||||
if (!pkLand->FindObjectByGroup(t->dwDependOnGroupVnum))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("건설에 필요한 건물이 지어져 있지 않습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The Main Building has to be erected first."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2808,21 +2808,21 @@ ACMD(do_build)
|
|||
|
||||
if (test_server || GMLevel == GM_PLAYER)
|
||||
{
|
||||
// GM이 아닐경우만 (테섭에서는 GM도 소모)
|
||||
// 건설 비용 체크
|
||||
// GM이 아닐경우만 (테섭에서는 GM도 소모)
|
||||
// 건설 비용 체크
|
||||
if (t->dwPrice > BUILDING_MAX_PRICE)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("건물 비용 정보 이상으로 건설 작업에 실패했습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Building failed because of incorrect pricing."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch->GetGold() < (int)t->dwPrice)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("건설 비용이 부족합니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Your guild does not have enough Yang to erect this building."));
|
||||
return;
|
||||
}
|
||||
|
||||
// 아이템 자재 개수 체크
|
||||
// 아이템 자재 개수 체크
|
||||
|
||||
int i;
|
||||
for (i = 0; i < OBJECT_MATERIAL_MAX_NUM; ++i)
|
||||
|
@ -2835,7 +2835,7 @@ ACMD(do_build)
|
|||
|
||||
if ((int) dwItemCount > ch->CountSpecifyItem(dwItemVnum))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("자재가 부족하여 건설할 수 없습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You do not have enough resources to build a building."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2844,11 +2844,11 @@ ACMD(do_build)
|
|||
float x_rot = atof(arg4);
|
||||
float y_rot = atof(arg5);
|
||||
float z_rot = atof(arg6);
|
||||
// 20050811.myevan.건물 회전 기능 봉인 해제
|
||||
// 20050811.myevan.건물 회전 기능 봉인 해제
|
||||
/*
|
||||
if (x_rot != 0.0f || y_rot != 0.0f || z_rot != 0.0f)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "건물 회전 기능은 아직 제공되지 않습니다");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "Rotating buildings is not yet available");
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
@ -2869,17 +2869,17 @@ ACMD(do_build)
|
|||
if (!isSuccess)
|
||||
{
|
||||
if (test_server)
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("건물을 지을 수 없는 위치입니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot erect a building at this place."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (test_server || GMLevel == GM_PLAYER)
|
||||
// 건설 재료 소모하기 (테섭에서는 GM도 소모)
|
||||
// 건설 재료 소모하기 (테섭에서는 GM도 소모)
|
||||
{
|
||||
// 건설 비용 소모
|
||||
// 건설 비용 소모
|
||||
ch->PointChange(POINT_GOLD, -t->dwPrice);
|
||||
|
||||
// 아이템 자재 사용하기
|
||||
// 아이템 자재 사용하기
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < OBJECT_MATERIAL_MAX_NUM; ++i)
|
||||
|
@ -2958,8 +2958,8 @@ ACMD(do_build)
|
|||
break;
|
||||
|
||||
case 'W' :
|
||||
// 담장 세우기
|
||||
// build (w)all 담장번호 담장크기 대문동 대문서 대문남 대문북
|
||||
// 담장 세우기
|
||||
// build (w)all 담장번호 담장크기 대문동 대문서 대문남 대문북
|
||||
|
||||
if (GMLevel > GM_PLAYER)
|
||||
{
|
||||
|
@ -2993,8 +2993,8 @@ ACMD(do_build)
|
|||
break;
|
||||
|
||||
case 'E' :
|
||||
// 담장 지우기
|
||||
// build (e)rase 담장셋ID
|
||||
// 담장 지우기
|
||||
// build (e)rase 담장셋ID
|
||||
if (GMLevel > GM_PLAYER)
|
||||
{
|
||||
one_argument(line, arg1, sizeof(arg1));
|
||||
|
@ -3051,7 +3051,7 @@ ACMD(do_horse_level)
|
|||
|
||||
if (NULL == victim)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("존재하지 않는 캐릭터 입니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This character does not exist."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3235,17 +3235,17 @@ ACMD(do_end_duel)
|
|||
LPCHARACTER pChar = CHARACTER_MANAGER::instance().FindPC(szName);
|
||||
if (pChar == NULL)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("존재하지 않는 캐릭터 입니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This character does not exist."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (CArenaManager::instance().EndDuel(pChar->GetPlayerID()) == false)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련 강제 종료 실패"));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Duel has not been successfully cancelled."));
|
||||
}
|
||||
else
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련 강제 종료 성공"));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Duel cancelled successfully."));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3268,7 +3268,7 @@ ACMD(do_duel)
|
|||
|
||||
if (!str_to_number(minute, szMinute))
|
||||
{
|
||||
// 캐나다는 기본 10분.
|
||||
// 캐나다는 기본 10분.
|
||||
if (LC_IsCanada() == true)
|
||||
{
|
||||
minute = 10;
|
||||
|
@ -3301,7 +3301,7 @@ ACMD(do_duel)
|
|||
}
|
||||
else
|
||||
{
|
||||
pChar1->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티에서 나가셨습니다."));
|
||||
pChar1->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Group] You have left the group."));
|
||||
pParty->Quit(pChar1->GetPlayerID());
|
||||
}
|
||||
}
|
||||
|
@ -3315,23 +3315,23 @@ ACMD(do_duel)
|
|||
}
|
||||
else
|
||||
{
|
||||
pChar2->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티에서 나가셨습니다."));
|
||||
pChar2->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Group] You have left the group."));
|
||||
pParty->Quit(pChar2->GetPlayerID());
|
||||
}
|
||||
}
|
||||
|
||||
if (CArenaManager::instance().StartDuel(pChar1, pChar2, set, minute) == true)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련이 성공적으로 시작 되었습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The duel has been successfully started."));
|
||||
}
|
||||
else
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련 시작에 문제가 있습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("There is a problem with initiating the duel."));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련자가 없습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("There are no combatants."));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3346,7 +3346,7 @@ ACMD(do_stat_plus_amount)
|
|||
|
||||
if (ch->IsPolymorphed())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("둔갑 중에는 능력을 올릴 수 없습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot change your status while you are transformed."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3354,7 +3354,7 @@ ACMD(do_stat_plus_amount)
|
|||
|
||||
if (nRemainPoint <= 0)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("남은 스탯 포인트가 없습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("No status points left."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3363,40 +3363,40 @@ ACMD(do_stat_plus_amount)
|
|||
|
||||
if (nRemainPoint < nPoint)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("남은 스탯 포인트가 적습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Remaining status points are too low."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (nPoint < 0)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("값을 잘못 입력하였습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You entered an incorrect value."));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (subcmd)
|
||||
{
|
||||
case POINT_HT : // 체력
|
||||
case POINT_HT : // 체력
|
||||
if (nPoint + ch->GetPoint(POINT_HT) > 90)
|
||||
{
|
||||
nPoint = 90 - ch->GetPoint(POINT_HT);
|
||||
}
|
||||
break;
|
||||
|
||||
case POINT_IQ : // 지능
|
||||
case POINT_IQ : // 지능
|
||||
if (nPoint + ch->GetPoint(POINT_IQ) > 90)
|
||||
{
|
||||
nPoint = 90 - ch->GetPoint(POINT_IQ);
|
||||
}
|
||||
break;
|
||||
|
||||
case POINT_ST : // 근력
|
||||
case POINT_ST : // 근력
|
||||
if (nPoint + ch->GetPoint(POINT_ST) > 90)
|
||||
{
|
||||
nPoint = 90 - ch->GetPoint(POINT_ST);
|
||||
}
|
||||
break;
|
||||
|
||||
case POINT_DX : // 민첩
|
||||
case POINT_DX : // 민첩
|
||||
if (nPoint + ch->GetPoint(POINT_DX) > 90)
|
||||
{
|
||||
nPoint = 90 - ch->GetPoint(POINT_DX);
|
||||
|
@ -3404,7 +3404,7 @@ ACMD(do_stat_plus_amount)
|
|||
break;
|
||||
|
||||
default :
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("명령어의 서브 커맨드가 잘못 되었습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Suborder or the Order is incorrect."));
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
@ -3437,7 +3437,7 @@ ACMD(do_break_marriage)
|
|||
str_to_number(pids.pid1, arg1);
|
||||
str_to_number(pids.pid2, arg2);
|
||||
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("플레이어 %d 와 플레이어 %d를 파혼시킵니다.."), pids.pid1, pids.pid2);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Broken contract between player %d and player %d."), pids.pid1, pids.pid2);
|
||||
db_clientdesc->DBPacket(HEADER_GD_BREAK_MARRIAGE, 0, &pids, sizeof(pids));
|
||||
}
|
||||
|
||||
|
@ -3471,8 +3471,8 @@ struct FCountInMap
|
|||
|
||||
ACMD(do_threeway_war_info)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("각제국 진행 정보"));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("선택 맵 정보 성지 %d 통로 %d %d %d"), GetSungziMapIndex(), GetPassMapIndex(1), GetPassMapIndex(2), GetPassMapIndex(3));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Information for the Kingdoms"));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Choose the Map Information of the Holy Land %d Entrance %d %d %d"), GetSungziMapIndex(), GetPassMapIndex(1), GetPassMapIndex(2), GetPassMapIndex(3));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "ThreewayPhase %d", CThreeWayWar::instance().GetRegenFlag());
|
||||
|
||||
for (int n = 1; n < 4; ++n)
|
||||
|
@ -3495,7 +3495,7 @@ ACMD(do_threeway_war_info)
|
|||
|
||||
ACMD(do_threeway_war_myinfo)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("나의 삼거리 진행정보"));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Information about the status of the kingdom battle"));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "Deadcount %d",
|
||||
CThreeWayWar::instance().GetReviveTokenForPlayer(ch->GetPlayerID()));
|
||||
}
|
||||
|
@ -3577,7 +3577,7 @@ ACMD(do_check_monarch_money)
|
|||
str_to_number(empire, arg1);
|
||||
int NationMoney = CMonarch::instance().GetMoney(empire);
|
||||
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "국고: %d 원", NationMoney);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "Treasury: %d Yang", NationMoney);
|
||||
}
|
||||
|
||||
ACMD(do_reset_subskill)
|
||||
|
@ -3856,13 +3856,13 @@ ACMD(do_set_stat)
|
|||
{
|
||||
if (tch->IsPolymorphed())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("둔갑 중에는 능력을 올릴 수 없습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot change your status while you are transformed."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (subcmd != POINT_HT && subcmd != POINT_IQ && subcmd != POINT_ST && subcmd != POINT_DX)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("명령어의 서브 커맨드가 잘못 되었습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Suborder or the Order is incorrect."));
|
||||
return;
|
||||
}
|
||||
int nRemainPoint = tch->GetPoint(POINT_STAT);
|
||||
|
@ -3916,7 +3916,7 @@ ACMD(do_set_stat)
|
|||
|
||||
if (nRemainPoint < nChangeAmount)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("남은 스탯 포인트가 적습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Remaining status points are too low."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4153,8 +4153,8 @@ ACMD (do_attr_full_set)
|
|||
case JOB_SURA:
|
||||
case JOB_SHAMAN:
|
||||
{
|
||||
// 무사 몸빵 셋팅.
|
||||
// 이것만 나와 있어서 임시로 모든 직군 다 이런 속성 따름.
|
||||
// 무사 몸빵 셋팅.
|
||||
// 이것만 나와 있어서 임시로 모든 직군 다 이런 속성 따름.
|
||||
item = ch->GetWear(WEAR_HEAD);
|
||||
if (item != NULL)
|
||||
{
|
||||
|
@ -4261,7 +4261,7 @@ ACMD (do_use_item)
|
|||
}
|
||||
else
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "아이템이 없어서 착용할 수 없어.");
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, "I can't wear it because I don't have the item.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,16 +19,16 @@ ACMD(do_oxevent_log)
|
|||
{
|
||||
if ( COXEventManager::instance().LogWinner() == false )
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("OX이벤트의 나머지 인원을 기록하였습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("OX The other event participants are being noted down."));
|
||||
}
|
||||
else
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("OX이벤트의 나머지 인원 기록을 실패했습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("OX The other event participants have not been noted down."));
|
||||
}
|
||||
}
|
||||
|
||||
ACMD(do_oxevent_get_attender)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("현재 남은 참가자수 : %d"), COXEventManager::instance().GetAttenderCount());
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Number of other participants : %d"), COXEventManager::instance().GetAttenderCount());
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ WORD teen_port = 0;
|
|||
|
||||
BYTE g_bChannel = 0;
|
||||
int passes_per_sec = 25;
|
||||
int save_event_second_cycle = passes_per_sec * 120; // 3분
|
||||
int save_event_second_cycle = passes_per_sec * 120; // 3분
|
||||
int ping_event_second_cycle = passes_per_sec * 60;
|
||||
bool g_bNoMoreClient = false;
|
||||
bool g_bNoRegen = false;
|
||||
|
@ -100,17 +100,17 @@ int SPEEDHACK_LIMIT_COUNT = 50;
|
|||
int SPEEDHACK_LIMIT_BONUS = 80;
|
||||
int g_iSyncHackLimitCount = 20; // 10 -> 20 2013 09 11 CYH
|
||||
|
||||
//시야 = VIEW_RANGE + VIEW_BONUS_RANGE
|
||||
//VIEW_BONUSE_RANGE : 클라이언트와 시야 처리에서너무 딱 떨어질경우 문제가 발생할수있어 500CM의 여분을 항상준다.
|
||||
//시야 = VIEW_RANGE + VIEW_BONUS_RANGE
|
||||
//VIEW_BONUSE_RANGE : 클라이언트와 시야 처리에서너무 딱 떨어질경우 문제가 발생할수있어 500CM의 여분을 항상준다.
|
||||
int VIEW_RANGE = 5000;
|
||||
int VIEW_BONUS_RANGE = 500;
|
||||
|
||||
int g_server_id = 0;
|
||||
string g_strWebMallURL = "www.metin2.de";
|
||||
|
||||
unsigned int g_uiSpamBlockDuration = 60 * 15; // 기본 15분
|
||||
unsigned int g_uiSpamBlockScore = 100; // 기본 100점
|
||||
unsigned int g_uiSpamReloadCycle = 60 * 10; // 기본 10분
|
||||
unsigned int g_uiSpamBlockDuration = 60 * 15; // 기본 15분
|
||||
unsigned int g_uiSpamBlockScore = 100; // 기본 100점
|
||||
unsigned int g_uiSpamReloadCycle = 60 * 10; // 기본 10분
|
||||
|
||||
bool g_bCheckMultiHack = true;
|
||||
|
||||
|
@ -119,8 +119,8 @@ int g_iSpamBlockMaxLevel = 10;
|
|||
void LoadStateUserCount();
|
||||
void LoadValidCRCList();
|
||||
bool LoadClientVersion();
|
||||
bool g_protectNormalPlayer = false; // 범법자가 "평화모드" 인 일반유저를 공격하지 못함
|
||||
bool g_noticeBattleZone = false; // 중립지대에 입장하면 안내메세지를 알려줌
|
||||
bool g_protectNormalPlayer = false; // 범법자가 "평화모드" 인 일반유저를 공격하지 못함
|
||||
bool g_noticeBattleZone = false; // 중립지대에 입장하면 안내메세지를 알려줌
|
||||
|
||||
int gPlayerMaxLevel = 99;
|
||||
|
||||
|
@ -316,7 +316,7 @@ void config_init(const string& st_localeServiceName)
|
|||
}
|
||||
|
||||
char db_host[2][64], db_user[2][64], db_pwd[2][64], db_db[2][64];
|
||||
// ... 아... db_port는 이미 있는데... 네이밍 어찌해야함...
|
||||
// ... 아... db_port는 이미 있는데... 네이밍 어찌해야함...
|
||||
int mysql_db_port[2];
|
||||
|
||||
for (int n = 0; n < 2; ++n)
|
||||
|
@ -337,9 +337,9 @@ void config_init(const string& st_localeServiceName)
|
|||
*log_db = '\0';
|
||||
|
||||
|
||||
// DB에서 로케일정보를 세팅하기위해서는 다른 세팅값보다 선행되어서
|
||||
// DB정보만 읽어와 로케일 세팅을 한후 다른 세팅을 적용시켜야한다.
|
||||
// 이유는 로케일관련된 초기화 루틴이 곳곳에 존재하기 때문.
|
||||
// DB에서 로케일정보를 세팅하기위해서는 다른 세팅값보다 선행되어서
|
||||
// DB정보만 읽어와 로케일 세팅을 한후 다른 세팅을 적용시켜야한다.
|
||||
// 이유는 로케일관련된 초기화 루틴이 곳곳에 존재하기 때문.
|
||||
|
||||
bool isCommonSQL = false;
|
||||
bool isPlayerSQL = false;
|
||||
|
@ -475,7 +475,7 @@ void config_init(const string& st_localeServiceName)
|
|||
}
|
||||
}
|
||||
|
||||
//처리가 끝났으니 파일을 닫자.
|
||||
//처리가 끝났으니 파일을 닫자.
|
||||
fclose(fpOnlyForDB);
|
||||
|
||||
// CONFIG_SQL_INFO_ERROR
|
||||
|
@ -501,7 +501,7 @@ void config_init(const string& st_localeServiceName)
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Common DB 가 Locale 정보를 가지고 있기 때문에 가장 먼저 접속해야 한다.
|
||||
// Common DB 가 Locale 정보를 가지고 있기 때문에 가장 먼저 접속해야 한다.
|
||||
AccountDB::instance().Connect(db_host[1], mysql_db_port[1], db_user[1], db_pwd[1], db_db[1]);
|
||||
|
||||
if (false == AccountDB::instance().IsConnected())
|
||||
|
@ -512,8 +512,8 @@ void config_init(const string& st_localeServiceName)
|
|||
|
||||
SPDLOG_INFO("CommonSQL connected");
|
||||
|
||||
// 로케일 정보를 가져오자
|
||||
// <경고> 쿼리문에 절대 조건문(WHERE) 달지 마세요. (다른 지역에서 문제가 생길수 있습니다)
|
||||
// 로케일 정보를 가져오자
|
||||
// <경고> 쿼리문에 절대 조건문(WHERE) 달지 마세요. (다른 지역에서 문제가 생길수 있습니다)
|
||||
{
|
||||
char szQuery[512];
|
||||
snprintf(szQuery, sizeof(szQuery), "SELECT mKey, mValue FROM locale");
|
||||
|
@ -530,7 +530,7 @@ void config_init(const string& st_localeServiceName)
|
|||
|
||||
while (NULL != (row = mysql_fetch_row(pMsg->Get()->pSQLResult)))
|
||||
{
|
||||
// 로케일 세팅
|
||||
// 로케일 세팅
|
||||
if (strcasecmp(row[0], "LOCALE") == 0)
|
||||
{
|
||||
if (LocaleService_Init(row[1]) == false)
|
||||
|
@ -542,15 +542,15 @@ void config_init(const string& st_localeServiceName)
|
|||
}
|
||||
}
|
||||
|
||||
// 로케일 정보를 COMMON SQL에 세팅해준다.
|
||||
// 참고로 g_stLocale 정보는 LocaleService_Init() 내부에서 세팅된다.
|
||||
// 로케일 정보를 COMMON SQL에 세팅해준다.
|
||||
// 참고로 g_stLocale 정보는 LocaleService_Init() 내부에서 세팅된다.
|
||||
SPDLOG_INFO("Setting DB to locale {}", g_stLocale.c_str());
|
||||
|
||||
AccountDB::instance().SetLocale(g_stLocale);
|
||||
|
||||
AccountDB::instance().ConnectAsync(db_host[1], mysql_db_port[1], db_user[1], db_pwd[1], db_db[1], g_stLocale.c_str());
|
||||
|
||||
// Player DB 접속
|
||||
// Player DB 접속
|
||||
DBManager::instance().Connect(db_host[0], mysql_db_port[0], db_user[0], db_pwd[0], db_db[0]);
|
||||
|
||||
if (!DBManager::instance().IsConnected())
|
||||
|
@ -561,9 +561,9 @@ void config_init(const string& st_localeServiceName)
|
|||
|
||||
SPDLOG_INFO("PlayerSQL connected");
|
||||
|
||||
if (false == g_bAuthServer) // 인증 서버가 아닐 경우
|
||||
if (false == g_bAuthServer) // 인증 서버가 아닐 경우
|
||||
{
|
||||
// Log DB 접속
|
||||
// Log DB 접속
|
||||
LogManager::instance().Connect(log_host, log_port, log_user, log_pwd, log_db);
|
||||
|
||||
if (!LogManager::instance().IsConnected())
|
||||
|
@ -578,8 +578,8 @@ void config_init(const string& st_localeServiceName)
|
|||
}
|
||||
|
||||
// SKILL_POWER_BY_LEVEL
|
||||
// 스트링 비교의 문제로 인해서 AccountDB::instance().SetLocale(g_stLocale) 후부터 한다.
|
||||
// 물론 국내는 별로 문제가 안된다(해외가 문제)
|
||||
// 스트링 비교의 문제로 인해서 AccountDB::instance().SetLocale(g_stLocale) 후부터 한다.
|
||||
// 물론 국내는 별로 문제가 안된다(해외가 문제)
|
||||
{
|
||||
char szQuery[256];
|
||||
snprintf(szQuery, sizeof(szQuery), "SELECT mValue FROM locale WHERE mKey='SKILL_POWER_BY_LEVEL'");
|
||||
|
@ -619,13 +619,13 @@ void config_init(const string& st_localeServiceName)
|
|||
}
|
||||
}
|
||||
|
||||
// 종족별 스킬 세팅
|
||||
// 종족별 스킬 세팅
|
||||
for (int job = 0; job < JOB_MAX_NUM * 2; ++job)
|
||||
{
|
||||
snprintf(szQuery, sizeof(szQuery), "SELECT mValue from locale where mKey='SKILL_POWER_BY_LEVEL_TYPE%d' ORDER BY CAST(mValue AS unsigned)", job);
|
||||
std::unique_ptr<SQLMsg> pMsg(AccountDB::instance().DirectQuery(szQuery));
|
||||
|
||||
// 세팅이 안되어있으면 기본테이블을 사용한다.
|
||||
// 세팅이 안되어있으면 기본테이블을 사용한다.
|
||||
if (pMsg->Get()->uiNumRows == 0)
|
||||
{
|
||||
CTableBySkill::instance().SetSkillPowerByLevelFromType(job, aiBaseSkillPowerByLevelTable);
|
||||
|
@ -995,7 +995,7 @@ void config_init(const string& st_localeServiceName)
|
|||
TOKEN("spam_block_reload_cycle")
|
||||
{
|
||||
str_to_number(g_uiSpamReloadCycle, value_string);
|
||||
g_uiSpamReloadCycle = std::max<int>(60, g_uiSpamReloadCycle); // 최소 1분
|
||||
g_uiSpamReloadCycle = std::max<int>(60, g_uiSpamReloadCycle); // 최소 1분
|
||||
}
|
||||
|
||||
TOKEN("check_multihack")
|
||||
|
@ -1205,7 +1205,7 @@ void CheckClientVersion()
|
|||
//if (0 != g_stClientVersion.compare(d->GetClientVersion()) )
|
||||
if (version > date)
|
||||
{
|
||||
d->GetCharacter()->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("클라이언트 버전이 틀려 로그아웃 됩니다. 정상적으로 패치 후 접속하세요."));
|
||||
d->GetCharacter()->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("You do not have the correct client version. Please install the normal patch."));
|
||||
d->DelayedDisconnect(10);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ extern bool china_event_server;
|
|||
extern bool g_bNoMoreClient;
|
||||
extern bool g_bNoRegen;
|
||||
|
||||
extern bool g_bTrafficProfileOn; ///< true 이면 TrafficProfiler 를 켠다.
|
||||
extern bool g_bTrafficProfileOn; ///< true 이면 TrafficProfiler 를 켠다.
|
||||
|
||||
extern BYTE g_bChannel;
|
||||
|
||||
|
@ -98,8 +98,8 @@ extern int VIEW_RANGE;
|
|||
extern int VIEW_BONUS_RANGE;
|
||||
|
||||
extern bool g_bCheckMultiHack;
|
||||
extern bool g_protectNormalPlayer; // 범법자가 "평화모드" 인 일반유저를 공격하지 못함
|
||||
extern bool g_noticeBattleZone; // 중립지대에 입장하면 안내메세지를 알려줌
|
||||
extern bool g_protectNormalPlayer; // 범법자가 "평화모드" 인 일반유저를 공격하지 못함
|
||||
extern bool g_noticeBattleZone; // 중립지대에 입장하면 안내메세지를 알려줌
|
||||
|
||||
extern DWORD g_GoldDropTimeLimitValue;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ TJobInitialPoints JobInitialPoints[JOB_MAX_NUM] =
|
|||
}
|
||||
*/
|
||||
{
|
||||
// str con dex int 초기HP 초기SP CON/HP INT/SP HP랜덤/lv MP랜덤/lv 초기stam stam/con stam/lv
|
||||
// str con dex int 초기HP 초기SP CON/HP INT/SP HP랜덤/lv MP랜덤/lv 초기stam stam/con stam/lv
|
||||
{ 6, 4, 3, 3, 600, 200, 40, 20, 36, 44, 18, 22, 800, 5, 1, 3 }, // JOB_WARRIOR 16
|
||||
{ 4, 3, 6, 3, 650, 200, 40, 20, 36, 44, 18, 22, 800, 5, 1, 3 }, // JOB_ASSASSIN 16
|
||||
{ 5, 3, 3, 5, 650, 200, 40, 20, 36, 44, 18, 22, 800, 5, 1, 3 }, // JOB_SURA 16
|
||||
|
@ -162,7 +162,7 @@ const DWORD exp_table_euckr[PLAYER_EXP_TABLE_MAX + 1] =
|
|||
1676898443,
|
||||
1844588288,
|
||||
2029047116,
|
||||
2100000000, // 99 99레벨일 때 필요경험치 (100레벨이 되기 위한)
|
||||
2100000000, // 99 99레벨일 때 필요경험치 (100레벨이 되기 위한)
|
||||
2100000000, // 100
|
||||
2100000000,
|
||||
2100000000,
|
||||
|
@ -287,7 +287,7 @@ const DWORD exp_table_common[PLAYER_EXP_TABLE_MAX + 1] =
|
|||
1676898443,
|
||||
1844588288,
|
||||
2029047116,
|
||||
2050000000, // 99레벨 일 때 필요경험치 (100레벨이 되기 위한)
|
||||
2050000000, // 99레벨 일 때 필요경험치 (100레벨이 되기 위한)
|
||||
2150000000, // 100
|
||||
2210000000,
|
||||
2250000000,
|
||||
|
@ -412,7 +412,7 @@ const DWORD exp_table_newcibn[PLAYER_EXP_TABLE_MAX + 1 ] =
|
|||
2000000000,
|
||||
2000000000,
|
||||
2000000000,
|
||||
2000000000, // 99 99레벨일 때 필요경험치 (100레벨이 되기 위한).. 현재 CIBN이 어떻게 운영하고 있는 지 모르니 신규 테이블을 쓰지 않고 기존값 계속 연장 유지
|
||||
2000000000, // 99 99레벨일 때 필요경험치 (100레벨이 되기 위한).. 현재 CIBN이 어떻게 운영하고 있는 지 모르니 신규 테이블을 쓰지 않고 기존값 계속 연장 유지
|
||||
2000000000, // 100
|
||||
2000000000,
|
||||
2000000000,
|
||||
|
@ -439,8 +439,8 @@ const DWORD exp_table_newcibn[PLAYER_EXP_TABLE_MAX + 1 ] =
|
|||
const int * aiPercentByDeltaLev = NULL;
|
||||
const int * aiPercentByDeltaLevForBoss = NULL;
|
||||
|
||||
// 적과 나와의 레벨차이에 의한 계산에 사용되는 테이블
|
||||
// MIN(MAX_EXP_DELTA_OF_LEV - 1, (적렙 + 15) - 내렙))
|
||||
// 적과 나와의 레벨차이에 의한 계산에 사용되는 테이블
|
||||
// MIN(MAX_EXP_DELTA_OF_LEV - 1, (적렙 + 15) - 내렙))
|
||||
const int aiPercentByDeltaLevForBoss_euckr[MAX_EXP_DELTA_OF_LEV] =
|
||||
{
|
||||
1, // -15 0
|
||||
|
@ -720,7 +720,7 @@ const DWORD guild_exp_table[GUILD_MAX_LEVEL+1] =
|
|||
42000000UL
|
||||
};
|
||||
|
||||
// INTERNATIONAL_VERSION 길드경험치
|
||||
// INTERNATIONAL_VERSION 길드경험치
|
||||
const DWORD guild_exp_table2[GUILD_MAX_LEVEL+1] =
|
||||
{
|
||||
0,
|
||||
|
@ -745,7 +745,7 @@ const DWORD guild_exp_table2[GUILD_MAX_LEVEL+1] =
|
|||
4000000UL,
|
||||
16800000UL
|
||||
};
|
||||
// END_OF_INTERNATIONAL_VERSION 길드경험치
|
||||
// END_OF_INTERNATIONAL_VERSION 길드경험치
|
||||
|
||||
const int aiMobEnchantApplyIdx[MOB_ENCHANTS_MAX_NUM] =
|
||||
{
|
||||
|
@ -899,16 +899,16 @@ const TApplyInfo aApplyInfo[MAX_APPLY_NUM] =
|
|||
{ POINT_PC_BANG_DROP_BONUS }, // 76
|
||||
// END_PC_BANG_ITEM_ADD
|
||||
|
||||
{ POINT_NONE, }, // 77 사용시 HP 소모 APPLY_EXTRACT_HP_PCT
|
||||
{ POINT_NONE, }, // 77 사용시 HP 소모 APPLY_EXTRACT_HP_PCT
|
||||
|
||||
{ POINT_RESIST_WARRIOR, }, // 78 무사에게 저항 APPLY_RESIST_WARRIOR
|
||||
{ POINT_RESIST_ASSASSIN, }, // 79 자객에게 저항 APPLY_RESIST_ASSASSIN
|
||||
{ POINT_RESIST_SURA, }, // 80 수라에게 저항 APPLY_RESIST_SURA
|
||||
{ POINT_RESIST_SHAMAN, }, // 81 무당에게 저항 APPLY_RESIST_SHAMAN
|
||||
{ POINT_ENERGY }, // 82 기력
|
||||
{ POINT_DEF_GRADE }, // 83 방어력. DEF_GRADE_BONUS는 클라에서 두배로 보여지는 의도된 버그(...)가 있다.
|
||||
{ POINT_COSTUME_ATTR_BONUS }, // 84 코스튬에 붙은 속성에 대해서만 보너스를 주는 기력
|
||||
{ POINT_MAGIC_ATT_BONUS_PER }, // 85 마법 공격력 +x%
|
||||
{ POINT_RESIST_WARRIOR, }, // 78 무사에게 저항 APPLY_RESIST_WARRIOR
|
||||
{ POINT_RESIST_ASSASSIN, }, // 79 자객에게 저항 APPLY_RESIST_ASSASSIN
|
||||
{ POINT_RESIST_SURA, }, // 80 수라에게 저항 APPLY_RESIST_SURA
|
||||
{ POINT_RESIST_SHAMAN, }, // 81 무당에게 저항 APPLY_RESIST_SHAMAN
|
||||
{ POINT_ENERGY }, // 82 기력
|
||||
{ POINT_DEF_GRADE }, // 83 방어력. DEF_GRADE_BONUS는 클라에서 두배로 보여지는 의도된 버그(...)가 있다.
|
||||
{ POINT_COSTUME_ATTR_BONUS }, // 84 코스튬에 붙은 속성에 대해서만 보너스를 주는 기력
|
||||
{ POINT_MAGIC_ATT_BONUS_PER }, // 85 마법 공격력 +x%
|
||||
{ POINT_MELEE_MAGIC_ATT_BONUS_PER }, // 86 APPLY_MELEE_MAGIC_ATTBONUS_PER
|
||||
{ POINT_RESIST_ICE, }, // APPLY_RESIST_ICE, 87
|
||||
{ POINT_RESIST_EARTH, }, // APPLY_RESIST_EARTH, 88
|
||||
|
@ -1077,19 +1077,19 @@ const SStoneDropInfo aStoneDrop[STONE_INFO_MAX_NUM] =
|
|||
|
||||
const char * c_apszEmpireNames[EMPIRE_MAX_NUM] =
|
||||
{
|
||||
"전제국",
|
||||
"신수국",
|
||||
"천조국",
|
||||
"진노국"
|
||||
"All kingdoms",
|
||||
"Shinsoo Kingdom",
|
||||
"Chunjo Kingdom",
|
||||
"Jinno Kingdom"
|
||||
};
|
||||
|
||||
const char * c_apszPrivNames[MAX_PRIV_NUM] =
|
||||
{
|
||||
"",
|
||||
"아이템이 나올 확률",
|
||||
"돈이 나올 확률",
|
||||
"돈 대박이 나올 확률",
|
||||
"경험치 배율",
|
||||
"Item drop rate in percent",
|
||||
"Yang drop rate in percent",
|
||||
"Yang rain drop rate",
|
||||
"Experience percentage",
|
||||
};
|
||||
|
||||
const int aiPolymorphPowerByLevel[SKILL_MAX_LEVEL + 1] =
|
||||
|
@ -1154,28 +1154,28 @@ TGuildWarInfo KOR_aGuildWarInfo[GUILD_WAR_TYPE_MAX_NUM] =
|
|||
};
|
||||
|
||||
//
|
||||
// 악세서리 소켓용 수치들
|
||||
// 악세서리 소켓용 수치들
|
||||
//
|
||||
|
||||
// 다이아몬드로 소켓을 추가할 때 확률
|
||||
// 다이아몬드로 소켓을 추가할 때 확률
|
||||
const int aiAccessorySocketAddPct[ITEM_ACCESSORY_SOCKET_MAX_NUM] =
|
||||
{
|
||||
50, 50, 50
|
||||
};
|
||||
|
||||
// 악세서리 수치 값의 몇%만큼의 성능을 추가하는지
|
||||
// 악세서리 수치 값의 몇%만큼의 성능을 추가하는지
|
||||
const int aiAccessorySocketEffectivePct[ITEM_ACCESSORY_SOCKET_MAX_NUM + 1] =
|
||||
{
|
||||
0, 10, 20, 40
|
||||
};
|
||||
|
||||
// 소켓 지속시간 24, 12, 6
|
||||
// 소켓 지속시간 24, 12, 6
|
||||
const int aiAccessorySocketDegradeTime[ITEM_ACCESSORY_SOCKET_MAX_NUM + 1] =
|
||||
{
|
||||
0, 3600 * 24, 3600 * 12, 3600 * 6
|
||||
};
|
||||
|
||||
// 소켓 장착 성공률
|
||||
// 소켓 장착 성공률
|
||||
const int aiAccessorySocketPutPct[ITEM_ACCESSORY_SOCKET_MAX_NUM + 1] =
|
||||
{
|
||||
90, 80, 70, 0
|
||||
|
@ -1275,10 +1275,10 @@ TValueName c_aApplyTypeNames[] =
|
|||
{ "RESIST_ASSASSIN", APPLY_RESIST_ASSASSIN},
|
||||
{ "RESIST_SURA", APPLY_RESIST_SURA},
|
||||
{ "RESIST_SHAMAN", APPLY_RESIST_SHAMAN},
|
||||
// by mhh game/affect.h 정의되어있음. INFINITE_AFFECT_DURATION = 0x1FFFFFFF
|
||||
// by mhh game/affect.h 정의되어있음. INFINITE_AFFECT_DURATION = 0x1FFFFFFF
|
||||
{ "INFINITE_AFFECT_DURATION", 0x1FFFFFFF },
|
||||
{ "ENERGY", APPLY_ENERGY }, // 기력
|
||||
{ "COSTUME_ATTR_BONUS", APPLY_COSTUME_ATTR_BONUS }, // 기력
|
||||
{ "ENERGY", APPLY_ENERGY }, // 기력
|
||||
{ "COSTUME_ATTR_BONUS", APPLY_COSTUME_ATTR_BONUS }, // 기력
|
||||
{ "MAGIC_ATTBONUS_PER", APPLY_MAGIC_ATTBONUS_PER },
|
||||
{ "MELEE_MAGIC_ATTBONUS_PER", APPLY_MELEE_MAGIC_ATTBONUS_PER },
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ enum EMonsterChatState
|
|||
|
||||
typedef struct SMobRankStat
|
||||
{
|
||||
int iGoldPercent; // 돈이 나올 확률
|
||||
int iGoldPercent; // 돈이 나올 확률
|
||||
} TMobRankStat;
|
||||
|
||||
typedef struct SMobStat
|
||||
|
@ -124,7 +124,7 @@ extern const int aiMobResistsApplyIdx[MOB_RESISTS_MAX_NUM];
|
|||
|
||||
extern const int aSkillAttackAffectProbByRank[MOB_RANK_MAX_NUM];
|
||||
|
||||
extern const int aiItemMagicAttributePercentHigh[ITEM_ATTRIBUTE_MAX_LEVEL]; // 1개까지
|
||||
extern const int aiItemMagicAttributePercentHigh[ITEM_ATTRIBUTE_MAX_LEVEL]; // 1개까지
|
||||
extern const int aiItemMagicAttributePercentLow[ITEM_ATTRIBUTE_MAX_LEVEL];
|
||||
|
||||
extern const int aiItemAttributeAddPercent[ITEM_ATTRIBUTE_MAX_NUM];
|
||||
|
|
|
@ -37,11 +37,11 @@ static bool s_isInitializedCubeMaterialInformation = false;
|
|||
/*--------------------------------------------------------*/
|
||||
enum ECubeResultCategory
|
||||
{
|
||||
CUBE_CATEGORY_POTION, // 약초, 진액 등등.. (포션으로 특정할 수 없으니 사용 안 함. 약초같은건 다 걍 기타)
|
||||
CUBE_CATEGORY_WEAPON, // 무기
|
||||
CUBE_CATEGORY_ARMOR, // 방어구
|
||||
CUBE_CATEGORY_ACCESSORY, // 장신구
|
||||
CUBE_CATEGORY_ETC, // 기타 등등...
|
||||
CUBE_CATEGORY_POTION, // 약초, 진액 등등.. (포션으로 특정할 수 없으니 사용 안 함. 약초같은건 다 걍 기타)
|
||||
CUBE_CATEGORY_WEAPON, // 무기
|
||||
CUBE_CATEGORY_ARMOR, // 방어구
|
||||
CUBE_CATEGORY_ACCESSORY, // 장신구
|
||||
CUBE_CATEGORY_ETC, // 기타 등등...
|
||||
};
|
||||
|
||||
typedef std::vector<CUBE_VALUE> TCubeValueVector;
|
||||
|
@ -53,12 +53,12 @@ struct SCubeMaterialInfo
|
|||
bHaveComplicateMaterial = false;
|
||||
};
|
||||
|
||||
CUBE_VALUE reward; // 보상이 뭐냐
|
||||
TCubeValueVector material; // 재료들은 뭐냐
|
||||
DWORD gold; // 돈은 얼마드냐
|
||||
TCubeValueVector complicateMaterial; // 복잡한-_- 재료들
|
||||
CUBE_VALUE reward; // 보상이 뭐냐
|
||||
TCubeValueVector material; // 재료들은 뭐냐
|
||||
DWORD gold; // 돈은 얼마드냐
|
||||
TCubeValueVector complicateMaterial; // 복잡한-_- 재료들
|
||||
|
||||
// .. 클라이언트에서 재료를 보여주기 위하여 약속한 포맷
|
||||
// .. 클라이언트에서 재료를 보여주기 위하여 약속한 포맷
|
||||
// 72723,1&72724,2&72730,1
|
||||
// 52001,1|52002,1|52003,1&72723,1&72724,5
|
||||
// => ( 52001,1 or 52002,1 or 52003,1 ) and 72723,1 and 72724,5
|
||||
|
@ -75,13 +75,13 @@ struct SItemNameAndLevel
|
|||
};
|
||||
|
||||
|
||||
// 자료구조나 이런거 병신인건 이해좀... 누구땜에 영혼이 없는 상태에서 만들었씀
|
||||
// 자료구조나 이런거 병신인건 이해좀... 누구땜에 영혼이 없는 상태에서 만들었씀
|
||||
typedef std::vector<SCubeMaterialInfo> TCubeResultList;
|
||||
typedef std::unordered_map<DWORD, TCubeResultList> TCubeMapByNPC; // 각각의 NPC별로 어떤 걸 만들 수 있고 재료가 뭔지...
|
||||
typedef std::unordered_map<DWORD, std::string> TCubeResultInfoTextByNPC; // 각각의 NPC별로 만들 수 있는 목록을 정해진 포맷으로 정리한 정보
|
||||
typedef std::unordered_map<DWORD, TCubeResultList> TCubeMapByNPC; // 각각의 NPC별로 어떤 걸 만들 수 있고 재료가 뭔지...
|
||||
typedef std::unordered_map<DWORD, std::string> TCubeResultInfoTextByNPC; // 각각의 NPC별로 만들 수 있는 목록을 정해진 포맷으로 정리한 정보
|
||||
|
||||
TCubeMapByNPC cube_info_map;
|
||||
TCubeResultInfoTextByNPC cube_result_info_map_by_npc; // 네이밍 존나 병신같다 ㅋㅋㅋ
|
||||
TCubeResultInfoTextByNPC cube_result_info_map_by_npc; // 네이밍 존나 병신같다 ㅋㅋㅋ
|
||||
|
||||
class CCubeMaterialInfoHelper
|
||||
{
|
||||
|
@ -92,7 +92,7 @@ public:
|
|||
/*--------------------------------------------------------*/
|
||||
/* STATIC FUNCTIONS */
|
||||
/*--------------------------------------------------------*/
|
||||
// 필요한 아이템 개수를 가지고있는가?
|
||||
// 필요한 아이템 개수를 가지고있는가?
|
||||
static bool FN_check_item_count (LPITEM *items, DWORD item_vnum, int need_count)
|
||||
{
|
||||
int count = 0;
|
||||
|
@ -111,7 +111,7 @@ static bool FN_check_item_count (LPITEM *items, DWORD item_vnum, int need_count)
|
|||
return (count>=need_count);
|
||||
}
|
||||
|
||||
// 큐브내의 재료를 지운다.
|
||||
// 큐브내의 재료를 지운다.
|
||||
static void FN_remove_material (LPITEM *items, DWORD item_vnum, int need_count)
|
||||
{
|
||||
int count = 0;
|
||||
|
@ -170,7 +170,7 @@ static bool FN_check_valid_npc( WORD vnum )
|
|||
return false;
|
||||
}
|
||||
|
||||
// 큐브데이타가 올바르게 초기화 되었는지 체크한다.
|
||||
// 큐브데이타가 올바르게 초기화 되었는지 체크한다.
|
||||
static bool FN_check_cube_data (CUBE_DATA *cube_data)
|
||||
{
|
||||
DWORD i = 0;
|
||||
|
@ -204,10 +204,10 @@ CUBE_DATA::CUBE_DATA()
|
|||
this->gold = 0;
|
||||
}
|
||||
|
||||
// 필요한 재료의 수량을 만족하는지 체크한다.
|
||||
// 필요한 재료의 수량을 만족하는지 체크한다.
|
||||
bool CUBE_DATA::can_make_item (LPITEM *items, WORD npc_vnum)
|
||||
{
|
||||
// 필요한 재료, 수량을 만족하는지 체크한다.
|
||||
// 필요한 재료, 수량을 만족하는지 체크한다.
|
||||
DWORD i, end_index;
|
||||
DWORD need_vnum;
|
||||
int need_count;
|
||||
|
@ -235,7 +235,7 @@ bool CUBE_DATA::can_make_item (LPITEM *items, WORD npc_vnum)
|
|||
return true;
|
||||
}
|
||||
|
||||
// 큐브를 돌렸을때 나오는 아이템의 종류를 결정함
|
||||
// 큐브를 돌렸을때 나오는 아이템의 종류를 결정함
|
||||
CUBE_VALUE* CUBE_DATA::reward_value ()
|
||||
{
|
||||
int end_index = 0;
|
||||
|
@ -248,7 +248,7 @@ CUBE_VALUE* CUBE_DATA::reward_value ()
|
|||
return &this->reward[reward_index];
|
||||
}
|
||||
|
||||
// 큐브에 들어있는 재료를 지운다
|
||||
// 큐브에 들어있는 재료를 지운다
|
||||
void CUBE_DATA::remove_material (LPCHARACTER ch)
|
||||
{
|
||||
DWORD i, end_index;
|
||||
|
@ -281,7 +281,7 @@ void Cube_clean_item (LPCHARACTER ch)
|
|||
}
|
||||
}
|
||||
|
||||
// 큐브창 열기
|
||||
// 큐브창 열기
|
||||
void Cube_open (LPCHARACTER ch)
|
||||
{
|
||||
if (false == s_isInitializedCubeMaterialInformation)
|
||||
|
@ -308,12 +308,12 @@ void Cube_open (LPCHARACTER ch)
|
|||
|
||||
if (ch->IsCubeOpen())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("이미 제조창이 열려있습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The Build window is already open."));
|
||||
return;
|
||||
}
|
||||
if ( ch->GetExchange() || ch->GetMyShop() || ch->GetShopOwner() || ch->IsOpenSafebox() || ch->IsCubeOpen() )
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 거래중(창고,교환,상점)에는 사용할 수 없습니다."));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot build something while another trade/storeroom window is open."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -331,7 +331,7 @@ void Cube_open (LPCHARACTER ch)
|
|||
ch->ChatPacket(CHAT_TYPE_COMMAND, "cube open %d", npc->GetRaceNum());
|
||||
}
|
||||
|
||||
// 큐브 캔슬
|
||||
// 큐브 캔슬
|
||||
void Cube_close (LPCHARACTER ch)
|
||||
{
|
||||
RETURN_IF_CUBE_IS_NOT_OPENED(ch);
|
||||
|
@ -426,7 +426,7 @@ bool Cube_load (const char *file)
|
|||
}
|
||||
else TOKEN("gold")
|
||||
{
|
||||
// 제조에 필요한 금액
|
||||
// 제조에 필요한 금액
|
||||
cube_data->gold = value1;
|
||||
}
|
||||
else TOKEN("end")
|
||||
|
@ -504,10 +504,10 @@ static bool FN_update_cube_status(LPCHARACTER ch)
|
|||
// return new item
|
||||
bool Cube_make (LPCHARACTER ch)
|
||||
{
|
||||
// 주어진 아이템을 필요로하는 조합을 찾는다. (큐브데이타로 칭함)
|
||||
// 큐브 데이타가 있다면 아이템의 재료를 체크한다.
|
||||
// 새로운 아이템을 만든다.
|
||||
// 새로운 아이템 지급
|
||||
// 주어진 아이템을 필요로하는 조합을 찾는다. (큐브데이타로 칭함)
|
||||
// 큐브 데이타가 있다면 아이템의 재료를 체크한다.
|
||||
// 새로운 아이템을 만든다.
|
||||
// 새로운 아이템 지급
|
||||
|
||||
LPCHARACTER npc;
|
||||
int percent_number = 0;
|
||||
|
@ -517,7 +517,7 @@ bool Cube_make (LPCHARACTER ch)
|
|||
|
||||
if (!(ch)->IsCubeOpen())
|
||||
{
|
||||
(ch)->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("제조창이 열려있지 않습니다"));
|
||||
(ch)->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The build window is not open."));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -532,29 +532,29 @@ bool Cube_make (LPCHARACTER ch)
|
|||
|
||||
if (NULL == cube_proto)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("제조 재료가 부족합니다"));
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You do not have the right material."));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ch->GetGold() < cube_proto->gold)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("돈이 부족하거나 아이템이 제자리에 없습니다.")); // 이 텍스트는 이미 널리 쓰이는거라 추가번역 필요 없음
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Not enough Yang or not enough space in the inventory.")); // 이 텍스트는 이미 널리 쓰이는거라 추가번역 필요 없음
|
||||
return false;
|
||||
}
|
||||
|
||||
CUBE_VALUE *reward_value = cube_proto->reward_value();
|
||||
|
||||
// 사용되었던 재료아이템 삭제
|
||||
// 사용되었던 재료아이템 삭제
|
||||
cube_proto->remove_material (ch);
|
||||
|
||||
// 제조시 필요한 골드 차감
|
||||
// 제조시 필요한 골드 차감
|
||||
if (0 < cube_proto->gold)
|
||||
ch->PointChange(POINT_GOLD, -(cube_proto->gold), false);
|
||||
|
||||
percent_number = Random::get(1,100);
|
||||
if ( percent_number<=cube_proto->percent)
|
||||
{
|
||||
// 성공
|
||||
// 성공
|
||||
ch->ChatPacket(CHAT_TYPE_COMMAND, "cube success %d %d", reward_value->vnum, reward_value->count);
|
||||
new_item = ch->AutoGiveItem(reward_value->vnum, reward_value->count);
|
||||
|
||||
|
@ -564,8 +564,8 @@ bool Cube_make (LPCHARACTER ch)
|
|||
}
|
||||
else
|
||||
{
|
||||
// 실패
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("제조에 실패하였습니다.")); // 2012.11.12 새로 추가된 메세지 (locale_string.txt 에 추가해야 함)
|
||||
// 실패
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Manufacturing failed.")); // 2012.11.12 새로 추가된 메세지 (locale_string.txt 에 추가해야 함)
|
||||
ch->ChatPacket(CHAT_TYPE_COMMAND, "cube fail");
|
||||
LogManager::instance().CubeLog(ch->GetPlayerID(), ch->GetX(), ch->GetY(),
|
||||
reward_value->vnum, 0, 0, 0);
|
||||
|
@ -576,7 +576,7 @@ bool Cube_make (LPCHARACTER ch)
|
|||
}
|
||||
|
||||
|
||||
// 큐브에 있는 아이템들을 표시
|
||||
// 큐브에 있는 아이템들을 표시
|
||||
void Cube_show_list (LPCHARACTER ch)
|
||||
{
|
||||
LPITEM *cube_item;
|
||||
|
@ -597,13 +597,13 @@ void Cube_show_list (LPCHARACTER ch)
|
|||
}
|
||||
|
||||
|
||||
// 인벤토리에 있는 아이템을 큐브에 등록
|
||||
// 인벤토리에 있는 아이템을 큐브에 등록
|
||||
void Cube_add_item (LPCHARACTER ch, int cube_index, int inven_index)
|
||||
{
|
||||
// 아이템이 있는가?
|
||||
// 큐브내의 빈자리 찾기
|
||||
// 큐브세팅
|
||||
// 메시지 전송
|
||||
// 아이템이 있는가?
|
||||
// 큐브내의 빈자리 찾기
|
||||
// 큐브세팅
|
||||
// 메시지 전송
|
||||
LPITEM item;
|
||||
LPITEM *cube_item;
|
||||
|
||||
|
@ -620,7 +620,7 @@ void Cube_add_item (LPCHARACTER ch, int cube_index, int inven_index)
|
|||
|
||||
cube_item = ch->GetCubeItem();
|
||||
|
||||
// 이미 다른위치에 등록되었던 아이템이면 기존 indext삭제
|
||||
// 이미 다른위치에 등록되었던 아이템이면 기존 indext삭제
|
||||
for (int i=0; i<CUBE_MAX_NUM; ++i)
|
||||
{
|
||||
if (item==cube_item[i])
|
||||
|
@ -636,14 +636,14 @@ void Cube_add_item (LPCHARACTER ch, int cube_index, int inven_index)
|
|||
ch->ChatPacket(CHAT_TYPE_INFO, "cube[%d]: inventory[%d]: %s added",
|
||||
cube_index, inven_index, item->GetName());
|
||||
|
||||
// 현재 상자에 올라온 아이템들로 무엇을 만들 수 있는지 클라이언트에 정보 전달
|
||||
// 을 하고싶었으나 그냥 필요한 골드가 얼마인지 전달
|
||||
// 현재 상자에 올라온 아이템들로 무엇을 만들 수 있는지 클라이언트에 정보 전달
|
||||
// 을 하고싶었으나 그냥 필요한 골드가 얼마인지 전달
|
||||
FN_update_cube_status(ch);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 큐브에있는 아이템을 제거
|
||||
// 큐브에있는 아이템을 제거
|
||||
void Cube_delete_item (LPCHARACTER ch, int cube_index)
|
||||
{
|
||||
LPITEM item;
|
||||
|
@ -664,14 +664,14 @@ void Cube_delete_item (LPCHARACTER ch, int cube_index)
|
|||
ch->ChatPacket(CHAT_TYPE_INFO, "cube[%d]: cube[%d]: %s deleted",
|
||||
cube_index, item->GetCell(), item->GetName());
|
||||
|
||||
// 현재 상자에 올라온 아이템들로 무엇을 만들 수 있는지 클라이언트에 정보 전달
|
||||
// 을 하고싶었으나 그냥 필요한 골드가 얼마인지 전달
|
||||
// 현재 상자에 올라온 아이템들로 무엇을 만들 수 있는지 클라이언트에 정보 전달
|
||||
// 을 하고싶었으나 그냥 필요한 골드가 얼마인지 전달
|
||||
FN_update_cube_status(ch);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 아이템 이름을 통해서 순수 이름과 강화레벨을 분리하는 함수 (무쌍검+5 -> 무쌍검, 5)
|
||||
// 아이템 이름을 통해서 순수 이름과 강화레벨을 분리하는 함수 (무쌍검+5 -> 무쌍검, 5)
|
||||
SItemNameAndLevel SplitItemNameAndLevelFromName(const std::string& name)
|
||||
{
|
||||
int level = 0;
|
||||
|
@ -705,7 +705,7 @@ bool FIsLessCubeValue(const CUBE_VALUE& a, const CUBE_VALUE& b)
|
|||
|
||||
void Cube_MakeCubeInformationText()
|
||||
{
|
||||
// 이제 정리된 큐브 결과 및 재료들의 정보로 클라이언트에 보내 줄 정보로 변환함.
|
||||
// 이제 정리된 큐브 결과 및 재료들의 정보로 클라이언트에 보내 줄 정보로 변환함.
|
||||
for (TCubeMapByNPC::iterator iter = cube_info_map.begin(); cube_info_map.end() != iter; ++iter)
|
||||
{
|
||||
const DWORD& npcVNUM = iter->first;
|
||||
|
@ -717,13 +717,13 @@ void Cube_MakeCubeInformationText()
|
|||
std::string& infoText = materialInfo.infoText;
|
||||
|
||||
|
||||
// 이놈이 나쁜놈이야
|
||||
// 이놈이 나쁜놈이야
|
||||
if (0 < materialInfo.complicateMaterial.size())
|
||||
{
|
||||
std::sort(materialInfo.complicateMaterial.begin(), materialInfo.complicateMaterial.end(), FIsLessCubeValue);
|
||||
std::sort(materialInfo.material.begin(), materialInfo.material.end(), FIsLessCubeValue);
|
||||
|
||||
//// 중복되는 재료들을 지움
|
||||
//// 중복되는 재료들을 지움
|
||||
for (TCubeValueVector::iterator iter = materialInfo.complicateMaterial.begin(); materialInfo.complicateMaterial.end() != iter; ++iter)
|
||||
{
|
||||
for (TCubeValueVector::iterator targetIter = materialInfo.material.begin(); materialInfo.material.end() != targetIter; ++targetIter)
|
||||
|
@ -735,7 +735,7 @@ void Cube_MakeCubeInformationText()
|
|||
}
|
||||
}
|
||||
|
||||
// 72723,1 or 72725,1 or ... 이런 식의 약속된 포맷을 지키는 텍스트를 생성
|
||||
// 72723,1 or 72725,1 or ... 이런 식의 약속된 포맷을 지키는 텍스트를 생성
|
||||
for (TCubeValueVector::iterator iter = materialInfo.complicateMaterial.begin(); materialInfo.complicateMaterial.end() != iter; ++iter)
|
||||
{
|
||||
char tempBuffer[128];
|
||||
|
@ -750,7 +750,7 @@ void Cube_MakeCubeInformationText()
|
|||
infoText.push_back('&');
|
||||
}
|
||||
|
||||
// 중복되지 않는 일반 재료들도 포맷 생성
|
||||
// 중복되지 않는 일반 재료들도 포맷 생성
|
||||
for (TCubeValueVector::iterator iter = materialInfo.material.begin(); materialInfo.material.end() != iter; ++iter)
|
||||
{
|
||||
char tempBuffer[128];
|
||||
|
@ -760,7 +760,7 @@ void Cube_MakeCubeInformationText()
|
|||
|
||||
infoText.erase(infoText.size() - 1);
|
||||
|
||||
// 만들 때 골드가 필요하다면 골드정보 추가
|
||||
// 만들 때 골드가 필요하다면 골드정보 추가
|
||||
if (0 < materialInfo.gold)
|
||||
{
|
||||
char temp[128];
|
||||
|
@ -779,7 +779,7 @@ bool Cube_InformationInitialize()
|
|||
|
||||
const std::vector<CUBE_VALUE>& rewards = cubeData->reward;
|
||||
|
||||
// 하드코딩 ㅈㅅ
|
||||
// 하드코딩 ㅈㅅ
|
||||
if (1 != rewards.size())
|
||||
{
|
||||
SPDLOG_ERROR("[CubeInfo] WARNING! Does not support multiple rewards (count: {})", rewards.size());
|
||||
|
@ -807,13 +807,13 @@ bool Cube_InformationInitialize()
|
|||
{
|
||||
SCubeMaterialInfo& existInfo = *iter;
|
||||
|
||||
// 이미 중복되는 보상이 등록되어 있다면 아예 다른 조합으로 만드는 것인지,
|
||||
// 거의 같은 조합인데 특정 부분만 틀린 것인지 구분함.
|
||||
// 예를들면 특정 부분만 틀린 아이템들은 아래처럼 하나로 묶어서 하나의 결과로 보여주기 위함임:
|
||||
// 용신지검:
|
||||
// 무쌍검+5 ~ +9 x 1
|
||||
// 붉은 칼자루 조각 x1
|
||||
// 녹색 검장식 조각 x1
|
||||
// 이미 중복되는 보상이 등록되어 있다면 아예 다른 조합으로 만드는 것인지,
|
||||
// 거의 같은 조합인데 특정 부분만 틀린 것인지 구분함.
|
||||
// 예를들면 특정 부분만 틀린 아이템들은 아래처럼 하나로 묶어서 하나의 결과로 보여주기 위함임:
|
||||
// 용신지검:
|
||||
// 무쌍검+5 ~ +9 x 1
|
||||
// 붉은 칼자루 조각 x1
|
||||
// 녹색 검장식 조각 x1
|
||||
if (reward.vnum == existInfo.reward.vnum)
|
||||
{
|
||||
for (TCubeValueVector::iterator existMaterialIter = existInfo.material.begin(); existInfo.material.end() != existMaterialIter; ++existMaterialIter)
|
||||
|
@ -828,8 +828,8 @@ bool Cube_InformationInitialize()
|
|||
|
||||
if (0 < existItemInfo.level)
|
||||
{
|
||||
// 지금 추가하는 큐브 결과물의 재료와, 기존에 등록되어있던 큐브 결과물의 재료 중
|
||||
// 중복되는 부분이 있는지 검색한다
|
||||
// 지금 추가하는 큐브 결과물의 재료와, 기존에 등록되어있던 큐브 결과물의 재료 중
|
||||
// 중복되는 부분이 있는지 검색한다
|
||||
for (TCubeValueVector::iterator currentMaterialIter = materialInfo.material.begin(); materialInfo.material.end() != currentMaterialIter; ++currentMaterialIter)
|
||||
{
|
||||
TItemTable* currentMaterialProto = ITEM_MANAGER::Instance().GetTable(currentMaterialIter->vnum);
|
||||
|
@ -845,7 +845,7 @@ bool Cube_InformationInitialize()
|
|||
|
||||
//currentMaterialIter = materialInfo.material.erase(currentMaterialIter);
|
||||
|
||||
// TODO: 중복되는 아이템 두 개 이상 검출해야 될 수도 있음
|
||||
// TODO: 중복되는 아이템 두 개 이상 검출해야 될 수도 있음
|
||||
break;
|
||||
}
|
||||
} // for currentMaterialIter
|
||||
|
@ -865,7 +865,7 @@ bool Cube_InformationInitialize()
|
|||
return true;
|
||||
}
|
||||
|
||||
// 클라이언트에서 서버로 : 현재 NPC가 만들 수 있는 아이템들의 정보(목록)를 요청
|
||||
// 클라이언트에서 서버로 : 현재 NPC가 만들 수 있는 아이템들의 정보(목록)를 요청
|
||||
void Cube_request_result_list(LPCHARACTER ch)
|
||||
{
|
||||
RETURN_IF_CUBE_IS_NOT_OPENED(ch);
|
||||
|
@ -879,7 +879,7 @@ void Cube_request_result_list(LPCHARACTER ch)
|
|||
|
||||
std::string& resultText = cube_result_info_map_by_npc[npcVNUM];
|
||||
|
||||
// 해당 NPC가 만들 수 있는 목록이 정리된 게 없다면 캐시를 생성
|
||||
// 해당 NPC가 만들 수 있는 목록이 정리된 게 없다면 캐시를 생성
|
||||
if (resultText.length() == 0)
|
||||
{
|
||||
resultText.clear();
|
||||
|
@ -898,7 +898,7 @@ void Cube_request_result_list(LPCHARACTER ch)
|
|||
|
||||
resultText.erase(resultText.size() - 1);
|
||||
|
||||
// 채팅 패킷의 한계를 넘어가면 에러 남김... 기획자 분들 께 조정해달라고 요청하거나, 나중에 다른 방식으로 바꾸거나...
|
||||
// 채팅 패킷의 한계를 넘어가면 에러 남김... 기획자 분들 께 조정해달라고 요청하거나, 나중에 다른 방식으로 바꾸거나...
|
||||
if (resultText.size() - 20 >= CHAT_MAX_LEN)
|
||||
{
|
||||
SPDLOG_ERROR("[CubeInfo] Too long cube result list text. (NPC: {}, length: {})", npcVNUM, resultText.size());
|
||||
|
@ -908,7 +908,7 @@ void Cube_request_result_list(LPCHARACTER ch)
|
|||
|
||||
}
|
||||
|
||||
// 현재 NPC가 만들 수 있는 아이템들의 목록을 아래 포맷으로 전송한다.
|
||||
// 현재 NPC가 만들 수 있는 아이템들의 목록을 아래 포맷으로 전송한다.
|
||||
// (Server -> Client) /cube r_list npcVNUM resultCount vnum1,count1/vnum2,count2,/vnum3,count3/...
|
||||
// (Server -> Client) /cube r_list 20383 4 123,1/125,1/128,1/130,5
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* date : 2006.11.20
|
||||
* file : cube.h
|
||||
* author : mhh
|
||||
* description : 큐브시스템
|
||||
* description : 큐브시스템
|
||||
*/
|
||||
|
||||
#ifndef _cube_h_
|
||||
|
@ -30,7 +30,7 @@ struct CUBE_DATA
|
|||
std::vector<CUBE_VALUE> item;
|
||||
std::vector<CUBE_VALUE> reward;
|
||||
int percent;
|
||||
unsigned int gold; // 제조시 필요한 금액
|
||||
unsigned int gold; // 제조시 필요한 금액
|
||||
|
||||
CUBE_DATA();
|
||||
|
||||
|
|
|
@ -268,7 +268,7 @@ void DBManager::AnalyzeReturnQuery(SQLMsg * pMsg)
|
|||
M2_DELETE(pinfo);
|
||||
break;
|
||||
}
|
||||
|
||||
// Change Location
|
||||
d->SetLogin(pinfo->login);
|
||||
|
||||
SPDLOG_DEBUG("QID_AUTH_LOGIN: START {} {}", qi->dwIdent, (void*) get_pointer(d));
|
||||
|
@ -394,7 +394,7 @@ void DBManager::AnalyzeReturnQuery(SQLMsg * pMsg)
|
|||
|
||||
if (true == LC_IsBrazil())
|
||||
{
|
||||
nPasswordDiff = 0; // 브라질 버전에서는 비밀번호 체크를 하지 않는다.
|
||||
nPasswordDiff = 0; // 브라질 버전에서는 비밀번호 체크를 하지 않는다.
|
||||
}
|
||||
|
||||
if (nPasswordDiff)
|
||||
|
@ -425,7 +425,7 @@ void DBManager::AnalyzeReturnQuery(SQLMsg * pMsg)
|
|||
{
|
||||
if (LC_IsEurope())
|
||||
{
|
||||
//stBlockData >= 0 == 날짜가 BlockDate 보다 미래
|
||||
//stBlockData >= 0 == 날짜가 BlockDate 보다 미래
|
||||
if (strncmp(szCreateDate, g_stBlockDate.c_str(), 8) >= 0)
|
||||
{
|
||||
LoginFailure(d, "BLKLOGIN");
|
||||
|
@ -493,7 +493,7 @@ void DBManager::AnalyzeReturnQuery(SQLMsg * pMsg)
|
|||
if (pkItem)
|
||||
{
|
||||
SPDLOG_DEBUG("GIVE LOTTO SUCCESS TO {} (pid {})", ch->GetName(), qi->dwIdent);
|
||||
//ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("아이템 획득: %s"), pkItem->GetName());
|
||||
//ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s received"), pkItem->GetName());
|
||||
|
||||
pkItem->SetSocket(0, pMsg->Get()->uiInsertID);
|
||||
pkItem->SetSocket(1, pdw[2]);
|
||||
|
@ -657,7 +657,7 @@ enum EAccountQID
|
|||
QID_SPAM_DB,
|
||||
};
|
||||
|
||||
// 10분마다 리로드
|
||||
// 10분마다 리로드
|
||||
static LPEVENT s_pkReloadSpamEvent = NULL;
|
||||
|
||||
EVENTINFO(reload_spam_event_info)
|
||||
|
|
|
@ -82,8 +82,8 @@ class DBManager : public singleton<DBManager>
|
|||
DWORD CountQueryResult() { return m_sql.CountResult(); }
|
||||
void ResetQueryResult() { m_sql.ResetQueryFinished(); }
|
||||
|
||||
template<class Functor> void FuncQuery(Functor f, const char * c_pszFormat, ...); // 결과를 f인자로 호출함 (SQLMsg *) 알아서 해제됨
|
||||
template<class Functor> void FuncAfterQuery(Functor f, const char * c_pszFormat, ...); // 끝나고 나면 f가 호출됨 void f(void) 형태
|
||||
template<class Functor> void FuncQuery(Functor f, const char * c_pszFormat, ...); // 결과를 f인자로 호출함 (SQLMsg *) 알아서 해제됨
|
||||
template<class Functor> void FuncAfterQuery(Functor f, const char * c_pszFormat, ...); // 끝나고 나면 f가 호출됨 void f(void) 형태
|
||||
|
||||
size_t EscapeString(char* dst, size_t dstSize, const char *src, size_t srcSize);
|
||||
|
||||
|
|
|
@ -316,12 +316,12 @@ void DESC::Packet(const void * c_pvData, int iSize)
|
|||
{
|
||||
assert(iSize > 0);
|
||||
|
||||
if (m_iPhase == PHASE_CLOSE) // 끊는 상태면 보내지 않는다.
|
||||
if (m_iPhase == PHASE_CLOSE) // 끊는 상태면 보내지 않는다.
|
||||
return;
|
||||
|
||||
if (m_stRelayName.length() != 0)
|
||||
{
|
||||
// Relay 패킷은 암호화하지 않는다.
|
||||
// Relay 패킷은 암호화하지 않는다.
|
||||
TPacketGGRelay p;
|
||||
|
||||
p.bHeader = HEADER_GG_RELAY;
|
||||
|
@ -367,7 +367,7 @@ void DESC::SetPhase(int _phase)
|
|||
switch (m_iPhase)
|
||||
{
|
||||
case PHASE_CLOSE:
|
||||
// 메신저가 캐릭터단위가 되면서 삭제
|
||||
// 메신저가 캐릭터단위가 되면서 삭제
|
||||
//MessengerManager::instance().Logout(GetAccountTable().login);
|
||||
m_pInputProcessor = &m_inputClose;
|
||||
break;
|
||||
|
@ -377,8 +377,8 @@ void DESC::SetPhase(int _phase)
|
|||
break;
|
||||
|
||||
case PHASE_SELECT:
|
||||
// 메신저가 캐릭터단위가 되면서 삭제
|
||||
//MessengerManager::instance().Logout(GetAccountTable().login); // 의도적으로 break 안검
|
||||
// 메신저가 캐릭터단위가 되면서 삭제
|
||||
//MessengerManager::instance().Logout(GetAccountTable().login); // 의도적으로 break 안검
|
||||
case PHASE_LOGIN:
|
||||
case PHASE_LOADING:
|
||||
m_pInputProcessor = &m_inputLogin;
|
||||
|
@ -550,7 +550,7 @@ void DESC::DisconnectOfSameLogin()
|
|||
if (m_pkDisconnectEvent)
|
||||
return;
|
||||
|
||||
GetCharacter()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 컴퓨터에서 로그인 하여 접속을 종료 합니다."));
|
||||
GetCharacter()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Someone has logged into your account. You will be disconnected from the server."));
|
||||
DelayedDisconnect(5);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -47,14 +47,14 @@ class CLoginKey
|
|||
};
|
||||
|
||||
|
||||
// sequence 버그 찾기용 데이타
|
||||
// sequence 버그 찾기용 데이타
|
||||
struct seq_t
|
||||
{
|
||||
BYTE hdr;
|
||||
BYTE seq;
|
||||
};
|
||||
typedef std::vector<seq_t> seq_vector_t;
|
||||
// sequence 버그 찾기용 데이타
|
||||
// sequence 버그 찾기용 데이타
|
||||
|
||||
extern void DescReadHandler(bufferevent *bev, void *ctx);
|
||||
extern void DescWriteHandler(bufferevent *bev, void *ctx);
|
||||
|
@ -109,7 +109,7 @@ class DESC
|
|||
|
||||
bool IsPhase(int phase) const { return m_iPhase == phase ? true : false; }
|
||||
|
||||
// 핸드쉐이크 (시간 동기화)
|
||||
// 핸드쉐이크 (시간 동기화)
|
||||
void StartHandshake(DWORD _dw);
|
||||
void SendHandshake(DWORD dwCurTime, LONG lNewDelta);
|
||||
bool HandshakeProcess(DWORD dwTime, LONG lDelta, bool bInfiniteRetry=false);
|
||||
|
@ -118,7 +118,7 @@ class DESC
|
|||
DWORD GetHandshake() const { return m_dwHandshake; }
|
||||
DWORD GetClientTime();
|
||||
|
||||
// 제국
|
||||
// 제국
|
||||
BYTE GetEmpire();
|
||||
|
||||
// for p2p
|
||||
|
@ -127,7 +127,7 @@ class DESC
|
|||
void DisconnectOfSameLogin();
|
||||
|
||||
void SetAdminMode();
|
||||
bool IsAdminMode(); // Handshake 에서 어드민 명령을 쓸수있나?
|
||||
bool IsAdminMode(); // Handshake 에서 어드민 명령을 쓸수있나?
|
||||
|
||||
void SetPong(bool b);
|
||||
bool IsPong();
|
||||
|
@ -197,7 +197,7 @@ class DESC
|
|||
WORD m_wP2PPort;
|
||||
BYTE m_bP2PChannel;
|
||||
|
||||
bool m_bAdminMode; // Handshake 에서 어드민 명령을 쓸수있나?
|
||||
bool m_bAdminMode; // Handshake 에서 어드민 명령을 쓸수있나?
|
||||
bool m_bPong;
|
||||
|
||||
int m_iCurrentSequence;
|
||||
|
@ -248,7 +248,7 @@ class DESC
|
|||
|
||||
void ChatPacket(BYTE type, const char * format, ...);
|
||||
|
||||
/* 시퀀스 버그 찾기용 코드 */
|
||||
/* 시퀀스 버그 찾기용 코드 */
|
||||
public:
|
||||
seq_vector_t m_seq_vector;
|
||||
void push_seq (BYTE hdr, BYTE seq);
|
||||
|
|
|
@ -96,7 +96,7 @@ bool CLIENT_DESC::Connect(int iPhaseWhenSucceed)
|
|||
if (iPhaseWhenSucceed != 0)
|
||||
m_iPhaseWhenSucceed = iPhaseWhenSucceed;
|
||||
|
||||
if (get_global_time() - m_LastTryToConnectTime < 3) // 3초
|
||||
if (get_global_time() - m_LastTryToConnectTime < 3) // 3초
|
||||
return false;
|
||||
|
||||
m_LastTryToConnectTime = get_global_time();
|
||||
|
@ -219,7 +219,7 @@ void CLIENT_DESC::SetPhase(int iPhase)
|
|||
|
||||
SPDLOG_DEBUG("DB_SETUP current user {} size {}", p.dwLoginCount, buf.size());
|
||||
|
||||
// 파티를 처리할 수 있게 됨.
|
||||
// 파티를 처리할 수 있게 됨.
|
||||
CPartyManager::instance().EnablePCParty();
|
||||
//CPartyManager::instance().SendPartyToDB();
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ void CLIENT_DESC::Update(DWORD t)
|
|||
void CLIENT_DESC::UpdateChannelStatus(DWORD t, bool fForce)
|
||||
{
|
||||
enum {
|
||||
CHANNELSTATUS_UPDATE_PERIOD = 5*60*1000, // 5분마다
|
||||
CHANNELSTATUS_UPDATE_PERIOD = 5*60*1000, // 5분마다
|
||||
};
|
||||
if (fForce || m_tLastChannelStatusUpdateTime+CHANNELSTATUS_UPDATE_PERIOD < t) {
|
||||
int iTotal;
|
||||
|
|
|
@ -53,7 +53,7 @@ int IsValidIP(struct valid_ip* ip_table, const char *host)
|
|||
DESC_MANAGER::DESC_MANAGER() : m_bDestroyed(false)
|
||||
{
|
||||
Initialize();
|
||||
//NOTE : Destroy 끝에서 Initialize 를 부르는건 또 무슨 짓이냐..-_-; 정말
|
||||
//NOTE : Destroy 끝에서 Initialize 를 부르는건 또 무슨 짓이냐..-_-; 정말
|
||||
|
||||
m_pPackageCrypt = new CClientPackageCryptInfo;
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ RETRY:
|
|||
|
||||
LPDESC DESC_MANAGER::AcceptDesc(evconnlistener* listener, evutil_socket_t fd, sockaddr* address)
|
||||
{
|
||||
if (!IsValidIP(admin_ip, GetSocketHost(address).c_str())) // admin_ip 에 등록된 IP 는 최대 사용자 수에 구애받지 않는다.
|
||||
if (!IsValidIP(admin_ip, GetSocketHost(address).c_str())) // admin_ip 에 등록된 IP 는 최대 사용자 수에 구애받지 않는다.
|
||||
{
|
||||
if (m_iSocketsConnected >= MAX_ALLOW_USER)
|
||||
{
|
||||
|
|
|
@ -172,7 +172,7 @@ bool DragonSoulTable::ReadBasicApplys()
|
|||
TVecApplys vecApplys;
|
||||
int n = pChild->GetRowCount();
|
||||
|
||||
// BasicApply Group은 Key가 1부터 시작함.
|
||||
// BasicApply Group은 Key가 1부터 시작함.
|
||||
for (int j = 1; j <= n; j++)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
@ -655,7 +655,7 @@ bool DragonSoulTable::GetWeight(BYTE ds_type, BYTE grade_idx, BYTE step_index, B
|
|||
return true;
|
||||
}
|
||||
}
|
||||
// default group을 살펴봄.
|
||||
// default group을 살펴봄.
|
||||
pDragonSoulGroup = m_pWeightTableNode->GetChildNode("default");
|
||||
if (NULL != pDragonSoulGroup)
|
||||
{
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue