forked from metin2/server
Compare commits
56 Commits
Author | SHA1 | Date |
---|---|---|
Exynox | 175816c81d | |
Tr0n | b15eb7f3fe | |
Tr0n | 3a8d9e38e8 | |
Tr0n | 4074c3b96a | |
Tr0n | 854fef68e8 | |
Tr0n | cf66bb3310 | |
Tr0n | 254f6f6664 | |
Tr0n | 0072bc5e14 | |
Tr0n | 62f3635b86 | |
Tr0n | 2c37b2009d | |
Tr0n | e0701ed5bd | |
Tr0n | 21381a4e3a | |
Tr0n | ba44269071 | |
Tr0n | f5ccb17736 | |
Tr0n | bb52a57ffc | |
Tr0n | 8360d6939f | |
Tr0n | 1e362d8507 | |
Tr0n | 0a907f41d2 | |
Tr0n | dbcabd7fa9 | |
Exynox | fcc2a9e4a0 | |
Tr0n | 12b6abf373 | |
Tr0n | e1daa48366 | |
Exynox | 83707434ee | |
Exynox | 042414a499 | |
Tr0n | 68c7c4bc4f | |
Tr0n | eafbee616f | |
Tr0n | 026cb861a8 | |
Tr0n | 1ba21fb1f9 | |
Tr0n | 8fede9a1df | |
Tr0n | dfb3d08998 | |
Tr0n | 326c134f9e | |
Tr0n | 9b7536ee9a | |
Tr0n | 9056f6c6c6 | |
Tr0n | 8685b02fdc | |
Tr0n | 341bef9aba | |
sdgmt2 | 8a1acefeeb | |
sdgmt2 | eacc808366 | |
sdgmt2 | 4a1460f36e | |
sdgmt2 | aae9b169df | |
sdgmt2 | dd74eafc24 | |
sdgmt2 | d471d99a24 | |
sdgmt2 | 350fb0d424 | |
sdgmt2 | 869720f9e6 | |
sdgmt2 | 4fc612552a | |
sdgmt2 | 248205ae01 | |
sdgmt2 | 82317e6c4d | |
Exynox | 847ab2ef89 | |
Exynox | ebc479b7df | |
Exynox | 1ee687f269 | |
Exynox | d85ef28eac | |
Exynox | 01cc27a7df | |
Exynox | 72b495c03c | |
Exynox | 0c86f802ca | |
Exynox | 05a1406c7c | |
Exynox | 00c5634c09 | |
Exynox | 42079d56b7 |
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="PROJECT" charset="EUC-KR" />
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"cmake.configureOnOpen": true
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
FROM ubuntu:22.04 as build
|
||||
FROM ubuntu:latest as build
|
||||
WORKDIR /app
|
||||
|
||||
# Update the system and install various dependencies
|
||||
|
@ -21,7 +21,7 @@ RUN mkdir build/
|
|||
RUN cd build && cmake -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmake ..
|
||||
RUN cd build && make -j $(nproc)
|
||||
|
||||
FROM ubuntu:22.04 as app
|
||||
FROM ubuntu:latest as app
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update && apt-get install -y python2 libdevil-dev libbsd-dev && apt-get clean
|
||||
|
|
|
@ -41,8 +41,6 @@ tstr IMPLEMENTOR
|
|||
tint IMPLEMENTOR
|
||||
tcon IMPLEMENTOR
|
||||
mob_ld IMPLEMENTOR
|
||||
pcbang_check IMPLEMENTOR
|
||||
pcbang_update IMPLEMENTOR
|
||||
setqf IMPLEMENTOR
|
||||
delqf IMPLEMENTOR
|
||||
effect IMPLEMENTOR
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -174,8 +174,6 @@ guild.level
|
|||
guild.name
|
||||
guild.war_bet
|
||||
guild.war_enter
|
||||
highscore.register
|
||||
highscore.show
|
||||
horse.advance
|
||||
horse.feed
|
||||
horse.get_grade
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef __INC_METIN_II_COMMON_BILLING_H__
|
||||
#define __INC_METIN_II_COMMON_BILLING_H__
|
||||
|
||||
enum EBillingTypes
|
||||
{
|
||||
BILLING_NONE,
|
||||
BILLING_IP_FREE,
|
||||
BILLING_FREE,
|
||||
BILLING_IP_TIME,
|
||||
BILLING_IP_DAY,
|
||||
BILLING_TIME,
|
||||
BILLING_DAY,
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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
|
||||
|
@ -333,18 +333,20 @@ enum ELimitTypes
|
|||
LIMIT_DEX,
|
||||
LIMIT_INT,
|
||||
LIMIT_CON,
|
||||
|
||||
// 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
|
||||
|
|
|
@ -16,17 +16,15 @@ enum EMisc
|
|||
ABILITY_MAX_NUM = 50,
|
||||
EMPIRE_MAX_NUM = 4,
|
||||
BANWORD_MAX_LEN = 24,
|
||||
SMS_MAX_LEN = 80,
|
||||
MOBILE_MAX_LEN = 32,
|
||||
SOCIAL_ID_MAX_LEN = 18,
|
||||
MAP_ALLOW_MAX_LEN = 128,
|
||||
|
||||
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,
|
||||
|
||||
|
@ -80,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
|
||||
| 미사용 |
|
||||
| 미사용 |
|
||||
+------------------------------------------------------+ ??
|
||||
*/
|
||||
};
|
||||
|
@ -127,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 //
|
||||
};
|
||||
|
@ -141,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
|
||||
|
@ -163,7 +161,7 @@ enum EDirection
|
|||
DIR_MAX_NUM
|
||||
};
|
||||
|
||||
#define ABILITY_MAX_LEVEL 10 /* 기술 최대 레벨 */
|
||||
#define ABILITY_MAX_LEVEL 10 /* 기술 최대 레벨 */
|
||||
|
||||
enum EAbilityDifficulty
|
||||
{
|
||||
|
@ -176,9 +174,9 @@ enum EAbilityDifficulty
|
|||
|
||||
enum EAbilityCategory
|
||||
{
|
||||
CATEGORY_PHYSICAL, /* 신체적 어빌리티 */
|
||||
CATEGORY_MENTAL, /* 정신적 어빌리티 */
|
||||
CATEGORY_ATTRIBUTE, /* 능력 어빌리티 */
|
||||
CATEGORY_PHYSICAL, /* 신체적 어빌리티 */
|
||||
CATEGORY_MENTAL, /* 정신적 어빌리티 */
|
||||
CATEGORY_ATTRIBUTE, /* 능력 어빌리티 */
|
||||
CATEGORY_NUM_TYPES
|
||||
};
|
||||
|
||||
|
@ -248,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,
|
||||
|
@ -397,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, //
|
||||
|
@ -580,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,
|
||||
};
|
||||
|
@ -624,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
|
||||
};
|
||||
|
||||
|
@ -660,28 +658,18 @@ 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
|
||||
{
|
||||
TEENFLAG_NONE = 0,
|
||||
TEENFLAG_1HOUR,
|
||||
TEENFLAG_2HOUR,
|
||||
TEENFLAG_3HOUR,
|
||||
TEENFLAG_4HOUR,
|
||||
TEENFLAG_5HOUR,
|
||||
};
|
||||
|
||||
#include "item_length.h"
|
||||
|
||||
// inventory의 position을 나타내는 구조체
|
||||
// int와의 암시적 형변환이 있는 이유는,
|
||||
// 인벤 관련된 모든 함수가 window_type은 받지 않고, cell 하나만 받았기 때문에,(기존에는 인벤이 하나 뿐이어서 inventory type이란게 필요없었기 때문에,)
|
||||
// 인벤 관련 모든 함수 호출부분을 수정하는 것이 난감하기 ??문이다.
|
||||
// inventory의 position을 나타내는 구조체
|
||||
// int와의 암시적 형변환이 있는 이유는,
|
||||
// 인벤 관련된 모든 함수가 window_type은 받지 않고, cell 하나만 받았기 때문에,(기존에는 인벤이 하나 뿐이어서 inventory type이란게 필요없었기 때문에,)
|
||||
// 인벤 관련 모든 함수 호출부분을 수정하는 것이 난감하기 ??문이다.
|
||||
|
||||
enum EDragonSoulRefineWindowSize
|
||||
{
|
||||
|
@ -730,7 +718,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
|
||||
{
|
||||
|
@ -49,7 +49,6 @@ enum
|
|||
HEADER_GD_ADD_AFFECT = 32,
|
||||
HEADER_GD_REMOVE_AFFECT = 33,
|
||||
|
||||
HEADER_GD_HIGHSCORE_REGISTER = 34,
|
||||
HEADER_GD_ITEM_FLUSH = 35,
|
||||
|
||||
HEADER_GD_PARTY_CREATE = 36,
|
||||
|
@ -63,7 +62,6 @@ enum
|
|||
HEADER_GD_RELOAD_PROTO = 43,
|
||||
|
||||
HEADER_GD_CHANGE_NAME = 44,
|
||||
HEADER_GD_SMS = 45,
|
||||
|
||||
HEADER_GD_GUILD_CHANGE_LADDER_POINT = 46,
|
||||
HEADER_GD_GUILD_USE_SKILL = 47,
|
||||
|
@ -99,38 +97,27 @@ enum
|
|||
|
||||
HEADER_GD_AUTH_LOGIN = 100,
|
||||
HEADER_GD_LOGIN_BY_KEY = 101,
|
||||
HEADER_GD_BILLING_EXPIRE = 104,
|
||||
HEADER_GD_VCARD = 105,
|
||||
HEADER_GD_BILLING_CHECK = 106,
|
||||
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,
|
||||
|
||||
// PCBANG_IP_LIST_BY_AUTH
|
||||
HEADER_GD_PCBANG_REQUEST_IP_LIST = 111,
|
||||
HEADER_GD_PCBANG_CLEAR_IP_LIST = 112,
|
||||
HEADER_GD_PCBANG_INSERT_IP = 113,
|
||||
// END_OF_PCBANG_IP_LIST_BY_AUTH
|
||||
|
||||
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,
|
||||
HEADER_GD_BLOCK_COUNTRY_IP = 127, // 광대역 IP-Block
|
||||
HEADER_GD_BLOCK_EXCEPTION = 128, // 광대역 IP-Block 예외
|
||||
|
||||
HEADER_GD_REQ_CHANGE_GUILD_MASTER = 129,
|
||||
|
||||
|
@ -139,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,12 +225,6 @@ enum
|
|||
|
||||
HEADER_DG_CHANGE_CHARACTER_PRIV = 127,
|
||||
|
||||
HEADER_DG_BILLING_REPAIR = 128,
|
||||
HEADER_DG_BILLING_EXPIRE = 129,
|
||||
HEADER_DG_BILLING_LOGIN = 130,
|
||||
HEADER_DG_VCARD = 131,
|
||||
HEADER_DG_BILLING_CHECK = 132,
|
||||
|
||||
HEADER_DG_CREATE_OBJECT = 140,
|
||||
HEADER_DG_DELETE_OBJECT = 141,
|
||||
HEADER_DG_UPDATE_LAND = 142,
|
||||
|
@ -257,23 +238,21 @@ 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,
|
||||
HEADER_DG_UPDATE_MONARCH_INFO = 170,
|
||||
HEADER_DG_BLOCK_COUNTRY_IP = 171, // 광대역 IP-Block
|
||||
HEADER_DG_BLOCK_EXCEPTION = 172, // 광대역 IP-Block 예외 account
|
||||
|
||||
HEADER_DG_ACK_CHANGE_GUILD_MASTER = 173,
|
||||
|
||||
|
@ -364,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];
|
||||
|
||||
|
@ -441,7 +420,6 @@ typedef struct SPlayerTable
|
|||
|
||||
BYTE skill_group;
|
||||
LONG lAlignment;
|
||||
char szMobile[MOBILE_MAX_LEN + 1];
|
||||
|
||||
WORD stat_reset_count;
|
||||
|
||||
|
@ -572,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
|
||||
|
@ -638,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;
|
||||
|
||||
|
@ -681,7 +659,7 @@ typedef struct SPlayerLoadPacket
|
|||
{
|
||||
DWORD account_id;
|
||||
DWORD player_id;
|
||||
BYTE account_index; /* account 에서의 위치 */
|
||||
BYTE account_index; /* account 에서의 위치 */
|
||||
} TPlayerLoadPacket;
|
||||
|
||||
typedef struct SPlayerCreatePacket
|
||||
|
@ -758,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;
|
||||
|
@ -851,14 +829,6 @@ typedef struct SPacketGDRemoveAffect
|
|||
BYTE bApplyOn;
|
||||
} TPacketGDRemoveAffect;
|
||||
|
||||
typedef struct SPacketGDHighscore
|
||||
{
|
||||
DWORD dwPID;
|
||||
LONG lValue;
|
||||
char cDir;
|
||||
char szBoard[21];
|
||||
} TPacketGDHighscore;
|
||||
|
||||
typedef struct SPacketPartyCreate
|
||||
{
|
||||
DWORD dwLeaderPID;
|
||||
|
@ -938,8 +908,8 @@ typedef struct SPacketGuildWar
|
|||
LONG lInitialScore;
|
||||
} TPacketGuildWar;
|
||||
|
||||
// Game -> DB : 상대적 변화값
|
||||
// DB -> Game : 토탈된 최종값
|
||||
// Game -> DB : 상대적 변화값
|
||||
// DB -> Game : 토탈된 최종값
|
||||
typedef struct SPacketGuildWarScore
|
||||
{
|
||||
DWORD dwGuildGainPoint;
|
||||
|
@ -960,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;
|
||||
|
||||
|
@ -997,14 +967,6 @@ typedef struct SPacketGuildLadderPoint
|
|||
LONG lChange;
|
||||
} TPacketGuildLadderPoint;
|
||||
|
||||
typedef struct SPacketGDSMS
|
||||
{
|
||||
char szFrom[CHARACTER_NAME_MAX_LEN + 1];
|
||||
char szTo[CHARACTER_NAME_MAX_LEN + 1];
|
||||
char szMobile[MOBILE_MAX_LEN + 1];
|
||||
char szMsg[SMS_MAX_LEN + 1];
|
||||
} TPacketGDSMS;
|
||||
|
||||
typedef struct SPacketGuildUseSkill
|
||||
{
|
||||
DWORD dwGuild;
|
||||
|
@ -1032,9 +994,7 @@ typedef struct SPacketGDAuthLogin
|
|||
char szLogin[LOGIN_MAX_LEN + 1];
|
||||
char szSocialID[SOCIAL_ID_MAX_LEN + 1];
|
||||
DWORD adwClientKey[4];
|
||||
BYTE bBillType;
|
||||
DWORD dwBillID;
|
||||
DWORD iPremiumTimes[PREMIUM_MAX_NUM];
|
||||
DWORD iPremiumTimes[PREMIUM_MAX_NUM];
|
||||
} TPacketGDAuthLogin;
|
||||
|
||||
typedef struct SPacketGDLoginByKey
|
||||
|
@ -1046,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
|
||||
{
|
||||
|
@ -1088,7 +1048,7 @@ typedef struct SPacketDGChangeCharacterPriv
|
|||
} TPacketDGChangeCharacterPriv;
|
||||
|
||||
/**
|
||||
* @version 05/06/08 Bang2ni - 지속시간 추가
|
||||
* @version 05/06/08 Bang2ni - 지속시간 추가
|
||||
*/
|
||||
typedef struct SPacketDGChangeGuildPriv
|
||||
{
|
||||
|
@ -1096,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
|
||||
|
@ -1146,26 +1106,6 @@ typedef struct SPacketSetEventFlag
|
|||
LONG lValue;
|
||||
} TPacketSetEventFlag;
|
||||
|
||||
typedef struct SPacketBillingLogin
|
||||
{
|
||||
DWORD dwLoginKey;
|
||||
BYTE bLogin;
|
||||
} TPacketBillingLogin;
|
||||
|
||||
typedef struct SPacketBillingRepair
|
||||
{
|
||||
DWORD dwLoginKey;
|
||||
char szLogin[LOGIN_MAX_LEN + 1];
|
||||
char szHost[MAX_HOST_LENGTH + 1];
|
||||
} TPacketBillingRepair;
|
||||
|
||||
typedef struct SPacketBillingExpire
|
||||
{
|
||||
char szLogin[LOGIN_MAX_LEN + 1];
|
||||
BYTE bBillType;
|
||||
DWORD dwRemainSeconds;
|
||||
} TPacketBillingExpire;
|
||||
|
||||
typedef struct SPacketLoginOnSetup
|
||||
{
|
||||
DWORD dwID;
|
||||
|
@ -1193,15 +1133,6 @@ typedef struct SPacketGDHammerOfTor
|
|||
DWORD delay;
|
||||
} TPacketGDHammerOfTor;
|
||||
|
||||
typedef struct SPacketGDVCard
|
||||
{
|
||||
DWORD dwID;
|
||||
char szSellCharacter[CHARACTER_NAME_MAX_LEN + 1];
|
||||
char szSellAccount[LOGIN_MAX_LEN + 1];
|
||||
char szBuyCharacter[CHARACTER_NAME_MAX_LEN + 1];
|
||||
char szBuyAccount[LOGIN_MAX_LEN + 1];
|
||||
} TPacketGDVCard;
|
||||
|
||||
typedef struct SGuildReserve
|
||||
{
|
||||
DWORD dwID;
|
||||
|
@ -1277,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
|
||||
|
@ -1306,24 +1237,15 @@ typedef struct
|
|||
LONG lDuration;
|
||||
} TPacketBlockChat;
|
||||
|
||||
// PCBANG_IP_LIST
|
||||
typedef struct SPacketPCBangIP
|
||||
{
|
||||
DWORD id;
|
||||
DWORD ip;
|
||||
} TPacketPCBangIP;
|
||||
// END_OF_PCBANG_IP_LIST
|
||||
|
||||
|
||||
//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
|
||||
|
||||
|
@ -1344,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;
|
||||
|
@ -1379,26 +1301,6 @@ typedef struct tChangeMonarchLordACK
|
|||
char szDate[32];
|
||||
} TPacketChangeMonarchLordACK;
|
||||
|
||||
// Block Country Ip
|
||||
typedef struct tBlockCountryIp
|
||||
{
|
||||
DWORD ip_from;
|
||||
DWORD ip_to;
|
||||
} TPacketBlockCountryIp;
|
||||
|
||||
enum EBlockExceptionCommand
|
||||
{
|
||||
BLOCK_EXCEPTION_CMD_ADD = 1,
|
||||
BLOCK_EXCEPTION_CMD_DEL = 2,
|
||||
};
|
||||
|
||||
// Block Exception Account
|
||||
typedef struct tBlockException
|
||||
{
|
||||
BYTE cmd; // 1 == add, 2 == delete
|
||||
char login[LOGIN_MAX_LEN + 1];
|
||||
}TPacketBlockException;
|
||||
|
||||
typedef struct tChangeGuildMaster
|
||||
{
|
||||
DWORD dwGuildID;
|
||||
|
@ -1429,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;
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
/*********************************************************************
|
||||
* date : 2007.06.07
|
||||
* file : teen_packet.h
|
||||
* author : mhh
|
||||
* description :
|
||||
*/
|
||||
|
||||
#ifndef _teen_packet_h_
|
||||
#define _teen_packet_h_
|
||||
|
||||
#define HEADER_GT_LOGIN 0x10
|
||||
#define HEADER_GT_LOGOUT 0x11
|
||||
|
||||
|
||||
#define HEADER_TG_TEEN_NOTICE 0x12
|
||||
#define HEADER_TG_FORCE_LOGOUT 0x13
|
||||
#define HEADER_TG_LOGIN_NOTICE 0x14
|
||||
|
||||
#endif /* _teen_packet_h_ */
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -1,214 +0,0 @@
|
|||
// vim:ts=4 sw=4
|
||||
/*********************************************************************
|
||||
* date : 2007.05.31
|
||||
* file : BlockCountry.cpp
|
||||
* author : mhh
|
||||
* description :
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "BlockCountry.h"
|
||||
|
||||
#include "DBManager.h"
|
||||
|
||||
#define DO_ALL_BLOCK_IP(iter) \
|
||||
for ((iter) = m_block_ip.begin(); (iter) != m_block_ip.end(); ++(iter))
|
||||
|
||||
#define DO_ALL_BLOCK_EXCEPTION(iter) \
|
||||
for ((iter) = m_block_exception.begin(); (iter) != m_block_exception.end(); ++(iter))
|
||||
|
||||
CBlockCountry::CBlockCountry()
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
CBlockCountry::~CBlockCountry()
|
||||
{
|
||||
BLOCK_IP *block_ip;
|
||||
BLOCK_IP_VECTOR::iterator iter;
|
||||
|
||||
DO_ALL_BLOCK_IP(iter)
|
||||
{
|
||||
block_ip = *iter;
|
||||
delete block_ip;
|
||||
}
|
||||
|
||||
m_block_ip.clear();
|
||||
}
|
||||
|
||||
|
||||
bool CBlockCountry::Load()
|
||||
{
|
||||
// load blocked ip
|
||||
{
|
||||
char szQuery[256];
|
||||
snprintf(szQuery, sizeof(szQuery), "SELECT IP_FROM, IP_TO, COUNTRY_NAME FROM iptocountry");
|
||||
SQLMsg * pMsg = CDBManager::instance().DirectQuery(szQuery, SQL_ACCOUNT);
|
||||
|
||||
if (pMsg->Get()->uiNumRows == 0)
|
||||
{
|
||||
SPDLOG_ERROR(" DirectQuery failed({})", szQuery);
|
||||
delete pMsg;
|
||||
return false;
|
||||
}
|
||||
|
||||
MYSQL_ROW row;
|
||||
for (int n = 0; (row = mysql_fetch_row(pMsg->Get()->pSQLResult)) != NULL; ++n)
|
||||
{
|
||||
BLOCK_IP *block_ip = new BLOCK_IP;
|
||||
block_ip->ip_from = strtoul(row[0], NULL, 10);
|
||||
block_ip->ip_to = strtoul(row[1], NULL, 10);
|
||||
strlcpy(block_ip->country, row[2], sizeof(block_ip->country));
|
||||
|
||||
m_block_ip.push_back(block_ip);
|
||||
SPDLOG_DEBUG("BLOCKED_IP : {} - {}", block_ip->ip_from, block_ip->ip_to);
|
||||
|
||||
}
|
||||
delete pMsg;
|
||||
}
|
||||
|
||||
|
||||
// load block exception account
|
||||
{
|
||||
char szQuery[256];
|
||||
snprintf(szQuery, sizeof(szQuery), "SELECT login FROM block_exception");
|
||||
SQLMsg * pMsg = CDBManager::instance().DirectQuery(szQuery, SQL_ACCOUNT);
|
||||
|
||||
if (pMsg->Get()->uiNumRows == 0)
|
||||
{
|
||||
SPDLOG_ERROR(" DirectQuery failed({})", szQuery);
|
||||
delete pMsg;
|
||||
return true;
|
||||
}
|
||||
|
||||
MYSQL_ROW row;
|
||||
for (int n = 0; (row = mysql_fetch_row(pMsg->Get()->pSQLResult)) != NULL; ++n)
|
||||
{
|
||||
const char *login = row[0];
|
||||
|
||||
m_block_exception.push_back(strdup(login));
|
||||
|
||||
SPDLOG_DEBUG("BLOCK_EXCEPTION = {}", login);
|
||||
|
||||
}
|
||||
delete pMsg;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBlockCountry::IsBlockedCountryIp(const char *user_ip)
|
||||
{
|
||||
BLOCK_IP* block_ip;
|
||||
BLOCK_IP_VECTOR::iterator iter;
|
||||
struct in_addr st_addr;
|
||||
|
||||
#ifndef __WIN32__
|
||||
if (0 == inet_aton(user_ip, &st_addr))
|
||||
#else
|
||||
unsigned int in_address;
|
||||
in_address = inet_addr(user_ip);
|
||||
st_addr.s_addr = in_address;
|
||||
if (INADDR_NONE == in_address)
|
||||
#endif
|
||||
return true; // 아이피가 괴상하니 일단 블럭처리
|
||||
|
||||
DO_ALL_BLOCK_IP(iter)
|
||||
{
|
||||
block_ip = *iter;
|
||||
|
||||
if (st_addr.s_addr >= block_ip->ip_from && st_addr.s_addr <= block_ip->ip_to)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CBlockCountry::SendBlockedCountryIp(CPeer *peer)
|
||||
{
|
||||
SPDLOG_DEBUG("SendBlockedCountryIp start");
|
||||
BLOCK_IP *block_ip;
|
||||
BLOCK_IP_VECTOR::iterator iter;
|
||||
TPacketBlockCountryIp packet;
|
||||
|
||||
DO_ALL_BLOCK_IP(iter)
|
||||
{
|
||||
block_ip = *iter;
|
||||
|
||||
packet.ip_from = block_ip->ip_from;
|
||||
packet.ip_to = block_ip->ip_to;
|
||||
|
||||
peer->EncodeHeader(HEADER_DG_BLOCK_COUNTRY_IP, 0, sizeof(TPacketBlockCountryIp));
|
||||
peer->Encode(&packet, sizeof(packet));
|
||||
}
|
||||
|
||||
SPDLOG_DEBUG("[DONE] CBlockCountry::SendBlockedCountryIp() : count = {}",
|
||||
m_block_ip.size());
|
||||
SPDLOG_DEBUG("SendBlockedCountryIp end");
|
||||
} /* end of CBlockCountry::SendBlockedCountryIp() */
|
||||
|
||||
|
||||
void CBlockCountry::SendBlockException(CPeer *peer)
|
||||
{
|
||||
BLOCK_EXCEPTION_VECTOR::iterator iter;
|
||||
|
||||
DO_ALL_BLOCK_EXCEPTION(iter)
|
||||
{
|
||||
const char *login = *iter;
|
||||
|
||||
this->SendBlockExceptionOne(peer, login, BLOCK_EXCEPTION_CMD_ADD);
|
||||
}
|
||||
} /* end of CBlockCountry::SendBlockException() */
|
||||
|
||||
void CBlockCountry::SendBlockExceptionOne(CPeer *peer, const char *login, BYTE cmd)
|
||||
{
|
||||
if (NULL == peer || NULL == login)
|
||||
return;
|
||||
|
||||
if (BLOCK_EXCEPTION_CMD_ADD != cmd && BLOCK_EXCEPTION_CMD_DEL != cmd)
|
||||
return;
|
||||
|
||||
TPacketBlockException packet;
|
||||
|
||||
packet.cmd = cmd;
|
||||
strlcpy(packet.login, login, sizeof(packet.login));
|
||||
|
||||
peer->EncodeHeader(HEADER_DG_BLOCK_EXCEPTION, 0, sizeof(TPacketBlockException));
|
||||
peer->Encode(&packet, sizeof(packet));
|
||||
}
|
||||
|
||||
void CBlockCountry::AddBlockException(const char *login)
|
||||
{
|
||||
BLOCK_EXCEPTION_VECTOR::iterator iter;
|
||||
DO_ALL_BLOCK_EXCEPTION(iter)
|
||||
{
|
||||
const char *saved_login = *iter;
|
||||
|
||||
if (!strcmp(saved_login, login))
|
||||
return;
|
||||
}
|
||||
|
||||
m_block_exception.push_back(strdup(login));
|
||||
return;
|
||||
}
|
||||
|
||||
void CBlockCountry::DelBlockException(const char *login)
|
||||
{
|
||||
BLOCK_EXCEPTION_VECTOR::iterator iter;
|
||||
DO_ALL_BLOCK_EXCEPTION(iter)
|
||||
{
|
||||
const char *saved_login = *iter;
|
||||
|
||||
if (!strcmp(saved_login, login))
|
||||
{
|
||||
::free((void*)saved_login);
|
||||
m_block_exception.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
// vim: ts=4 sw=4
|
||||
// Date : 2007.05.31
|
||||
// File : BlockCountry.h
|
||||
// Author : mhh
|
||||
// Description :
|
||||
|
||||
#ifndef __INC_METIN_II_BLOCKCOUNTRY_H__
|
||||
#define __INC_METIN_II_BLOCKCOUNTRY_H__
|
||||
|
||||
#include "Peer.h"
|
||||
|
||||
#define MAX_COUNTRY_NAME_LENGTH 50
|
||||
|
||||
class CBlockCountry : public singleton<CBlockCountry>
|
||||
{
|
||||
private:
|
||||
struct BLOCK_IP
|
||||
{
|
||||
DWORD ip_from;
|
||||
DWORD ip_to;
|
||||
char country[MAX_COUNTRY_NAME_LENGTH + 1];
|
||||
};
|
||||
|
||||
typedef std::vector<BLOCK_IP*> BLOCK_IP_VECTOR;
|
||||
BLOCK_IP_VECTOR m_block_ip;
|
||||
|
||||
typedef std::vector<const char*> BLOCK_EXCEPTION_VECTOR;
|
||||
BLOCK_EXCEPTION_VECTOR m_block_exception;
|
||||
|
||||
public:
|
||||
CBlockCountry();
|
||||
~CBlockCountry();
|
||||
|
||||
public:
|
||||
bool Load();
|
||||
bool IsBlockedCountryIp(const char *user_ip);
|
||||
void SendBlockedCountryIp(CPeer *peer);
|
||||
void SendBlockException(CPeer *peer);
|
||||
void SendBlockExceptionOne(CPeer *peer, const char *login, BYTE cmd);
|
||||
void AddBlockException(const char *login);
|
||||
void DelBlockException(const char *login);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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:
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "stdafx.h"
|
||||
|
||||
#include <common/billing.h>
|
||||
#include <common/building.h>
|
||||
#include <common/VnumHelper.h>
|
||||
#include "../../libgame/include/grid.h"
|
||||
|
@ -17,7 +16,6 @@
|
|||
#include "ItemAwardManager.h"
|
||||
#include "Marriage.h"
|
||||
#include "Monarch.h"
|
||||
#include "BlockCountry.h"
|
||||
#include "ItemIDRangeManager.h"
|
||||
#include "Cache.h"
|
||||
#ifdef __AUCTION__
|
||||
|
@ -248,7 +246,7 @@ bool CClientManager::Initialize()
|
|||
|
||||
LoadEventFlag();
|
||||
|
||||
// database character-set을 강제로 맞춤
|
||||
// database character-set을 강제로 맞춤
|
||||
if (g_stLocale == "big5" || g_stLocale == "sjis")
|
||||
CDBManager::instance().QueryLocaleSet();
|
||||
|
||||
|
@ -261,7 +259,7 @@ void CClientManager::MainLoop()
|
|||
|
||||
SPDLOG_DEBUG("ClientManager pointer is {}", (void*) this);
|
||||
|
||||
// 메인루프
|
||||
// 메인루프
|
||||
while (!m_bShutdowned)
|
||||
{
|
||||
while ((tmp = CDBManager::instance().PopResult()))
|
||||
|
@ -275,7 +273,7 @@ void CClientManager::MainLoop()
|
|||
}
|
||||
|
||||
//
|
||||
// 메인루프 종료처리
|
||||
// 메인루프 종료처리
|
||||
//
|
||||
SPDLOG_DEBUG("MainLoop exited, Starting cache flushing");
|
||||
|
||||
|
@ -283,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;
|
||||
|
@ -295,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;
|
||||
|
@ -307,7 +305,7 @@ void CClientManager::MainLoop()
|
|||
|
||||
// MYSHOP_PRICE_LIST
|
||||
//
|
||||
// 개인상점 아이템 가격 리스트 Flush
|
||||
// 개인상점 아이템 가격 리스트 Flush
|
||||
//
|
||||
for (itertype(m_mapItemPriceListCache) itPriceList = m_mapItemPriceListCache.begin(); itPriceList != m_mapItemPriceListCache.end(); ++itPriceList)
|
||||
{
|
||||
|
@ -327,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;
|
||||
|
@ -584,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)
|
||||
{
|
||||
|
@ -611,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)))
|
||||
{
|
||||
|
@ -677,8 +675,8 @@ void CClientManager::RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg)
|
|||
}
|
||||
|
||||
|
||||
// 쿼리에 에러가 있었으므로 응답할 경우 창고가 비어있는 것 처럼
|
||||
// 보이기 때문에 창고가 아얘 안열리는게 나음
|
||||
// 쿼리에 에러가 있었으므로 응답할 경우 창고가 비어있는 것 처럼
|
||||
// 보이기 때문에 창고가 아얘 안열리는게 나음
|
||||
if (!msg->Get()->pSQLResult)
|
||||
{
|
||||
SPDLOG_ERROR("null safebox result");
|
||||
|
@ -787,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)
|
||||
|
@ -900,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];
|
||||
|
||||
|
@ -988,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;
|
||||
|
@ -1007,7 +1005,7 @@ void CClientManager::RESULT_PRICELIST_LOAD(CPeer* peer, SQLMsg* pMsg)
|
|||
PutItemPriceListCache(&table);
|
||||
|
||||
//
|
||||
// 로드한 데이터를 Game server 에 전송
|
||||
// 로드한 데이터를 Game server 에 전송
|
||||
//
|
||||
|
||||
TPacketMyshopPricelistHeader header;
|
||||
|
@ -1031,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;
|
||||
|
@ -1093,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)
|
||||
|
@ -1144,7 +1142,6 @@ void CClientManager::QUERY_SETUP(CPeer * peer, DWORD dwHandle, const char * c_pD
|
|||
SPDLOG_DEBUG("AUTH_PEER ptr {}", (void*) peer);
|
||||
|
||||
m_pkAuthPeer = peer;
|
||||
SendAllLoginToBilling();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1155,7 +1152,7 @@ void CClientManager::QUERY_SETUP(CPeer * peer, DWORD dwHandle, const char * c_pD
|
|||
peer->SetMaps(p->alMaps);
|
||||
|
||||
//
|
||||
// 어떤 맵이 어떤 서버에 있는지 보내기
|
||||
// 어떤 맵이 어떤 서버에 있는지 보내기
|
||||
//
|
||||
TMapLocation kMapLocations;
|
||||
|
||||
|
@ -1262,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);
|
||||
|
||||
|
@ -1278,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;
|
||||
|
||||
|
@ -1287,10 +1284,9 @@ void CClientManager::QUERY_SETUP(CPeer * peer, DWORD dwHandle, const char * c_pD
|
|||
}
|
||||
|
||||
//
|
||||
// 로그인 및 빌링정보 보내기
|
||||
// Log in the player
|
||||
//
|
||||
TPacketLoginOnSetup * pck = (TPacketLoginOnSetup *) c_pData;;
|
||||
std::vector<TPacketBillingRepair> vec_repair;
|
||||
TPacketLoginOnSetup * pck = (TPacketLoginOnSetup *) c_pData;
|
||||
|
||||
for (DWORD c = 0; c < p->dwLoginCount; ++c, ++pck)
|
||||
{
|
||||
|
@ -1313,29 +1309,11 @@ void CClientManager::QUERY_SETUP(CPeer * peer, DWORD dwHandle, const char * c_pD
|
|||
{
|
||||
SPDLOG_DEBUG("SETUP: login {} {} login_key {} host {}", pck->dwID, pck->szLogin, pck->dwLoginKey, pck->szHost);
|
||||
pkLD->SetPlay(true);
|
||||
|
||||
if (m_pkAuthPeer)
|
||||
{
|
||||
TPacketBillingRepair pck_repair;
|
||||
pck_repair.dwLoginKey = pkLD->GetKey();
|
||||
strlcpy(pck_repair.szLogin, pck->szLogin, sizeof(pck_repair.szLogin));
|
||||
strlcpy(pck_repair.szHost, pck->szHost, sizeof(pck_repair.szHost));
|
||||
vec_repair.push_back(pck_repair);
|
||||
}
|
||||
}
|
||||
else
|
||||
SPDLOG_DEBUG("SETUP: login_fail {} {} login_key {}", pck->dwID, pck->szLogin, pck->dwLoginKey);
|
||||
}
|
||||
|
||||
if (m_pkAuthPeer && !vec_repair.empty())
|
||||
{
|
||||
SPDLOG_DEBUG("REPAIR size {}", vec_repair.size());
|
||||
|
||||
m_pkAuthPeer->EncodeHeader(HEADER_DG_BILLING_REPAIR, 0, sizeof(DWORD) + sizeof(TPacketBillingRepair) * vec_repair.size());
|
||||
m_pkAuthPeer->EncodeDWORD(vec_repair.size());
|
||||
m_pkAuthPeer->Encode(&vec_repair[0], sizeof(TPacketBillingRepair) * vec_repair.size());
|
||||
}
|
||||
|
||||
SendPartyOnSetup(peer);
|
||||
CGuildManager::instance().OnSetup(peer);
|
||||
CPrivManager::instance().SendPrivOnSetup(peer);
|
||||
|
@ -1359,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)
|
||||
{
|
||||
|
@ -1495,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);
|
||||
|
@ -1503,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())
|
||||
|
@ -1522,7 +1500,7 @@ void CClientManager::PutItemCache(TPlayerItem * pNew, bool bSkipQuery)
|
|||
}
|
||||
}
|
||||
|
||||
// 새로운 정보 업데이트
|
||||
// 새로운 정보 업데이트
|
||||
c->Put(pNew, bSkipQuery);
|
||||
|
||||
TItemCacheSetPtrMap::iterator it = m_map_pkItemCacheSetPtr.find(c->Get()->owner);
|
||||
|
@ -1534,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();
|
||||
|
@ -1591,7 +1569,7 @@ void CClientManager::UpdatePlayerCache()
|
|||
|
||||
c->Flush();
|
||||
|
||||
// Item Cache도 업데이트
|
||||
// Item Cache도 업데이트
|
||||
UpdateItemCacheSet(c->Get()->id);
|
||||
}
|
||||
else if (c->CheckFlushTimeout())
|
||||
|
@ -1617,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);
|
||||
|
@ -1662,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);
|
||||
|
@ -1687,22 +1665,6 @@ void CClientManager::QUERY_FLUSH_CACHE(CPeer * pkPeer, const char * c_pData)
|
|||
delete pkCache;
|
||||
}
|
||||
|
||||
void CClientManager::QUERY_SMS(CPeer * pkPeer, TPacketGDSMS * pack)
|
||||
{
|
||||
char szQuery[QUERY_MAX_LEN];
|
||||
|
||||
char szMsg[256+1];
|
||||
//unsigned int len = CDBManager::instance().EscapeString(szMsg, pack->szMsg, strlen(pack->szMsg), SQL_ACCOUNT);
|
||||
unsigned int len = CDBManager::instance().EscapeString(szMsg, pack->szMsg, strlen(pack->szMsg));
|
||||
szMsg[len] = '\0';
|
||||
|
||||
snprintf(szQuery, sizeof(szQuery),
|
||||
"INSERT INTO sms_pool (server, sender, receiver, mobile, msg) VALUES(%d, '%s', '%s', '%s', '%s')",
|
||||
(m_iPlayerIDStart + 2) / 3, pack->szFrom, pack->szTo, pack->szMobile, szMsg);
|
||||
|
||||
CDBManager::instance().AsyncQuery(szQuery);
|
||||
}
|
||||
|
||||
void CClientManager::QUERY_RELOAD_PROTO()
|
||||
{
|
||||
if (!InitializeTables())
|
||||
|
@ -1740,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)
|
||||
{
|
||||
|
@ -1844,8 +1806,6 @@ void CClientManager::QUERY_AUTH_LOGIN(CPeer * pkPeer, DWORD dwHandle, TPacketGDA
|
|||
|
||||
pkLD->SetKey(p->dwLoginKey);
|
||||
pkLD->SetClientKey(p->adwClientKey);
|
||||
pkLD->SetBillType(p->bBillType);
|
||||
pkLD->SetBillID(p->dwBillID);
|
||||
pkLD->SetPremium(p->iPremiumTimes);
|
||||
|
||||
TAccountTable & r = pkLD->GetAccountRef();
|
||||
|
@ -1868,109 +1828,6 @@ void CClientManager::QUERY_AUTH_LOGIN(CPeer * pkPeer, DWORD dwHandle, TPacketGDA
|
|||
}
|
||||
}
|
||||
|
||||
void CClientManager::BillingExpire(TPacketBillingExpire * p)
|
||||
{
|
||||
char key[LOGIN_MAX_LEN + 1];
|
||||
trim_and_lower(p->szLogin, key, sizeof(key));
|
||||
|
||||
switch (p->bBillType)
|
||||
{
|
||||
case BILLING_IP_TIME:
|
||||
case BILLING_IP_DAY:
|
||||
{
|
||||
DWORD dwIPID = 0;
|
||||
str_to_number(dwIPID, p->szLogin);
|
||||
|
||||
TLogonAccountMap::iterator it = m_map_kLogonAccount.begin();
|
||||
|
||||
while (it != m_map_kLogonAccount.end())
|
||||
{
|
||||
CLoginData * pkLD = (it++)->second;
|
||||
|
||||
if (pkLD->GetBillID() == dwIPID)
|
||||
{
|
||||
CPeer * pkPeer = GetPeer(pkLD->GetConnectedPeerHandle());
|
||||
|
||||
if (pkPeer)
|
||||
{
|
||||
strlcpy(p->szLogin, pkLD->GetAccountRef().login, sizeof(p->szLogin));
|
||||
pkPeer->EncodeHeader(HEADER_DG_BILLING_EXPIRE, 0, sizeof(TPacketBillingExpire));
|
||||
pkPeer->Encode(p, sizeof(TPacketBillingExpire));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BILLING_TIME:
|
||||
case BILLING_DAY:
|
||||
{
|
||||
TLogonAccountMap::iterator it = m_map_kLogonAccount.find(key);
|
||||
|
||||
if (it != m_map_kLogonAccount.end())
|
||||
{
|
||||
CLoginData * pkLD = it->second;
|
||||
|
||||
CPeer * pkPeer = GetPeer(pkLD->GetConnectedPeerHandle());
|
||||
|
||||
if (pkPeer)
|
||||
{
|
||||
pkPeer->EncodeHeader(HEADER_DG_BILLING_EXPIRE, 0, sizeof(TPacketBillingExpire));
|
||||
pkPeer->Encode(p, sizeof(TPacketBillingExpire));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CClientManager::BillingCheck(const char * data)
|
||||
{
|
||||
if (!m_pkAuthPeer)
|
||||
return;
|
||||
|
||||
time_t curTime = GetCurrentTime();
|
||||
|
||||
DWORD dwCount = *(DWORD *) data;
|
||||
data += sizeof(DWORD);
|
||||
|
||||
std::vector<DWORD> vec;
|
||||
|
||||
SPDLOG_DEBUG("BillingCheck: size {}", dwCount);
|
||||
|
||||
for (DWORD i = 0; i < dwCount; ++i)
|
||||
{
|
||||
DWORD dwKey = *(DWORD *) data;
|
||||
data += sizeof(DWORD);
|
||||
|
||||
SPDLOG_DEBUG("BillingCheck: {}", dwKey);
|
||||
|
||||
TLoginDataByLoginKey::iterator it = m_map_pkLoginData.find(dwKey);
|
||||
|
||||
if (it == m_map_pkLoginData.end())
|
||||
{
|
||||
SPDLOG_DEBUG("BillingCheck: key not exist: {}", dwKey);
|
||||
vec.push_back(dwKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
CLoginData * pkLD = it->second;
|
||||
|
||||
if (!pkLD->IsPlay() && curTime - pkLD->GetLastPlayTime() > 180)
|
||||
{
|
||||
SPDLOG_DEBUG("BillingCheck: not login: {}", dwKey);
|
||||
vec.push_back(dwKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_pkAuthPeer->EncodeHeader(HEADER_DG_BILLING_CHECK, 0, sizeof(DWORD) + sizeof(DWORD) * vec.size());
|
||||
m_pkAuthPeer->EncodeDWORD(vec.size());
|
||||
|
||||
if (!vec.empty())
|
||||
m_pkAuthPeer->Encode(&vec[0], sizeof(DWORD) * vec.size());
|
||||
}
|
||||
|
||||
void CClientManager::GuildDepositMoney(TPacketGDGuildMoney* p)
|
||||
{
|
||||
CGuildManager::instance().DepositMoney(p->dwGuild, p->iGold);
|
||||
|
@ -1991,51 +1848,6 @@ void CClientManager::GuildWarBet(TPacketGDGuildWarBet * p)
|
|||
CGuildManager::instance().Bet(p->dwWarID, p->szLogin, p->dwGold, p->dwGuild);
|
||||
}
|
||||
|
||||
void CClientManager::SendAllLoginToBilling()
|
||||
{
|
||||
if (!m_pkAuthPeer)
|
||||
return;
|
||||
|
||||
std::vector<TPacketBillingRepair> vec;
|
||||
TPacketBillingRepair p;
|
||||
|
||||
TLogonAccountMap::iterator it = m_map_kLogonAccount.begin();
|
||||
|
||||
while (it != m_map_kLogonAccount.end())
|
||||
{
|
||||
CLoginData * pkLD = (it++)->second;
|
||||
|
||||
p.dwLoginKey = pkLD->GetKey();
|
||||
strlcpy(p.szLogin, pkLD->GetAccountRef().login, sizeof(p.szLogin));
|
||||
strlcpy(p.szHost, pkLD->GetIP(), sizeof(p.szHost));
|
||||
SPDLOG_DEBUG("SendAllLoginToBilling {} {}", pkLD->GetAccountRef().login, pkLD->GetIP());
|
||||
vec.push_back(p);
|
||||
}
|
||||
|
||||
if (!vec.empty())
|
||||
{
|
||||
m_pkAuthPeer->EncodeHeader(HEADER_DG_BILLING_REPAIR, 0, sizeof(DWORD) + sizeof(TPacketBillingRepair) * vec.size());
|
||||
m_pkAuthPeer->EncodeDWORD(vec.size());
|
||||
m_pkAuthPeer->Encode(&vec[0], sizeof(TPacketBillingRepair) * vec.size());
|
||||
}
|
||||
}
|
||||
|
||||
void CClientManager::SendLoginToBilling(CLoginData * pkLD, bool bLogin)
|
||||
{
|
||||
if (!m_pkAuthPeer)
|
||||
return;
|
||||
|
||||
TPacketBillingLogin p;
|
||||
|
||||
p.dwLoginKey = pkLD->GetKey();
|
||||
p.bLogin = bLogin ? 1 : 0;
|
||||
|
||||
DWORD dwCount = 1;
|
||||
m_pkAuthPeer->EncodeHeader(HEADER_DG_BILLING_LOGIN, 0, sizeof(DWORD) + sizeof(TPacketBillingLogin));
|
||||
m_pkAuthPeer->EncodeDWORD(dwCount);
|
||||
m_pkAuthPeer->Encode(&p, sizeof(TPacketBillingLogin));
|
||||
}
|
||||
|
||||
void CClientManager::CreateObject(TPacketGDCreateObject * p)
|
||||
{
|
||||
using namespace building;
|
||||
|
@ -2125,28 +1937,6 @@ void CClientManager::UpdateLand(DWORD * pdw)
|
|||
ForwardPacket(HEADER_DG_UPDATE_LAND, p, sizeof(building::TLand));
|
||||
}
|
||||
|
||||
void CClientManager::VCard(TPacketGDVCard * p)
|
||||
{
|
||||
SPDLOG_DEBUG("VCARD: {} {} {} {} {}",
|
||||
p->dwID, p->szSellCharacter, p->szSellAccount, p->szBuyCharacter, p->szBuyAccount);
|
||||
|
||||
m_queue_vcard.push(*p);
|
||||
}
|
||||
|
||||
void CClientManager::VCardProcess()
|
||||
{
|
||||
if (!m_pkAuthPeer)
|
||||
return;
|
||||
|
||||
while (!m_queue_vcard.empty())
|
||||
{
|
||||
m_pkAuthPeer->EncodeHeader(HEADER_DG_VCARD, 0, sizeof(TPacketGDVCard));
|
||||
m_pkAuthPeer->Encode(&m_queue_vcard.front(), sizeof(TPacketGDVCard));
|
||||
|
||||
m_queue_vcard.pop();
|
||||
}
|
||||
}
|
||||
|
||||
// BLOCK_CHAT
|
||||
void CClientManager::BlockChat(TPacketBlockChat* p)
|
||||
{
|
||||
|
@ -2220,8 +2010,8 @@ void CClientManager::WeddingEnd(TPacketWeddingEnd * p)
|
|||
}
|
||||
|
||||
//
|
||||
// 캐시에 가격정보가 있으면 캐시를 업데이트 하고 캐시에 가격정보가 없다면
|
||||
// 우선 기존의 데이터를 로드한 뒤에 기존의 정보로 캐시를 만들고 새로 받은 가격정보를 업데이트 한다.
|
||||
// 캐시에 가격정보가 있으면 캐시를 업데이트 하고 캐시에 가격정보가 없다면
|
||||
// 우선 기존의 데이터를 로드한 뒤에 기존의 정보로 캐시를 만들고 새로 받은 가격정보를 업데이트 한다.
|
||||
//
|
||||
void CClientManager::MyshopPricelistUpdate(const TPacketMyshopPricelistHeader* pPacket)
|
||||
{
|
||||
|
@ -2262,7 +2052,7 @@ void CClientManager::MyshopPricelistUpdate(const TPacketMyshopPricelistHeader* p
|
|||
}
|
||||
|
||||
// MYSHOP_PRICE_LIST
|
||||
// 캐시된 가격정보가 있으면 캐시를 읽어 바로 전송하고 캐시에 정보가 없으면 DB 에 쿼리를 한다.
|
||||
// 캐시된 가격정보가 있으면 캐시를 읽어 바로 전송하고 캐시에 정보가 없으면 DB 에 쿼리를 한다.
|
||||
//
|
||||
void CClientManager::MyshopPricelistRequest(CPeer* peer, DWORD dwHandle, DWORD dwPlayerID)
|
||||
{
|
||||
|
@ -2476,10 +2266,6 @@ void CClientManager::ProcessPackets(CPeer * peer)
|
|||
QUERY_REMOVE_AFFECT(peer, (TPacketGDRemoveAffect *) data);
|
||||
break;
|
||||
|
||||
case HEADER_GD_HIGHSCORE_REGISTER:
|
||||
QUERY_HIGHSCORE_REGISTER(peer, (TPacketGDHighscore *) data);
|
||||
break;
|
||||
|
||||
case HEADER_GD_PARTY_CREATE:
|
||||
QUERY_PARTY_CREATE(peer, (TPacketPartyCreate*) data);
|
||||
break;
|
||||
|
@ -2512,10 +2298,6 @@ void CClientManager::ProcessPackets(CPeer * peer)
|
|||
QUERY_CHANGE_NAME(peer, dwHandle, (TPacketGDChangeName *) data);
|
||||
break;
|
||||
|
||||
case HEADER_GD_SMS:
|
||||
QUERY_SMS(peer, (TPacketGDSMS *) data);
|
||||
break;
|
||||
|
||||
case HEADER_GD_AUTH_LOGIN:
|
||||
QUERY_AUTH_LOGIN(peer, dwHandle, (TPacketGDAuthLogin *) data);
|
||||
break;
|
||||
|
@ -2556,14 +2338,6 @@ void CClientManager::ProcessPackets(CPeer * peer)
|
|||
SetEventFlag((TPacketSetEventFlag*) data);
|
||||
break;
|
||||
|
||||
case HEADER_GD_BILLING_EXPIRE:
|
||||
BillingExpire((TPacketBillingExpire *) data);
|
||||
break;
|
||||
|
||||
case HEADER_GD_BILLING_CHECK:
|
||||
BillingCheck(data);
|
||||
break;
|
||||
|
||||
case HEADER_GD_CREATE_OBJECT:
|
||||
CreateObject((TPacketGDCreateObject *) data);
|
||||
break;
|
||||
|
@ -2576,10 +2350,6 @@ void CClientManager::ProcessPackets(CPeer * peer)
|
|||
UpdateLand((DWORD *) data);
|
||||
break;
|
||||
|
||||
case HEADER_GD_VCARD:
|
||||
VCard((TPacketGDVCard *) data);
|
||||
break;
|
||||
|
||||
case HEADER_GD_MARRIAGE_ADD:
|
||||
MarriageAdd((TPacketMarriageAdd *) data);
|
||||
break;
|
||||
|
@ -2655,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
|
||||
|
@ -2672,17 +2442,6 @@ void CClientManager::ProcessPackets(CPeer * peer)
|
|||
ChangeMonarchLord(peer, dwHandle, (TPacketChangeMonarchLord*)data);
|
||||
break;
|
||||
|
||||
case HEADER_GD_BLOCK_COUNTRY_IP:
|
||||
SPDLOG_DEBUG("HEADER_GD_BLOCK_COUNTRY_IP received");
|
||||
CBlockCountry::instance().SendBlockedCountryIp(peer);
|
||||
CBlockCountry::instance().SendBlockException(peer);
|
||||
break;
|
||||
|
||||
case HEADER_GD_BLOCK_EXCEPTION:
|
||||
SPDLOG_DEBUG("HEADER_GD_BLOCK_EXCEPTION received");
|
||||
BlockException((TPacketBlockException*) data);
|
||||
break;
|
||||
|
||||
case HEADER_GD_REQ_SPARE_ITEM_ID_RANGE :
|
||||
SendSpareItemIDRange(peer);
|
||||
break;
|
||||
|
@ -2818,7 +2577,6 @@ void CClientManager::RemovePeer(CPeer * pPeer)
|
|||
if (pkLD->IsPlay())
|
||||
{
|
||||
pkLD->SetPlay(false);
|
||||
SendLoginToBilling(pkLD, false);
|
||||
}
|
||||
|
||||
if (pkLD->IsDeleted())
|
||||
|
@ -2864,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;
|
||||
|
@ -2934,11 +2692,6 @@ int CClientManager::AnalyzeQueryResult(SQLMsg * msg)
|
|||
RESULT_SAFEBOX_CHANGE_PASSWORD_SECOND(peer, msg);
|
||||
break;
|
||||
|
||||
case QID_HIGHSCORE_REGISTER:
|
||||
SPDLOG_DEBUG("QUERY_RESULT: HEADER_GD_HIGHSCORE_REGISTER {}", (void*) msg);
|
||||
RESULT_HIGHSCORE_REGISTER(peer, msg);
|
||||
break;
|
||||
|
||||
case QID_SAFEBOX_SAVE:
|
||||
case QID_ITEM_SAVE:
|
||||
case QID_ITEM_DESTROY:
|
||||
|
@ -2984,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+");
|
||||
|
||||
|
@ -3017,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);
|
||||
|
@ -3095,11 +2848,11 @@ int CClientManager::Process()
|
|||
m_iCacheFlushCount = 0;
|
||||
|
||||
|
||||
//플레이어 플러쉬
|
||||
//플레이어 플러쉬
|
||||
UpdatePlayerCache();
|
||||
//아이템 플러쉬
|
||||
//아이템 플러쉬
|
||||
UpdateItemCache();
|
||||
//로그아웃시 처리- 캐쉬셋 플러쉬
|
||||
//로그아웃시 처리- 캐쉬셋 플러쉬
|
||||
UpdateLogoutPlayer();
|
||||
|
||||
// MYSHOP_PRICE_LIST
|
||||
|
@ -3169,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();
|
||||
}
|
||||
|
@ -3184,13 +2937,12 @@ int CClientManager::Process()
|
|||
// Process network events
|
||||
event_base_loop(m_base, EVLOOP_NONBLOCK);
|
||||
|
||||
VCardProcess();
|
||||
return 1;
|
||||
}
|
||||
|
||||
DWORD CClientManager::GetUserCount()
|
||||
{
|
||||
// 단순히 로그인 카운트를 센다.. --;
|
||||
// 단순히 로그인 카운트를 센다.. --;
|
||||
return m_map_kLogonAccount.size();
|
||||
}
|
||||
|
||||
|
@ -3250,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]");
|
||||
|
@ -3680,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'",
|
||||
|
@ -4190,50 +3942,13 @@ void CClientManager::ChangeMonarchLord(CPeer * peer, DWORD dwHandle, TPacketChan
|
|||
delete pMsg;
|
||||
}
|
||||
|
||||
void CClientManager::BlockException(TPacketBlockException *data)
|
||||
{
|
||||
SPDLOG_DEBUG("[BLOCK_EXCEPTION] CMD({}) login({})", data->cmd, data->login);
|
||||
|
||||
// save sql
|
||||
{
|
||||
char buf[1024];
|
||||
|
||||
switch (data->cmd)
|
||||
{
|
||||
case BLOCK_EXCEPTION_CMD_ADD:
|
||||
snprintf(buf, sizeof(buf), "INSERT INTO block_exception VALUES('%s')", data->login);
|
||||
CDBManager::instance().AsyncQuery(buf, SQL_ACCOUNT);
|
||||
CBlockCountry::instance().AddBlockException(data->login);
|
||||
break;
|
||||
case BLOCK_EXCEPTION_CMD_DEL:
|
||||
snprintf(buf, sizeof(buf), "DELETE FROM block_exception VALUES('%s')", data->login);
|
||||
CDBManager::instance().AsyncQuery(buf, SQL_ACCOUNT);
|
||||
CBlockCountry::instance().DelBlockException(data->login);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (itertype(m_peerList) it = m_peerList.begin(); it != m_peerList.end(); ++it)
|
||||
{
|
||||
CPeer *peer = *it;
|
||||
|
||||
if (!peer->GetChannel())
|
||||
continue;
|
||||
|
||||
CBlockCountry::instance().SendBlockExceptionOne(peer, data->login, data->cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void CClientManager::SendSpareItemIDRange(CPeer* peer)
|
||||
{
|
||||
peer->SendSpareItemIDRange();
|
||||
}
|
||||
|
||||
//
|
||||
// Login Key만 맵에서 지운다.
|
||||
// Login Key만 맵에서 지운다.
|
||||
//
|
||||
void CClientManager::DeleteLoginKey(TPacketDC *data)
|
||||
{
|
||||
|
@ -4346,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());
|
||||
|
@ -4365,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())
|
||||
|
@ -4418,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());
|
||||
|
@ -4437,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())
|
||||
|
@ -4477,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());
|
||||
|
||||
|
@ -4844,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)
|
||||
{
|
||||
|
@ -4873,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;
|
||||
|
@ -4915,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
|
||||
|
@ -310,9 +310,6 @@ class CClientManager : public singleton<CClientManager>
|
|||
|
||||
void SendPartyOnSetup(CPeer * peer);
|
||||
|
||||
void QUERY_HIGHSCORE_REGISTER(CPeer * peer, TPacketGDHighscore* data);
|
||||
void RESULT_HIGHSCORE_REGISTER(CPeer * pkPeer, SQLMsg * msg);
|
||||
|
||||
void QUERY_FLUSH_CACHE(CPeer * pkPeer, const char * c_pData);
|
||||
|
||||
void QUERY_PARTY_CREATE(CPeer * peer, TPacketPartyCreate* p);
|
||||
|
@ -327,7 +324,6 @@ class CClientManager : public singleton<CClientManager>
|
|||
void QUERY_CHANGE_NAME(CPeer * peer, DWORD dwHandle, TPacketGDChangeName * p);
|
||||
void GetPlayerFromRes(TPlayerTable * player_table, MYSQL_RES* res);
|
||||
|
||||
void QUERY_SMS(CPeer * pkPeer, TPacketGDSMS * p);
|
||||
void QUERY_LOGIN_KEY(CPeer * pkPeer, TPacketGDLoginKey * p);
|
||||
|
||||
void AddGuildPriv(TPacketGiveGuildPriv* p);
|
||||
|
@ -347,13 +343,7 @@ class CClientManager : public singleton<CClientManager>
|
|||
void SetEventFlag(TPacketSetEventFlag* p);
|
||||
void SendEventFlagsOnSetup(CPeer* peer);
|
||||
|
||||
void BillingExpire(TPacketBillingExpire * p);
|
||||
void BillingCheck(const char * data);
|
||||
|
||||
void SendAllLoginToBilling();
|
||||
void SendLoginToBilling(CLoginData * pkLD, bool bLogin);
|
||||
|
||||
// 결혼
|
||||
// 결혼
|
||||
void MarriageAdd(TPacketMarriageAdd * p);
|
||||
void MarriageUpdate(TPacketMarriageUpdate * p);
|
||||
void MarriageRemove(TPacketMarriageRemove * p);
|
||||
|
@ -363,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
|
||||
|
@ -385,10 +375,6 @@ class CClientManager : public singleton<CClientManager>
|
|||
void DeleteObject(DWORD dwID);
|
||||
void UpdateLand(DWORD * pdw);
|
||||
|
||||
// VCard
|
||||
void VCard(TPacketGDVCard * p);
|
||||
void VCardProcess();
|
||||
|
||||
// BLOCK_CHAT
|
||||
void BlockChat(TPacketBlockChat * p);
|
||||
// END_OF_BLOCK_CHAT
|
||||
|
@ -413,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;
|
||||
|
||||
|
@ -441,18 +427,16 @@ class CClientManager : public singleton<CClientManager>
|
|||
std::vector<building::TObjectProto> m_vec_kObjectProto;
|
||||
std::map<DWORD, building::TObject *> m_map_pkObjectTable;
|
||||
|
||||
std::queue<TPacketGDVCard> m_queue_vcard;
|
||||
|
||||
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;
|
||||
|
@ -490,7 +474,7 @@ class CClientManager : public singleton<CClientManager>
|
|||
|
||||
//BOOT_LOCALIZATION
|
||||
public:
|
||||
/* 로컬 정보 초기화
|
||||
/* 로컬 정보 초기화
|
||||
**/
|
||||
bool InitializeLocalization();
|
||||
|
||||
|
@ -545,7 +529,6 @@ class CClientManager : public singleton<CClientManager>
|
|||
//END_MONARCH
|
||||
|
||||
void ChangeMonarchLord(CPeer* peer, DWORD dwHandle, TPacketChangeMonarchLord* info);
|
||||
void BlockException(TPacketBlockException *data);
|
||||
|
||||
void SendSpareItemIDRange(CPeer* peer);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -55,7 +55,6 @@ bool CClientManager::DeleteLogonAccount(const char * c_pszLogin, DWORD dwHandle)
|
|||
if (pkLD->IsPlay())
|
||||
{
|
||||
pkLD->SetPlay(false);
|
||||
SendLoginToBilling(pkLD, false);
|
||||
}
|
||||
|
||||
if (pkLD->IsDeleted())
|
||||
|
@ -230,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));
|
||||
|
@ -354,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");
|
||||
|
@ -396,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);
|
||||
|
|
|
@ -6,11 +6,8 @@
|
|||
#include "Main.h"
|
||||
#include "QID.h"
|
||||
#include "ItemAwardManager.h"
|
||||
#include "HB.h"
|
||||
#include "Cache.h"
|
||||
|
||||
extern bool g_bHotBackup;
|
||||
|
||||
extern std::string g_stLocale;
|
||||
extern int g_test_server;
|
||||
|
||||
|
@ -31,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;
|
||||
|
@ -158,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));
|
||||
|
@ -195,9 +192,6 @@ void CClientManager::PutPlayerCache(TPlayerTable * pNew)
|
|||
m_map_playerCache.insert(TPlayerTableCacheMap::value_type(pNew->id, c));
|
||||
}
|
||||
|
||||
if (g_bHotBackup)
|
||||
PlayerHB::instance().Put(pNew->id);
|
||||
|
||||
c->Put(pNew);
|
||||
}
|
||||
|
||||
|
@ -210,7 +204,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
|
|||
TPlayerTable * pTab;
|
||||
|
||||
//
|
||||
// 한 계정에 속한 모든 캐릭터들 캐쉬처리
|
||||
// 한 계정에 속한 모든 캐릭터들 캐쉬처리
|
||||
//
|
||||
CLoginData * pLoginData = GetLoginDataByAID(packet->account_id);
|
||||
|
||||
|
@ -222,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)))
|
||||
{
|
||||
|
@ -243,7 +237,6 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
|
|||
pTab = c->Get();
|
||||
|
||||
pkLD->SetPlay(true);
|
||||
SendLoginToBilling(pkLD, true);
|
||||
memcpy(pTab->aiPremiumTimes, pkLD->GetPremiumPtr(), sizeof(pTab->aiPremiumTimes));
|
||||
|
||||
peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_SUCCESS, dwHandle, sizeof(TPlayerTable));
|
||||
|
@ -267,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)
|
||||
{
|
||||
|
@ -288,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));
|
||||
}
|
||||
|
||||
|
@ -314,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
|
||||
{
|
||||
|
@ -348,7 +341,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
|
|||
//return;
|
||||
}
|
||||
//----------------------------------
|
||||
// 2. 유저정보가 DBCache 에 없음 : DB에서
|
||||
// 2. 유저정보가 DBCache 에 없음 : DB에서
|
||||
//----------------------------------
|
||||
else
|
||||
{
|
||||
|
@ -357,14 +350,14 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
|
|||
char queryStr[QUERY_MAX_LEN];
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// 캐릭터 정보 얻어오기 : 무조건 DB에서
|
||||
// 캐릭터 정보 얻어오기 : 무조건 DB에서
|
||||
//--------------------------------------------------------------
|
||||
snprintf(queryStr, sizeof(queryStr),
|
||||
"SELECT "
|
||||
"id,name,job,voice,dir,x,y,z,map_index,exit_x,exit_y,exit_map_index,hp,mp,stamina,random_hp,random_sp,playtime,"
|
||||
"gold,level,level_step,st,ht,dx,iq,exp,"
|
||||
"stat_point,skill_point,sub_skill_point,stat_reset_count,part_base,part_hair,"
|
||||
"skill_level,quickslot,skill_group,alignment,mobile,horse_level,horse_riding,horse_hp,horse_hp_droptime,horse_stamina,"
|
||||
"skill_level,quickslot,skill_group,alignment,horse_level,horse_riding,horse_hp,horse_hp_droptime,horse_stamina,"
|
||||
"UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(last_play),horse_skill_point FROM player%s WHERE id=%d",
|
||||
GetTablePostfix(), packet->player_id);
|
||||
|
||||
|
@ -373,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 "
|
||||
|
@ -382,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",
|
||||
|
@ -407,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));
|
||||
}
|
||||
}
|
||||
|
@ -442,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));
|
||||
|
@ -454,7 +447,7 @@ bool CreatePlayerTableFromRes(MYSQL_RES * res, TPlayerTable * pkTab)
|
|||
// "id,name,job,voice,dir,x,y,z,map_index,exit_x,exit_y,exit_map_index,hp,mp,stamina,random_hp,random_sp,playtime,"
|
||||
// "gold,level,level_step,st,ht,dx,iq,exp,"
|
||||
// "stat_point,skill_point,sub_skill_point,stat_reset_count,part_base,part_hair,"
|
||||
// "skill_level,quickslot,skill_group,alignment,mobile,horse_level,horse_riding,horse_hp,horse_stamina FROM player%s WHERE id=%d",
|
||||
// "skill_level,quickslot,skill_group,alignment,horse_level,horse_riding,horse_hp,horse_stamina FROM player%s WHERE id=%d",
|
||||
str_to_number(pkTab->id, row[col++]);
|
||||
strlcpy(pkTab->name, row[col++], sizeof(pkTab->name));
|
||||
str_to_number(pkTab->job, row[col++]);
|
||||
|
@ -505,13 +498,6 @@ bool CreatePlayerTableFromRes(MYSQL_RES * res, TPlayerTable * pkTab)
|
|||
str_to_number(pkTab->skill_group, row[col++]);
|
||||
str_to_number(pkTab->lAlignment, row[col++]);
|
||||
|
||||
if (row[col])
|
||||
{
|
||||
strlcpy(pkTab->szMobile, row[col], sizeof(pkTab->szMobile));
|
||||
}
|
||||
|
||||
col++;
|
||||
|
||||
str_to_number(pkTab->horse.bLevel, row[col++]);
|
||||
str_to_number(pkTab->horse.bRiding, row[col++]);
|
||||
str_to_number(pkTab->horse.sHealth, row[col++]);
|
||||
|
@ -529,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;
|
||||
}
|
||||
|
@ -573,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 )
|
||||
|
@ -649,7 +635,6 @@ void CClientManager::RESULT_PLAYER_LOAD(CPeer * peer, MYSQL_RES * pRes, ClientHa
|
|||
}
|
||||
|
||||
pkLD->SetPlay(true);
|
||||
SendLoginToBilling(pkLD, true);
|
||||
memcpy(tab.aiPremiumTimes, pkLD->GetPremiumPtr(), sizeof(tab.aiPremiumTimes));
|
||||
|
||||
peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_SUCCESS, pkInfo->dwHandle, sizeof(TPlayerTable));
|
||||
|
@ -670,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
|
||||
|
@ -689,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를 넣는다.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -697,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;
|
||||
|
@ -793,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())
|
||||
|
@ -1022,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)
|
||||
{
|
||||
|
@ -1073,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)
|
||||
|
@ -1089,7 +1074,7 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
|
|||
delete pkPlayerCache;
|
||||
}
|
||||
|
||||
// 아이템들을 캐쉬에서 삭제한다.
|
||||
// 아이템들을 캐쉬에서 삭제한다.
|
||||
TItemCacheSet * pSet = GetItemCacheSet(pi->player_id);
|
||||
|
||||
if (pSet)
|
||||
|
@ -1152,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);
|
||||
|
@ -1206,84 +1191,14 @@ void CClientManager::QUERY_REMOVE_AFFECT(CPeer * peer, TPacketGDRemoveAffect * p
|
|||
CDBManager::instance().AsyncQuery(queryStr);
|
||||
}
|
||||
|
||||
|
||||
void CClientManager::QUERY_HIGHSCORE_REGISTER(CPeer* peer, TPacketGDHighscore * data)
|
||||
{
|
||||
char szQuery[128];
|
||||
snprintf(szQuery, sizeof(szQuery), "SELECT value FROM highscore%s WHERE board='%s' AND pid = %u", GetTablePostfix(), data->szBoard, data->dwPID);
|
||||
|
||||
SPDLOG_DEBUG("HEADER_GD_HIGHSCORE_REGISTER: PID {}", data->dwPID);
|
||||
|
||||
ClientHandleInfo * pi = new ClientHandleInfo(0);
|
||||
strlcpy(pi->login, data->szBoard, sizeof(pi->login));
|
||||
pi->account_id = (DWORD)data->lValue;
|
||||
pi->player_id = data->dwPID;
|
||||
pi->account_index = (data->cDir > 0);
|
||||
|
||||
CDBManager::instance().ReturnQuery(szQuery, QID_HIGHSCORE_REGISTER, peer->GetHandle(), pi);
|
||||
}
|
||||
|
||||
void CClientManager::RESULT_HIGHSCORE_REGISTER(CPeer * pkPeer, SQLMsg * msg)
|
||||
{
|
||||
CQueryInfo * qi = (CQueryInfo *) msg->pvUserData;
|
||||
ClientHandleInfo * pi = (ClientHandleInfo *) qi->pvData;
|
||||
//DWORD dwHandle = pi->dwHandle;
|
||||
|
||||
char szBoard[21];
|
||||
strlcpy(szBoard, pi->login, sizeof(szBoard));
|
||||
int value = (int)pi->account_id;
|
||||
|
||||
SQLResult * res = msg->Get();
|
||||
|
||||
if (res->uiNumRows == 0)
|
||||
{
|
||||
// 새로운 하이스코어를 삽입
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "INSERT INTO highscore%s VALUES('%s', %u, %d)", GetTablePostfix(), szBoard, pi->player_id, value);
|
||||
CDBManager::instance().AsyncQuery(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!res->pSQLResult)
|
||||
{
|
||||
delete pi;
|
||||
return;
|
||||
}
|
||||
|
||||
MYSQL_ROW row = mysql_fetch_row(res->pSQLResult);
|
||||
if (row && row[0])
|
||||
{
|
||||
int current_value = 0; str_to_number(current_value, row[0]);
|
||||
if (pi->account_index && current_value >= value || !pi->account_index && current_value <= value)
|
||||
{
|
||||
value = current_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "REPLACE INTO highscore%s VALUES('%s', %u, %d)", GetTablePostfix(), szBoard, pi->player_id, value);
|
||||
CDBManager::instance().AsyncQuery(buf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "INSERT INTO highscore%s VALUES('%s', %u, %d)", GetTablePostfix(), szBoard, pi->player_id, value);
|
||||
CDBManager::instance().AsyncQuery(buf);
|
||||
}
|
||||
}
|
||||
// TODO: 이곳에서 하이스코어가 업데이트 되었는지 체크하여 공지를 뿌려야한다.
|
||||
delete pi;
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -23,7 +23,6 @@ enum eSQL_SLOT
|
|||
SQL_PLAYER,
|
||||
SQL_ACCOUNT,
|
||||
SQL_COMMON,
|
||||
SQL_HOTBACKUP,
|
||||
SQL_MAX_NUM,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
#include "stdafx.h"
|
||||
#include "HB.h"
|
||||
#include "Main.h"
|
||||
#include "DBManager.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
PlayerHB::PlayerHB()
|
||||
{
|
||||
m_iExpireTime = 3600; // 1 hour hotbackup default.
|
||||
}
|
||||
|
||||
PlayerHB::~PlayerHB()
|
||||
{
|
||||
}
|
||||
|
||||
bool PlayerHB::Initialize()
|
||||
{
|
||||
char szQuery[128];
|
||||
snprintf(szQuery, sizeof(szQuery), "SHOW CREATE TABLE player%s", GetTablePostfix());
|
||||
|
||||
std::unique_ptr<SQLMsg> pMsg(CDBManager::instance().DirectQuery(szQuery));
|
||||
|
||||
if (pMsg->Get()->uiNumRows == 0)
|
||||
return false;
|
||||
|
||||
MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
|
||||
m_stCreateTableQuery = row[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// @version 05/07/05 Bang2ni - id 에 해당하는 data 가 없을 때 쿼리하고 data 를 insert 하는코드 추가.
|
||||
//
|
||||
void PlayerHB::Put(DWORD id)
|
||||
{
|
||||
itertype(m_map_data) it = m_map_data.find(id);
|
||||
|
||||
if (it == m_map_data.end())
|
||||
{
|
||||
Query(id);
|
||||
m_map_data.insert(std::pair< DWORD, time_t >(id, get_dword_time()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (time(0) - it->second > m_iExpireTime)
|
||||
Query(id);
|
||||
}
|
||||
|
||||
//
|
||||
// @version 05/07/05 Bang2ni - Query string 버퍼가 작아서 늘려줌.
|
||||
//
|
||||
bool PlayerHB::Query(DWORD id)
|
||||
{
|
||||
time_t ct = time(0);
|
||||
struct tm curr_tm = *localtime(&ct);
|
||||
char szTableName[64];
|
||||
snprintf(szTableName, sizeof(szTableName), "hb_%02d%02d%02d%02d_player%s",
|
||||
curr_tm.tm_year - 100, curr_tm.tm_mon + 1, curr_tm.tm_mday, curr_tm.tm_hour, GetTablePostfix());
|
||||
|
||||
char szQuery[4096];
|
||||
|
||||
if (m_stTableName.compare(szTableName))
|
||||
{
|
||||
char szFind[32];
|
||||
snprintf(szFind, sizeof(szFind), "CREATE TABLE `player%s`", GetTablePostfix());
|
||||
int pos = m_stCreateTableQuery.find(szFind);
|
||||
|
||||
if (pos < 0)
|
||||
{
|
||||
SPDLOG_ERROR("cannot find {} ", szFind);
|
||||
// SPDLOG_ERROR("cannot find {} in {}", szFind, m_stCreateTableQuery.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
snprintf(szQuery, sizeof(szQuery), "CREATE TABLE IF NOT EXISTS %s%s", szTableName, m_stCreateTableQuery.c_str() + strlen(szFind));
|
||||
// SPDLOG_DEBUG("{}", szQuery);
|
||||
std::unique_ptr<SQLMsg> pMsg(CDBManager::instance().DirectQuery(szQuery, SQL_HOTBACKUP));
|
||||
m_stTableName = szTableName;
|
||||
}
|
||||
|
||||
snprintf(szQuery, sizeof(szQuery), "REPLACE INTO %s SELECT * FROM %splayer%s WHERE id=%u", m_stTableName.c_str(), GetPlayerDBName(), GetTablePostfix(), id);
|
||||
CDBManager::instance().AsyncQuery(szQuery, SQL_HOTBACKUP);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
// vim:ts=8 sw=4
|
||||
#ifndef __INC_METIN_II_PLAYERHB_H__
|
||||
#define __INC_METIN_II_PLAYERHB_H__
|
||||
|
||||
class PlayerHB : public singleton<PlayerHB>
|
||||
{
|
||||
public:
|
||||
PlayerHB();
|
||||
virtual ~PlayerHB();
|
||||
|
||||
bool Initialize();
|
||||
|
||||
void Put(DWORD id);
|
||||
|
||||
private:
|
||||
bool Query(DWORD id);
|
||||
|
||||
std::map<DWORD, time_t> m_map_data;
|
||||
std::string m_stCreateTableQuery;
|
||||
std::string m_stTableName;
|
||||
int m_iExpireTime;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,6 @@ CLoginData::CLoginData()
|
|||
memset(m_szIP, 0, sizeof(m_szIP));
|
||||
m_bPlay = false;
|
||||
m_bDeleted = false;
|
||||
m_bBillType = 0;
|
||||
m_dwBillID = 0;
|
||||
m_lastPlayTime = 0;
|
||||
m_dwLastPlayerID = 0;
|
||||
|
||||
|
|
|
@ -29,12 +29,6 @@ class CLoginData
|
|||
void SetDeleted(bool bSet);
|
||||
bool IsDeleted();
|
||||
|
||||
void SetBillID(DWORD id) { m_dwBillID = id; }
|
||||
DWORD GetBillID() { return m_dwBillID; }
|
||||
|
||||
void SetBillType(BYTE type) { m_bBillType = type; }
|
||||
BYTE GetBillType() { return m_bBillType; }
|
||||
|
||||
time_t GetLastPlayTime() { return m_lastPlayTime; }
|
||||
|
||||
void SetPremium(DWORD * paiPremiumTimes);
|
||||
|
@ -53,8 +47,6 @@ class CLoginData
|
|||
bool m_bPlay;
|
||||
bool m_bDeleted;
|
||||
|
||||
BYTE m_bBillType;
|
||||
DWORD m_dwBillID;
|
||||
time_t m_lastPlayTime;
|
||||
DWORD m_aiPremiumTimes[PREMIUM_MAX_NUM];
|
||||
|
||||
|
|
|
@ -5,12 +5,10 @@
|
|||
#include "ClientManager.h"
|
||||
#include "GuildManager.h"
|
||||
#include "ItemAwardManager.h"
|
||||
#include "HB.h"
|
||||
#include "PrivManager.h"
|
||||
#include "MoneyLog.h"
|
||||
#include "Marriage.h"
|
||||
#include "Monarch.h"
|
||||
#include "BlockCountry.h"
|
||||
#include "ItemIDRangeManager.h"
|
||||
#include <version.h>
|
||||
#ifdef __AUCTION__
|
||||
|
@ -28,14 +26,13 @@ std::string g_stLocale = "euckr";
|
|||
std::string g_stPlayerDBName = "";
|
||||
|
||||
|
||||
bool g_bHotBackup = false;
|
||||
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;
|
||||
|
||||
|
||||
|
@ -70,14 +67,12 @@ int main()
|
|||
CConfig Config;
|
||||
CDBManager DBManager;
|
||||
CClientManager ClientManager;
|
||||
PlayerHB player_hb;
|
||||
CGuildManager GuildManager;
|
||||
CPrivManager PrivManager;
|
||||
CMoneyLog MoneyLog;
|
||||
ItemAwardManager ItemAwardManager;
|
||||
marriage::CManager MarriageManager;
|
||||
CMonarch Monarch;
|
||||
CBlockCountry BlockCountry;
|
||||
CItemIDRangeManager ItemIDRangeManager;
|
||||
#ifdef __AUCTION__
|
||||
AuctionManager auctionManager;
|
||||
|
@ -87,7 +82,6 @@ int main()
|
|||
|
||||
GuildManager.Initialize();
|
||||
MarriageManager.Initialize();
|
||||
BlockCountry.Load();
|
||||
ItemIDRangeManager.Build();
|
||||
#ifdef __AUCTION__
|
||||
AuctionManager::instance().Initialize();
|
||||
|
@ -122,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()
|
||||
{
|
||||
|
@ -170,27 +164,8 @@ int Start()
|
|||
{
|
||||
g_stLocale = szBuf;
|
||||
SPDLOG_INFO("LOCALE set to {}", g_stLocale.c_str());
|
||||
|
||||
// CHINA_DISABLE_HOTBACKUP
|
||||
if ("gb2312" == g_stLocale)
|
||||
{
|
||||
SPDLOG_INFO("CIBN_LOCALE: DISABLE_HOTBACKUP");
|
||||
g_bHotBackup = false;
|
||||
}
|
||||
// END_OF_CHINA_DISABLE_HOTBACKUP
|
||||
}
|
||||
|
||||
int iDisableHotBackup;
|
||||
if (CConfig::instance().GetValue("DISABLE_HOTBACKUP", &iDisableHotBackup))
|
||||
{
|
||||
if (iDisableHotBackup)
|
||||
{
|
||||
SPDLOG_INFO("CONFIG: DISABLE_HOTBACKUP");
|
||||
g_bHotBackup = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!CConfig::instance().GetValue("TABLE_POSTFIX", szBuf, 256))
|
||||
{
|
||||
SPDLOG_WARN("TABLE_POSTFIX not configured use default");
|
||||
|
@ -324,35 +299,6 @@ int Start()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (CConfig::instance().GetValue("SQL_HOTBACKUP", line, 256))
|
||||
{
|
||||
sscanf(line, " %s %s %s %s %d ", szAddr, szDB, szUser, szPassword, &iPort);
|
||||
SPDLOG_DEBUG("connecting to MySQL server (hotbackup)");
|
||||
|
||||
int iRetry = 5;
|
||||
|
||||
do
|
||||
{
|
||||
if (CDBManager::instance().Connect(SQL_HOTBACKUP, szAddr, iPort, szDB, szUser, szPassword))
|
||||
{
|
||||
SPDLOG_DEBUG(" OK");
|
||||
break;
|
||||
}
|
||||
|
||||
SPDLOG_DEBUG(" failed, retrying in 5 seconds");
|
||||
SPDLOG_ERROR(" failed, retrying in 5 seconds");
|
||||
sleep(5);
|
||||
}
|
||||
while (iRetry--);
|
||||
|
||||
SPDLOG_INFO("Success HOTBACKUP");
|
||||
}
|
||||
else
|
||||
{
|
||||
SPDLOG_ERROR("SQL_HOTBACKUP not configured");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CClientManager::instance().Initialize())
|
||||
{
|
||||
SPDLOG_ERROR("ClientManager initialization failed");
|
||||
|
@ -361,12 +307,6 @@ int Start()
|
|||
|
||||
SPDLOG_INFO("ClientManager initialization OK");
|
||||
|
||||
if (!PlayerHB::instance().Initialize())
|
||||
{
|
||||
SPDLOG_ERROR("cannot initialize player hotbackup");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef __WIN32__
|
||||
signal(SIGUSR1, emergency_sig);
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
@ -20,19 +20,18 @@ enum QID
|
|||
QID_ITEM_DESTROY, // 11
|
||||
QID_QUEST_SAVE, // 12
|
||||
QID_PLAYER_SAVE, // 13
|
||||
QID_HIGHSCORE_REGISTER, // 14
|
||||
QID_PLAYER_DELETE, // 15
|
||||
QID_LOGIN_BY_KEY, // 16
|
||||
QID_PLAYER_INDEX_CREATE, // 17
|
||||
QID_ITEM_AWARD_LOAD, // 18
|
||||
QID_ITEM_AWARD_TAKEN, // 19
|
||||
QID_GUILD_RANKING, // 20
|
||||
QID_PLAYER_DELETE, // 14
|
||||
QID_LOGIN_BY_KEY, // 15
|
||||
QID_PLAYER_INDEX_CREATE, // 16
|
||||
QID_ITEM_AWARD_LOAD, // 17
|
||||
QID_ITEM_AWARD_TAKEN, // 18
|
||||
QID_GUILD_RANKING, // 19
|
||||
|
||||
// MYSHOP_PRICE_LIST
|
||||
QID_ITEMPRICE_SAVE, ///< 21, 아이템 가격정보 저장 쿼리
|
||||
QID_ITEMPRICE_DESTROY, ///< 22, 아이템 가격정보 삭제 쿼리
|
||||
QID_ITEMPRICE_LOAD_FOR_UPDATE, ///< 23, 가격정보 업데이트를 위한 아이템 가격정보 로드 쿼리
|
||||
QID_ITEMPRICE_LOAD, ///< 24, 아이템 가격정보 로드 쿼리
|
||||
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,32 +197,25 @@ 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())
|
||||
{
|
||||
SendNoticeMap("??????X??O??????????B", OXEVENT_MAP_INDEX, true);
|
||||
}
|
||||
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++;
|
||||
return PASSES_PER_SEC(5);
|
||||
|
@ -230,7 +223,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 +240,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 +305,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();
|
||||
|
@ -1097,38 +1097,3 @@ bool CArena::RegisterObserverPtr(LPCHARACTER pChar)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CArenaManager::IsLimitedItem( int lMapIndex, DWORD dwVnum )
|
||||
{
|
||||
if ( IsArenaMap( lMapIndex ) == true )
|
||||
{
|
||||
if ( LC_IsCanada() == true )
|
||||
{
|
||||
switch ( dwVnum )
|
||||
{
|
||||
case 50020:
|
||||
case 50021:
|
||||
case 50022:
|
||||
case 50801:
|
||||
case 50802:
|
||||
case 50813:
|
||||
case 50814:
|
||||
case 50817:
|
||||
case 50818:
|
||||
case 50819:
|
||||
case 50820:
|
||||
case 50821:
|
||||
case 50822:
|
||||
case 50823:
|
||||
case 50824:
|
||||
case 50825:
|
||||
case 50826:
|
||||
case 71044:
|
||||
case 71055:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -131,8 +131,6 @@ class CArenaManager : public singleton<CArenaManager>
|
|||
|
||||
bool IsArenaMap(DWORD dwMapIndex);
|
||||
MEMBER_IDENTITY IsMember(DWORD dwMapIndex, DWORD PID);
|
||||
|
||||
bool IsLimitedItem( int lMapIndex, DWORD dwVnum );
|
||||
};
|
||||
|
||||
#endif /*__CLASS_ARENA_MANAGER__*/
|
||||
|
|
|
@ -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))
|
||||
|
@ -205,25 +205,14 @@ int CalcMagicDamage(LPCHARACTER pkAttacker, LPCHARACTER pkVictim)
|
|||
|
||||
float CalcAttackRating(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, bool bIgnoreTargetRating)
|
||||
{
|
||||
int iARSrc;
|
||||
int iERSrc;
|
||||
int attacker_dx = pkAttacker->GetPolymorphPoint(POINT_DX);
|
||||
int attacker_lv = pkAttacker->GetLevel();
|
||||
|
||||
if (LC_IsYMIR()) // 천마
|
||||
{
|
||||
iARSrc = std::min(90, pkAttacker->GetPolymorphPoint(POINT_DX));
|
||||
iERSrc = std::min(90, pkVictim->GetPolymorphPoint(POINT_DX));
|
||||
}
|
||||
else
|
||||
{
|
||||
int attacker_dx = pkAttacker->GetPolymorphPoint(POINT_DX);
|
||||
int attacker_lv = pkAttacker->GetLevel();
|
||||
int victim_dx = pkVictim->GetPolymorphPoint(POINT_DX);
|
||||
int victim_lv = pkAttacker->GetLevel();
|
||||
|
||||
int victim_dx = pkVictim->GetPolymorphPoint(POINT_DX);
|
||||
int victim_lv = pkAttacker->GetLevel();
|
||||
|
||||
iARSrc = std::min(90, (attacker_dx * 4 + attacker_lv * 2) / 6);
|
||||
iERSrc = std::min(90, (victim_dx * 4 + victim_lv * 2) / 6);
|
||||
}
|
||||
int iARSrc = std::min(90, (attacker_dx * 4 + attacker_lv * 2) / 6);
|
||||
int iERSrc = std::min(90, (victim_dx * 4 + victim_lv * 2) / 6);
|
||||
|
||||
float fAR = ((float) iARSrc + 210.0f) / 300.0f; // fAR = 0.7 ~ 1.0
|
||||
|
||||
|
@ -238,11 +227,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 +316,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 +542,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 +602,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 +626,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 +659,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 +680,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()
|
||||
|
|
|
@ -1,150 +0,0 @@
|
|||
/*********************************************************************
|
||||
* date : 2007.05.31
|
||||
* file : block_country.cpp
|
||||
* author : mhh
|
||||
* description :
|
||||
*/
|
||||
|
||||
#define _block_country_cpp_
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "constants.h"
|
||||
#include "block_country.h"
|
||||
|
||||
#define DEC_ITER(iter) std::vector<T_BLOCK_IP*>::iterator iter
|
||||
#define DO_ALL_BLOCKED_IP(iter) for ((iter)=s_blocked_ip.begin(); (iter)!=s_blocked_ip.end(); ++(iter))
|
||||
|
||||
#define DEC_EXCEPTION_ITER(iter) std::set<std::string>::iterator iter
|
||||
|
||||
|
||||
typedef struct {
|
||||
DWORD ip_from;
|
||||
DWORD ip_to;
|
||||
} T_BLOCK_IP;
|
||||
|
||||
//--------------------------------------
|
||||
// static variables
|
||||
std::vector<T_BLOCK_IP*> s_blocked_ip;
|
||||
std::set<std::string> s_block_exception;
|
||||
// static variables
|
||||
//--------------------------------------
|
||||
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
// static functions
|
||||
static void __add_block_exception(const char *login)
|
||||
{
|
||||
SPDLOG_TRACE("BLOCK_EXCEPTION_ADD : {}", login);
|
||||
|
||||
DEC_EXCEPTION_ITER(iter);
|
||||
std::string string_login(login);
|
||||
|
||||
iter = s_block_exception.find(string_login);
|
||||
|
||||
// can not find
|
||||
if (iter==s_block_exception.end())
|
||||
{
|
||||
s_block_exception.insert(string_login);
|
||||
}
|
||||
}
|
||||
|
||||
static void __del_block_exception(const char *login)
|
||||
{
|
||||
SPDLOG_TRACE("BLOCK_EXCEPTION_DEL : {}", login);
|
||||
|
||||
DEC_EXCEPTION_ITER(iter);
|
||||
std::string string_login(login);
|
||||
|
||||
iter = s_block_exception.find(string_login);
|
||||
|
||||
// ok : find
|
||||
if (iter!=s_block_exception.end())
|
||||
{
|
||||
s_block_exception.erase(iter);
|
||||
}
|
||||
}
|
||||
// static functions
|
||||
//--------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
void add_blocked_country_ip(TPacketBlockCountryIp *data)
|
||||
{
|
||||
T_BLOCK_IP *block_ip = M2_NEW T_BLOCK_IP;
|
||||
|
||||
block_ip->ip_from = data->ip_from;
|
||||
block_ip->ip_to = data->ip_to;
|
||||
|
||||
s_blocked_ip.push_back(block_ip);
|
||||
|
||||
SPDLOG_TRACE("BLOCKED_IP = {} - {}", block_ip->ip_from, block_ip->ip_to);
|
||||
}
|
||||
|
||||
|
||||
void block_exception(TPacketBlockException *data)
|
||||
{
|
||||
if (NULL==data) return;
|
||||
|
||||
if (BLOCK_EXCEPTION_CMD_ADD!=data->cmd && BLOCK_EXCEPTION_CMD_DEL!=data->cmd)
|
||||
return;
|
||||
|
||||
|
||||
switch (data->cmd)
|
||||
{
|
||||
case BLOCK_EXCEPTION_CMD_ADD:
|
||||
__add_block_exception(data->login);
|
||||
break;
|
||||
case BLOCK_EXCEPTION_CMD_DEL:
|
||||
__del_block_exception(data->login);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_blocked_country_ip(const char *user_ip)
|
||||
{
|
||||
DEC_ITER(iter);
|
||||
T_BLOCK_IP *block_ip;
|
||||
DWORD ip_number;
|
||||
struct in_addr st_addr;
|
||||
|
||||
#ifndef __WIN32__
|
||||
if (0 == inet_aton(user_ip, &st_addr))
|
||||
#else
|
||||
unsigned int in_address;
|
||||
in_address = inet_addr(user_ip);
|
||||
st_addr.s_addr = in_address;
|
||||
if (INADDR_NONE == in_address)
|
||||
#endif
|
||||
{
|
||||
SPDLOG_INFO("BLOCKED_COUNTRY_IP ({}) : YES", user_ip);
|
||||
return true; // 아이피가 괴상하니 일단 블럭처리
|
||||
}
|
||||
ip_number = htonl(st_addr.s_addr);
|
||||
|
||||
DO_ALL_BLOCKED_IP(iter)
|
||||
{
|
||||
block_ip = *iter;
|
||||
if ( block_ip->ip_from <= ip_number && ip_number <= block_ip->ip_to )
|
||||
{
|
||||
SPDLOG_INFO("BLOCKED_COUNTRY_IP ({}) : YES", user_ip);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
SPDLOG_DEBUG("BLOCKED_COUNTRY_IP ({}) : NO", user_ip);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_block_exception(const char *login)
|
||||
{
|
||||
std::string login_string(login);
|
||||
std::set<std::string>::iterator iter;
|
||||
|
||||
iter = s_block_exception.find(login_string);
|
||||
if (iter != s_block_exception.end())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
/*********************************************************************
|
||||
* date : 2007.05.31
|
||||
* file : block_country.h
|
||||
* author : mhh
|
||||
* description :
|
||||
*/
|
||||
|
||||
#ifndef _block_country_h_
|
||||
#define _block_country_h_
|
||||
|
||||
|
||||
void add_blocked_country_ip(TPacketBlockCountryIp *data);
|
||||
void block_exception(TPacketBlockException *data);
|
||||
bool is_blocked_country_ip(const char *user_ip);
|
||||
bool is_block_exception(const char *login);
|
||||
|
||||
#endif // _block_country_h_
|
||||
|
|
@ -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,56 +234,58 @@ 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_ENERGY = 128, // 128 기력
|
||||
POINT_RAMADAN_CANDY_BONUS_EXP, // 라마단 사탕 경험치 증가용
|
||||
|
||||
// 기력 ui 용.
|
||||
// 서버에서 쓰지 않기만, 클라이언트에서 기력의 끝 시간을 POINT로 관리하기 때문에 이렇게 한다.
|
||||
// 아 부끄럽다
|
||||
POINT_ENERGY_END_TIME = 129, // 129 기력 종료 시간
|
||||
POINT_ENERGY = 128, // 128 기력
|
||||
|
||||
// 기력 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
|
||||
};
|
||||
|
@ -352,7 +354,7 @@ struct DynamicCharacterPtr {
|
|||
uint32_t id;
|
||||
};
|
||||
|
||||
/* 저장하는 데이터 */
|
||||
/* 저장하는 데이터 */
|
||||
typedef struct character_point
|
||||
{
|
||||
int points[POINT_MAX_NUM];
|
||||
|
@ -375,7 +377,7 @@ typedef struct character_point
|
|||
BYTE skill_group;
|
||||
} CHARACTER_POINT;
|
||||
|
||||
/* 저장되지 않는 캐릭터 데이터 */
|
||||
/* 저장되지 않는 캐릭터 데이터 */
|
||||
typedef struct character_point_instant
|
||||
{
|
||||
int points[POINT_MAX_NUM];
|
||||
|
@ -397,7 +399,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];
|
||||
|
||||
|
@ -409,7 +411,7 @@ typedef struct character_point_instant
|
|||
|
||||
BYTE gm_level;
|
||||
|
||||
BYTE bBasePart; // 평상복 번호
|
||||
BYTE bBasePart; // 평상복 번호
|
||||
|
||||
int iMaxStamina;
|
||||
|
||||
|
@ -507,7 +509,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
{
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Entity 관련
|
||||
// Entity 관련
|
||||
virtual void EncodeInsertPacket(LPENTITY entity);
|
||||
virtual void EncodeRemovePacket(LPENTITY entity);
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -517,7 +519,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;
|
||||
|
@ -587,13 +589,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;
|
||||
|
@ -634,7 +636,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);
|
||||
|
||||
|
@ -717,14 +719,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);
|
||||
|
||||
|
@ -740,7 +742,6 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
|
||||
void ChatPacket(BYTE type, const char *format, ...);
|
||||
void MonsterChat(BYTE bMonsterChatType);
|
||||
void SendGreetMessage();
|
||||
|
||||
void ResetPoint(int iLv);
|
||||
|
||||
|
@ -749,7 +750,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;
|
||||
|
@ -789,8 +790,6 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
DWORD m_dwPlayStartTime;
|
||||
BYTE m_bAddChrState;
|
||||
bool m_bSkipSave;
|
||||
std::string m_stMobile;
|
||||
char m_szMobileAuth[5];
|
||||
BYTE m_bChatCounter;
|
||||
|
||||
// End of Basic Points
|
||||
|
@ -806,15 +805,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;
|
||||
|
@ -825,7 +824,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;
|
||||
|
@ -852,7 +851,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;
|
||||
|
@ -875,7 +874,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);
|
||||
|
@ -904,7 +903,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;
|
||||
|
@ -930,25 +929,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);
|
||||
|
||||
|
@ -961,45 +960,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);
|
||||
|
||||
|
@ -1008,11 +1007,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;
|
||||
|
@ -1046,7 +1045,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; }
|
||||
|
@ -1061,14 +1060,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
|
||||
|
@ -1114,10 +1113,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);
|
||||
|
@ -1149,14 +1148,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;
|
||||
|
@ -1170,7 +1169,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
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1236,9 +1235,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();
|
||||
|
@ -1268,7 +1267,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
void UpdateAlignment(int iAmount);
|
||||
int GetAlignment() const;
|
||||
|
||||
//선악치 얻기
|
||||
//선악치 얻기
|
||||
int GetRealAlignment() const;
|
||||
void ShowAlignment(bool bShow);
|
||||
|
||||
|
@ -1317,7 +1316,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;
|
||||
|
||||
|
@ -1340,8 +1339,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
|
||||
|
@ -1399,7 +1398,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
|
||||
|
@ -1456,10 +1455,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();
|
||||
|
@ -1483,8 +1482,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);
|
||||
|
@ -1505,19 +1504,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; }
|
||||
|
||||
|
@ -1535,7 +1534,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;
|
||||
|
@ -1569,7 +1568,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);
|
||||
|
||||
|
@ -1631,7 +1630,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; }
|
||||
|
||||
|
@ -1671,7 +1670,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:
|
||||
|
@ -1741,20 +1740,11 @@ 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
|
||||
|
||||
// PC_BANG_ITEM_ADD
|
||||
private :
|
||||
bool m_isinPCBang;
|
||||
|
||||
public :
|
||||
bool SetPCBang(bool flag) { m_isinPCBang = flag; return m_isinPCBang; }
|
||||
bool IsPCBang() const { return m_isinPCBang; }
|
||||
// END_PC_BANG_ITEM_ADD
|
||||
|
||||
// NEW_HAIR_STYLE_ADD
|
||||
public :
|
||||
bool ItemProcess_Hair(LPITEM item, int iDestCell);
|
||||
|
@ -1824,7 +1814,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
|
||||
|
@ -1874,9 +1864,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:
|
||||
|
@ -1952,7 +1942,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; }
|
||||
|
@ -1967,7 +1957,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
|||
bool IsPet() { return m_bIsPet; }
|
||||
#endif
|
||||
|
||||
//최종 데미지 보정.
|
||||
//최종 데미지 보정.
|
||||
private:
|
||||
float m_fAttMul;
|
||||
float m_fDamMul;
|
||||
|
@ -1980,7 +1970,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] = "";
|
||||
|
@ -1994,10 +1984,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;
|
||||
|
@ -2008,17 +1998,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();
|
||||
|
@ -2026,8 +2016,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())
|
||||
|
@ -99,16 +99,7 @@ bool CHARACTER::UpdateAffect()
|
|||
}
|
||||
else
|
||||
{
|
||||
int iVal = 0;
|
||||
|
||||
if (LC_IsYMIR())
|
||||
{
|
||||
iVal = std::min(GetPoint(POINT_HP_RECOVERY), GetMaxHP() * 9 / 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
iVal = std::min(GetPoint(POINT_HP_RECOVERY), GetMaxHP() * 7 / 100);
|
||||
}
|
||||
int iVal = std::min(GetPoint(POINT_HP_RECOVERY), GetMaxHP() * 7 / 100);;
|
||||
|
||||
PointChange(POINT_HP, iVal);
|
||||
PointChange(POINT_HP_RECOVERY, -iVal);
|
||||
|
@ -121,12 +112,7 @@ bool CHARACTER::UpdateAffect()
|
|||
PointChange(POINT_SP_RECOVERY, -GetPoint(POINT_SP_RECOVERY));
|
||||
else
|
||||
{
|
||||
int iVal;
|
||||
|
||||
if (!g_iUseLocale)
|
||||
iVal = std::min(GetPoint(POINT_SP_RECOVERY), GetMaxSP() * 7 / 100);
|
||||
else
|
||||
iVal = std::min(GetPoint(POINT_SP_RECOVERY), GetMaxSP() * 7 / 100);
|
||||
int iVal = std::min(GetPoint(POINT_SP_RECOVERY), GetMaxSP() * 7 / 100);
|
||||
|
||||
PointChange(POINT_SP, iVal);
|
||||
PointChange(POINT_SP_RECOVERY, -iVal);
|
||||
|
@ -146,7 +132,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 +141,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 +212,7 @@ int CHARACTER::ProcessAffect()
|
|||
CAffect *pkAff = NULL;
|
||||
|
||||
//
|
||||
// 프리미엄 처리
|
||||
// 프리미엄 처리
|
||||
//
|
||||
for (int i = 0; i <= PREMIUM_MAX_NUM; ++i)
|
||||
{
|
||||
|
@ -300,8 +286,8 @@ int CHARACTER::ProcessAffect()
|
|||
}
|
||||
|
||||
// AFFECT_DURATION_BUG_FIX
|
||||
// 무한 효과 아이템도 시간을 줄인다.
|
||||
// 시간을 매우 크게 잡기 때문에 상관 없을 것이라 생각됨.
|
||||
// 무한 효과 아이템도 시간을 줄인다.
|
||||
// 시간을 매우 크게 잡기 때문에 상관 없을 것이라 생각됨.
|
||||
if ( --pkAff->lDuration <= 0 )
|
||||
{
|
||||
bEnd = true;
|
||||
|
@ -470,7 +456,7 @@ void CHARACTER::LoadAffect(DWORD dwCount, TPacketAffectElement * pElements)
|
|||
|
||||
for (DWORD i = 0; i < dwCount; ++i, ++pElements)
|
||||
{
|
||||
// 무영진은 로드하지않는다.
|
||||
// 무영진은 로드하지않는다.
|
||||
if (pElements->dwType == SKILL_MUYEONG)
|
||||
continue;
|
||||
|
||||
|
@ -524,7 +510,7 @@ void CHARACTER::LoadAffect(DWORD dwCount, TPacketAffectElement * pElements)
|
|||
|
||||
m_bIsLoadedAffect = true;
|
||||
|
||||
// 용혼석 셋팅 로드 및 초기화
|
||||
// 용혼석 셋팅 로드 및 초기화
|
||||
DragonSoul_Initialize();
|
||||
}
|
||||
|
||||
|
@ -533,7 +519,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 +548,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 +559,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 +663,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 +699,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 +781,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);
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue