text encoding fixed

This commit is contained in:
d1str4ught
2025-08-18 02:12:07 +02:00
parent da0a923cde
commit 34000c3306
484 changed files with 5767 additions and 5767 deletions

View File

@@ -1,16 +1,16 @@
#ifndef __HEADER_VNUM_HELPER__
#ifndef __HEADER_VNUM_HELPER__
#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; }
};

View File

@@ -1,4 +1,4 @@
#ifndef __INC_AUCTION_TABLES_H__
#ifndef __INC_AUCTION_TABLES_H__
#define __INC_AUCTION_TABLES_H__
#include "tables.h"
@@ -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

View File

@@ -1,4 +1,4 @@
#ifndef __INC_METIN_II_COMMON_BILLING_H__
#ifndef __INC_METIN_II_COMMON_BILLING_H__
#define __INC_METIN_II_COMMON_BILLING_H__
enum EBillingTypes

View File

@@ -1,4 +1,4 @@
#ifndef __METIN_II_COMMON_BUILDING_H__
#ifndef __METIN_II_COMMON_BUILDING_H__
#define __METIN_II_COMMON_BUILDING_H__
namespace building
@@ -41,8 +41,8 @@ namespace building
long lNPCX;
long lNPCY;
DWORD dwGroupVnum; // 같은 그룹은 하나만 건설가능
DWORD dwDependOnGroupVnum; // 지어져 있어야하는 그룹
DWORD dwGroupVnum; // 같은 그룹은 하나만 건설가능
DWORD dwDependOnGroupVnum; // 지어져 있어야하는 그룹
} TObjectProto;
typedef struct SObject

View File

@@ -1,4 +1,4 @@
#ifndef __INC_COMMON_CACHE_H__
#ifndef __INC_COMMON_CACHE_H__
#define __INC_COMMON_CACHE_H__
template <typename T> class cache

View File

@@ -1,4 +1,4 @@
#ifndef __INC_METIN_II_D3DTYPE_H__
#ifndef __INC_METIN_II_D3DTYPE_H__
#define __INC_METIN_II_D3DTYPE_H__
typedef struct D3DXVECTOR2

View File

@@ -1,4 +1,4 @@
#ifndef __INC_METIN2_ITEM_LENGTH_H__
#ifndef __INC_METIN2_ITEM_LENGTH_H__
#define __INC_METIN2_ITEM_LENGTH_H__
enum EItemMisc
@@ -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
@@ -335,16 +335,16 @@ enum ELimitTypes
LIMIT_CON,
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

View File

@@ -1,4 +1,4 @@
#ifndef __INC_METIN_II_LENGTH_H__
#ifndef __INC_METIN_II_LENGTH_H__
#define __INC_METIN_II_LENGTH_H__
#define WORD_MAX 0xffff
@@ -22,10 +22,10 @@ enum EMisc
GUILD_NAME_MAX_LEN = 12,
SHOP_HOST_ITEM_MAX_NUM = 40, /* 호스트의 최대 아이템 개수 */
SHOP_GUEST_ITEM_MAX_NUM = 18, /* 게스트의 최대 아이템 개수 */
SHOP_HOST_ITEM_MAX_NUM = 40, /* 호스트의 최대 아이템 개수 */
SHOP_GUEST_ITEM_MAX_NUM = 18, /* 게스트의 최대 아이템 개수 */
SHOP_PRICELIST_MAX_NUM = 40, ///< 개인상점 가격정보 리스트에서 유지할 가격정보의 최대 갯수
SHOP_PRICELIST_MAX_NUM = 40, ///< 개인상점 가격정보 리스트에서 유지할 가격정보의 최대 갯수
CHAT_MAX_LEN = 512,
@@ -84,19 +84,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
| 미사용 |
| 미사용 |
+------------------------------------------------------+ ??
*/
};
@@ -131,10 +131,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 //
};
@@ -145,7 +145,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
@@ -167,7 +167,7 @@ enum EDirection
DIR_MAX_NUM
};
#define ABILITY_MAX_LEVEL 10 /* 기술 최대 레벨 */
#define ABILITY_MAX_LEVEL 10 /* 기술 최대 레벨 */
enum EAbilityDifficulty
{
@@ -180,9 +180,9 @@ enum EAbilityDifficulty
enum EAbilityCategory
{
CATEGORY_PHYSICAL, /* 신체적 어빌리티 */
CATEGORY_MENTAL, /* 정신적 어빌리티 */
CATEGORY_ATTRIBUTE, /* 능력 어빌리티 */
CATEGORY_PHYSICAL, /* 신체적 어빌리티 */
CATEGORY_MENTAL, /* 정신적 어빌리티 */
CATEGORY_ATTRIBUTE, /* 능력 어빌리티 */
CATEGORY_NUM_TYPES
};
@@ -252,13 +252,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,
@@ -401,38 +401,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, //
@@ -584,7 +584,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,
};
@@ -628,13 +628,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
};
@@ -664,10 +664,10 @@ enum SPECIAL_EFFECT
SE_AUTO_HPUP,
SE_AUTO_SPUP,
SE_EQUIP_RAMADAN_RING, // 라마단 초승달의 반지(71135) 착용할 때 이펙트 (발동이펙트임, 지속이펙트 아님)
SE_EQUIP_HALLOWEEN_CANDY, // 할로윈 사탕을 착용(-_-;)한 순간에 발동하는 이펙트
SE_EQUIP_HAPPINESS_RING, // 크리스마스 행복의 반지(71143) 착용할 때 이펙트 (발동이펙트임, 지속이펙트 아님)
SE_EQUIP_LOVE_PENDANT, // 발렌타인 사랑의 팬던트(71145) 착용할 때 이펙트 (발동이펙트임, 지속이펙트 아님)
SE_EQUIP_RAMADAN_RING, // 라마단 초승달의 반지(71135) 착용할 때 이펙트 (발동이펙트임, 지속이펙트 아님)
SE_EQUIP_HALLOWEEN_CANDY, // 할로윈 사탕을 착용(-_-;)한 순간에 발동하는 이펙트
SE_EQUIP_HAPPINESS_RING, // 크리스마스 행복의 반지(71143) 착용할 때 이펙트 (발동이펙트임, 지속이펙트 아님)
SE_EQUIP_LOVE_PENDANT, // 발렌타인 사랑의 팬던트(71145) 착용할 때 이펙트 (발동이펙트임, 지속이펙트 아님)
} ;
enum ETeenFlags
@@ -682,10 +682,10 @@ enum ETeenFlags
#include "item_length.h"
// inventory의 position을 나타내는 구조체
// int와의 암시적 형변환이 있는 이유는,
// 인벤 관련된 모든 함수가 window_type은 받지 않고, cell 하나만 받았기 때문에,(기존에는 인벤이 하나 뿐이어서 inventory type이란게 필요없었기 때문에,)
// 인벤 관련 모든 함수 호출부분을 수정하는 것이 난감하기 떄문이다.
// inventory의 position을 나타내는 구조체
// int와의 암시적 형변환이 있는 이유는,
// 인벤 관련된 모든 함수가 window_type은 받지 않고, cell 하나만 받았기 때문에,(기존에는 인벤이 하나 뿐이어서 inventory type이란게 필요없었기 때문에,)
// 인벤 관련 모든 함수 호출부분을 수정하는 것이 난감하기 떄문이다.
enum EDragonSoulRefineWindowSize
{
@@ -734,7 +734,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;

View File

@@ -1,4 +1,4 @@
#ifndef INC_METIN_II_COMMON_NONCOPYABLE_TEMPLATE
#ifndef INC_METIN_II_COMMON_NONCOPYABLE_TEMPLATE
#define INC_METIN_II_COMMON_NONCOPYABLE_TEMPLATE
class noncopyable

View File

@@ -1,4 +1,4 @@
#ifndef __INC_METIN_II_COMMON_POOL_H__
#ifndef __INC_METIN_II_COMMON_POOL_H__
#define __INC_METIN_II_COMMON_POOL_H__
#include <assert.h>

View File

@@ -1,10 +1,10 @@
#ifndef __INC_SERVICE_H__
#ifndef __INC_SERVICE_H__
#define __INC_SERVICE_H__
#define ENABLE_AUTODETECT_INTERNAL_IP
#define ENABLE_PROXY_IP
#define ENABLE_PORT_SECURITY
#define _IMPROVED_PACKET_ENCRYPTION_ // 패킷 암호화 개선
#define _IMPROVED_PACKET_ENCRYPTION_ // 패킷 암호화 개선
//#define __AUCTION__
#define __PET_SYSTEM__
#define __UDP_BLOCK__

View File

@@ -1,4 +1,4 @@
#ifndef __INC_SINGLETON_H__
#ifndef __INC_SINGLETON_H__
#define __INC_SINGLETON_H__
#include <assert.h>

View File

@@ -1,4 +1,4 @@
#ifndef __INC_METIN_II_STL_H__
#ifndef __INC_METIN_II_STL_H__
#define __INC_METIN_II_STL_H__
#include <vector>

View File

@@ -1,4 +1,4 @@
#ifndef __INC_TABLES_H__
#ifndef __INC_TABLES_H__
#define __INC_TABLES_H__
#include "length.h"
@@ -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
{
@@ -104,8 +104,8 @@ enum
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,
@@ -116,21 +116,21 @@ enum
// 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_BLOCK_COUNTRY_IP = 127, // 광대역 IP-Block
HEADER_GD_BLOCK_EXCEPTION = 128, // 광대역 IP-Block 예외
HEADER_GD_REQ_CHANGE_GUILD_MASTER = 129,
@@ -139,7 +139,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,
@@ -257,23 +257,23 @@ 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_BLOCK_COUNTRY_IP = 171, // 광대역 IP-Block
HEADER_DG_BLOCK_EXCEPTION = 172, // 광대역 IP-Block 예외 account
HEADER_DG_ACK_CHANGE_GUILD_MASTER = 173,
@@ -393,7 +393,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];
@@ -608,9 +608,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
@@ -674,12 +674,12 @@ typedef struct SItemTable : public SEntityTable
BYTE bSpecular;
BYTE bGainSocketPct;
short int sAddonType; // 기본 속성
short int 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;
@@ -717,7 +717,7 @@ typedef struct SPlayerLoadPacket
{
DWORD account_id;
DWORD player_id;
BYTE account_index; /* account 에서의 위치 */
BYTE account_index; /* account 에서의 위치 */
} TPlayerLoadPacket;
typedef struct SPlayerCreatePacket
@@ -794,9 +794,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[32];
DWORD dwLoginCount;
BYTE bAuthServer;
@@ -974,8 +974,8 @@ typedef struct SPacketGuildWar
long lInitialScore;
} TPacketGuildWar;
// Game -> DB : 상대적 변화값
// DB -> Game : 토탈된 최종값
// Game -> DB : 상대적 변화값
// DB -> Game : 토탈된 최종값
typedef struct SPacketGuildWarScore
{
DWORD dwGuildGainPoint;
@@ -996,8 +996,8 @@ typedef struct SRefineTable
//DWORD result_vnum;
DWORD id;
BYTE material_count;
int cost; // 소요 비용
int prob; // 확률
int cost; // 소요 비용
int prob; // 확률
TRefineMaterial materials[REFINE_MATERIAL_MAX_NUM];
} TRefineTable;
@@ -1082,14 +1082,14 @@ typedef struct SPacketGDLoginByKey
} TPacketGDLoginByKey;
/**
* @version 05/06/08 Bang2ni - 지속시간 추가
* @version 05/06/08 Bang2ni - 지속시간 추가
*/
typedef struct SPacketGiveGuildPriv
{
BYTE type;
int value;
DWORD guild_id;
time_t duration_sec; ///< 지속시간
time_t duration_sec; ///< 지속시간
} TPacketGiveGuildPriv;
typedef struct SPacketGiveEmpirePriv
{
@@ -1124,7 +1124,7 @@ typedef struct SPacketDGChangeCharacterPriv
} TPacketDGChangeCharacterPriv;
/**
* @version 05/06/08 Bang2ni - 지속시간 추가
* @version 05/06/08 Bang2ni - 지속시간 추가
*/
typedef struct SPacketDGChangeGuildPriv
{
@@ -1132,7 +1132,7 @@ typedef struct SPacketDGChangeGuildPriv
int value;
DWORD guild_id;
BYTE bLog;
time_t end_time_sec; ///< 지속시간
time_t end_time_sec; ///< 지속시간
} TPacketDGChangeGuildPriv;
typedef struct SPacketDGChangeEmpirePriv
@@ -1313,27 +1313,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
@@ -1354,12 +1354,12 @@ typedef struct SPacketPCBangIP
//ADMIN_MANAGER
typedef struct TAdminInfo
{
int m_ID; //고유ID
char m_szAccount[32]; //계정
char m_szName[32]; //캐릭터이름
char m_szContactIP[16]; //접근아이피
char m_szServerIP[16]; //서버아이피
int m_Authority; //권한
int m_ID; //고유ID
char m_szAccount[32]; //계정
char m_szName[32]; //캐릭터이름
char m_szContactIP[16]; //접근아이피
char m_szServerIP[16]; //서버아이피
int m_Authority; //권한
} tAdminInfo;
//END_ADMIN_MANAGER
@@ -1380,20 +1380,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;
@@ -1465,14 +1465,14 @@ typedef struct tNeedLoginLogInfo
DWORD dwPlayerID;
} TPacketNeedLoginLogInfo;
//독일 선물 알림 기능 테스트용 패킷 정보
//독일 선물 알림 기능 테스트용 패킷 정보
typedef struct tItemAwardInformer
{
char login[LOGIN_MAX_LEN + 1];
char command[20]; //명령어
unsigned int vnum; //아이템
char command[20]; //명령어
unsigned int vnum; //아이템
} TPacketItemAwardInfromer;
// 선물 알림 기능 삭제용 패킷 정보
// 선물 알림 기능 삭제용 패킷 정보
typedef struct tDeleteAwardID
{
DWORD dwID;

View File

@@ -1,4 +1,4 @@
/*********************************************************************
/*********************************************************************
* date : 2007.06.07
* file : teen_packet.h
* author : mhh

View File

@@ -1,4 +1,4 @@
/*----- atoi function -----*/
/*----- atoi function -----*/
inline bool str_to_number (bool& out, const char *in)
{
if (0==in || 0==in[0]) return false;

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#ifdef __AUCTION__
#include "DBManager.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);

View File

@@ -1,4 +1,4 @@
#ifdef __AUCTION__
#ifdef __AUCTION__
#ifndef __INC_AUCTION_MANAGER_H__
#define __INC_AUCTION_MANAGER_H__
@@ -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;

View File

@@ -1,4 +1,4 @@
// vim:ts=4 sw=4
// vim:ts=4 sw=4
/*********************************************************************
* date : 2007.05.31
* file : BlockCountry.cpp
@@ -114,7 +114,7 @@ bool CBlockCountry::IsBlockedCountryIp(const char *user_ip)
st_addr.s_addr = in_address;
if (INADDR_NONE == in_address)
#endif
return true; // 아이피가 괴상하니 일단 블럭처리
return true; // 아이피가 괴상하니 일단 블럭처리
DO_ALL_BLOCK_IP(iter)
{

View File

@@ -1,4 +1,4 @@
// vim: ts=4 sw=4
// vim: ts=4 sw=4
// Date : 2007.05.31
// File : BlockCountry.h
// Author : mhh

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "Cache.h"
@@ -29,12 +29,12 @@ CItemCache::~CItemCache()
{
}
// 이거 이상한데...
// Delete를 했으면, Cache도 해제해야 하는것 아닌가???
// 근데 Cache를 해제하는 부분이 없어.
// 못 찾은 건가?
// 이렇게 해놓으면, 계속 시간이 될 때마다 아이템을 계속 지워...
// 이미 사라진 아이템인데... 확인사살??????
// 이거 이상한데...
// Delete를 했으면, Cache도 해제해야 하는것 아닌가???
// 근데 Cache를 해제하는 부분이 없어.
// 못 찾은 건가?
// 이렇게 해놓으면, 계속 시간이 될 때마다 아이템을 계속 지워...
// 이미 사라진 아이템인데... 확인사살??????
// fixme
// by rtsummit
void CItemCache::Delete()
@@ -53,12 +53,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);
@@ -190,7 +190,7 @@ CItemPriceListTableCache::CItemPriceListTableCache()
void CItemPriceListTableCache::UpdateList(const TItemPriceListTable* pUpdateList)
{
//
// 이미 캐싱된 아이템과 중복된 아이템을 찾고 중복되지 않는 이전 정보는 tmpvec 에 넣는다.
// 이미 캐싱된 아이템과 중복된 아이템을 찾고 중복되지 않는 이전 정보는 tmpvec 에 넣는다.
//
std::vector<TItemPriceInfo> tmpvec;
@@ -206,7 +206,7 @@ void CItemPriceListTableCache::UpdateList(const TItemPriceListTable* pUpdateList
}
//
// pUpdateList 를 m_data 에 복사하고 남은 공간을 tmpvec 의 앞에서 부터 남은 만큼 복사한다.
// pUpdateList 를 m_data 에 복사하고 남은 공간을 tmpvec 의 앞에서 부터 남은 만큼 복사한다.
//
if (pUpdateList->byCount > SHOP_PRICELIST_MAX_NUM)
@@ -219,7 +219,7 @@ void CItemPriceListTableCache::UpdateList(const TItemPriceListTable* pUpdateList
thecore_memcpy(m_data.aPriceInfo, pUpdateList->aPriceInfo, sizeof(TItemPriceInfo) * pUpdateList->byCount);
int nDeletedNum; // 삭제된 가격정보의 갯수
int nDeletedNum; // 삭제된 가격정보의 갯수
if (pUpdateList->byCount < SHOP_PRICELIST_MAX_NUM)
{
@@ -248,14 +248,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)

View File

@@ -1,4 +1,4 @@
// vim:ts=8 sw=4
// vim:ts=8 sw=4
#ifndef __INC_DB_CACHE_H__
#define __INC_DB_CACHE_H__
@@ -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:

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "../../common/billing.h"
@@ -167,7 +167,7 @@ bool CClientManager::Initialize()
LoadEventFlag();
// database character-set을 강제로 맞춤
// database character-set을 강제로 맞춤
if (g_stLocale == "big5" || g_stLocale == "sjis")
CDBManager::instance().QueryLocaleSet();
@@ -180,7 +180,7 @@ void CClientManager::MainLoop()
sys_log(0, "ClientManager pointer is %p", this);
// 메인루프
// 메인루프
while (!m_bShutdowned)
{
while ((tmp = CDBManager::instance().PopResult()))
@@ -196,7 +196,7 @@ void CClientManager::MainLoop()
}
//
// 메인루프 종료처리
// 메인루프 종료처리
//
sys_log(0, "MainLoop exited, Starting cache flushing");
@@ -204,7 +204,7 @@ void CClientManager::MainLoop()
itertype(m_map_playerCache) it = m_map_playerCache.begin();
//플레이어 테이블 캐쉬 플러쉬
//플레이어 테이블 캐쉬 플러쉬
while (it != m_map_playerCache.end())
{
CPlayerTableCache * c = (it++)->second;
@@ -216,7 +216,7 @@ void CClientManager::MainLoop()
itertype(m_map_itemCache) it2 = m_map_itemCache.begin();
//아이템 플러쉬
//아이템 플러쉬
while (it2 != m_map_itemCache.end())
{
CItemCache * c = (it2++)->second;
@@ -228,7 +228,7 @@ void CClientManager::MainLoop()
// MYSHOP_PRICE_LIST
//
// 개인상점 아이템 가격 리스트 Flush
// 개인상점 아이템 가격 리스트 Flush
//
for (itertype(m_mapItemPriceListCache) itPriceList = m_mapItemPriceListCache.begin(); itPriceList != m_mapItemPriceListCache.end(); ++itPriceList)
{
@@ -248,7 +248,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;
@@ -507,9 +507,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)
{
@@ -534,7 +534,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)))
{
@@ -600,8 +600,8 @@ void CClientManager::RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg)
}
// 쿼리에 에러가 있었으므로 응답할 경우 창고가 비어있는 것 처럼
// 보이기 때문에 창고가 아얘 안열리는게 나음
// 쿼리에 에러가 있었으므로 응답할 경우 창고가 비어있는 것 처럼
// 보이기 때문에 창고가 아얘 안열리는게 나음
if (!msg->Get()->pSQLResult)
{
sys_err("null safebox result");
@@ -711,8 +711,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)
@@ -824,7 +824,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];
@@ -912,7 +912,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;
@@ -931,7 +931,7 @@ void CClientManager::RESULT_PRICELIST_LOAD(CPeer* peer, SQLMsg* pMsg)
PutItemPriceListCache(&table);
//
// 로드한 데이터를 Game server 에 전송
// 로드한 데이터를 Game server 에 전송
//
TPacketMyshopPricelistHeader header;
@@ -955,7 +955,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;
@@ -1017,18 +1017,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)
@@ -1079,7 +1079,7 @@ void CClientManager::QUERY_SETUP(CPeer * peer, DWORD dwHandle, const char * c_pD
peer->SetMaps(p->alMaps);
//
// 어떤 맵이 어떤 서버에 있는지 보내기
// 어떤 맵이 어떤 서버에 있는지 보내기
//
TMapLocation kMapLocations;
@@ -1186,7 +1186,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 컨넥션 생성)
//
sys_log(0, "SETUP: channel %u listen %u p2p %u count %u", peer->GetChannel(), p->wListenPort, p->wP2PPort, bMapCount);
@@ -1202,7 +1202,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;
@@ -1211,7 +1211,7 @@ void CClientManager::QUERY_SETUP(CPeer * peer, DWORD dwHandle, const char * c_pD
}
//
// 로그인 및 빌링정보 보내기
// 로그인 및 빌링정보 보내기
//
TPacketLoginOnSetup * pck = (TPacketLoginOnSetup *) c_pData;;
std::vector<TPacketBillingRepair> vec_repair;
@@ -1284,8 +1284,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)
{
@@ -1424,7 +1424,7 @@ void CClientManager::PutItemCache(TPlayerItem * pNew, bool bSkipQuery)
c = GetItemCache(pNew->id);
// 아이템 새로 생성
// 아이템 새로 생성
if (!c)
{
if (g_log)
@@ -1433,15 +1433,15 @@ void CClientManager::PutItemCache(TPlayerItem * pNew, bool bSkipQuery)
c = new CItemCache;
m_map_itemCache.insert(TItemCacheMap::value_type(pNew->id, c));
}
// 있을시
// 있을시
else
{
if (g_log)
sys_log(0, "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())
@@ -1453,7 +1453,7 @@ void CClientManager::PutItemCache(TPlayerItem * pNew, bool bSkipQuery)
}
}
// 새로운 정보 업데이트
// 새로운 정보 업데이트
c->Put(pNew, bSkipQuery);
TItemCacheSetPtrMap::iterator it = m_map_pkItemCacheSetPtr.find(c->Get()->owner);
@@ -1468,8 +1468,8 @@ void CClientManager::PutItemCache(TPlayerItem * pNew, bool bSkipQuery)
}
else
{
// 현재 소유자가 없으므로 바로 저장해야 다음 접속이 올 때 SQL에 쿼리하여
// 받을 수 있으므로 바로 저장한다.
// 현재 소유자가 없으므로 바로 저장해야 다음 접속이 올 때 SQL에 쿼리하여
// 받을 수 있으므로 바로 저장한다.
if (g_log)
sys_log(0, "ITEM_CACHE: direct save %u id %u", c->Get()->owner, c->Get()->id);
else
@@ -1529,7 +1529,7 @@ void CClientManager::UpdatePlayerCache()
c->Flush();
// Item Cache도 업데이트
// Item Cache도 업데이트
UpdateItemCacheSet(c->Get()->id);
}
else if (c->CheckFlushTimeout())
@@ -1555,7 +1555,7 @@ void CClientManager::UpdateItemCache()
{
CItemCache * c = (it++)->second;
// 아이템은 Flush만 한다.
// 아이템은 Flush만 한다.
if (c->CheckFlushTimeout())
{
if (g_test_server)
@@ -1602,7 +1602,7 @@ void CClientManager::QUERY_ITEM_DESTROY(CPeer * pkPeer, const char * c_pData)
if (g_log)
sys_log(0, "HEADER_GD_ITEM_DESTROY: PID %u ID %u", dwPID, dwID);
if (dwPID == 0) // 아무도 가진 사람이 없었다면, 비동기 쿼리
if (dwPID == 0) // 아무도 가진 사람이 없었다면, 비동기 쿼리
CDBManager::instance().AsyncQuery(szQuery);
else
CDBManager::instance().ReturnQuery(szQuery, QID_ITEM_DESTROY, pkPeer->GetHandle(), NULL);
@@ -1680,7 +1680,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)
{
@@ -2161,8 +2161,8 @@ void CClientManager::WeddingEnd(TPacketWeddingEnd * p)
}
//
// 캐시에 가격정보가 있으면 캐시를 업데이트 하고 캐시에 가격정보가 없다면
// 우선 기존의 데이터를 로드한 뒤에 기존의 정보로 캐시를 만들고 새로 받은 가격정보를 업데이트 한다.
// 캐시에 가격정보가 있으면 캐시를 업데이트 하고 캐시에 가격정보가 없다면
// 우선 기존의 데이터를 로드한 뒤에 기존의 정보로 캐시를 만들고 새로 받은 가격정보를 업데이트 한다.
//
// Old code:
@@ -2242,7 +2242,7 @@ void CClientManager::MyshopPricelistUpdate(const TItemPriceListTable* pPacket)
}
// MYSHOP_PRICE_LIST
// 캐시된 가격정보가 있으면 캐시를 읽어 바로 전송하고 캐시에 정보가 없으면 DB 에 쿼리를 한다.
// 캐시된 가격정보가 있으면 캐시를 읽어 바로 전송하고 캐시에 정보가 없으면 DB 에 쿼리를 한다.
//
void CClientManager::MyshopPricelistRequest(CPeer* peer, DWORD dwHandle, DWORD dwPlayerID)
{
@@ -2656,15 +2656,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
@@ -2857,9 +2857,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;
@@ -2977,7 +2977,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+");
@@ -3010,7 +3010,7 @@ int CClientManager::Process()
++thecore_heart->pulse;
/*
//30분마다 변경
//30분마다 변경
if (((thecore_pulse() % (60 * 30 * 10)) == 0))
{
g_iPlayerCacheFlushSeconds = MAX(60, rand() % 180);
@@ -3088,11 +3088,11 @@ int CClientManager::Process()
m_iCacheFlushCount = 0;
//플레이어 플러쉬
//플레이어 플러쉬
UpdatePlayerCache();
//아이템 플러쉬
//아이템 플러쉬
UpdateItemCache();
//로그아웃시 처리- 캐쉬셋 플러쉬
//로그아웃시 처리- 캐쉬셋 플러쉬
UpdateLogoutPlayer();
// MYSHOP_PRICE_LIST
@@ -3162,13 +3162,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();
}
@@ -3178,7 +3178,7 @@ int CClientManager::Process()
int idx;
CPeer * peer;
for (idx = 0; idx < num_events; ++idx) // 인풋
for (idx = 0; idx < num_events; ++idx) // 인풋
{
peer = (CPeer *) fdwatch_get_client_data(m_fdWatcher, idx);
@@ -3258,7 +3258,7 @@ int CClientManager::Process()
DWORD CClientManager::GetUserCount()
{
// 단순히 로그인 카운트를 센다.. --;
// 단순히 로그인 카운트를 센다.. --;
return m_map_kLogonAccount.size();
}
@@ -3318,7 +3318,7 @@ bool CClientManager::InitializeNowItemID()
{
DWORD dwMin, dwMax;
//아이템 ID를 초기화 한다.
//아이템 ID를 초기화 한다.
if (!CConfig::instance().GetTwoValue("ITEM_ID_RANGE", &dwMin, &dwMax))
{
sys_err("conf.txt: Cannot find ITEM_ID_RANGE [start_item_id] [end_item_id]");
@@ -3748,7 +3748,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'",
@@ -4312,7 +4312,7 @@ void CClientManager::SendSpareItemIDRange(CPeer* peer)
}
//
// Login Key만 맵에서 지운다.
// Login Key만 맵에서 지운다.
//
void CClientManager::DeleteLoginKey(TPacketDC *data)
{
@@ -4425,7 +4425,7 @@ void CClientManager::EnrollInAuction (CPeer * peer, DWORD owner_id, AuctionEnrol
sys_err ("Player id %d doesn't have item %d.", 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());
@@ -4444,7 +4444,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())
@@ -4497,7 +4497,7 @@ void CClientManager::EnrollInSale (CPeer * peer, DWORD owner_id, AuctionEnrollSa
sys_err ("Player id %d doesn't have item %d.", 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());
@@ -4516,7 +4516,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())
@@ -4556,7 +4556,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());
@@ -4923,11 +4923,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)
{
@@ -4952,14 +4952,14 @@ void CClientManager::AuctionReBid (CPeer * peer, DWORD bidder_id, AuctionBidInfo
{
sys_log(0, "ReBid Success. bidder_id item_id %d %d", 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;
@@ -4994,14 +4994,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;

View File

@@ -1,4 +1,4 @@
// vim:ts=8 sw=4
// vim:ts=8 sw=4
#ifndef __INC_CLIENTMANAGER_H__
#define __INC_CLIENTMANAGER_H__
@@ -40,10 +40,10 @@ class CClientManager : public CNetBase, 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
@@ -69,7 +69,7 @@ class CClientManager : public CNetBase, public singleton<CClientManager>
pAccountTable = NULL;
player_id = dwPID;
};
//독일선물기능용 생성자
//독일선물기능용 생성자
ClientHandleInfo(DWORD argHandle, DWORD dwPID, DWORD accountId)
{
dwHandle = argHandle;
@@ -108,7 +108,7 @@ class CClientManager : public CNetBase, public singleton<CClientManager>
void SetChinaEventServer(bool flag) { m_bChinaEventServer = flag; }
bool IsChinaEventServer() { return m_bChinaEventServer; }
DWORD GetUserCount(); // 접속된 사용자 수를 리턴 한다.
DWORD GetUserCount(); // 접속된 사용자 수를 리턴 한다.
void SendAllGuildSkillRechargePacket();
void SendTime();
@@ -128,23 +128,23 @@ class CClientManager : public CNetBase, 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
@@ -162,8 +162,8 @@ class CClientManager : public CNetBase, public singleton<CClientManager>
void SendNotice(const char * c_pszFormat, ...);
char* GetCommand(char* str); //독일선물기능에서 명령어 얻는 함수
void ItemAward(CPeer * peer, char* login); //독일 선물 기능
char* GetCommand(char* str); //독일선물기능에서 명령어 얻는 함수
void ItemAward(CPeer * peer, char* login); //독일 선물 기능
protected:
void Destroy();
@@ -184,9 +184,9 @@ class CClientManager : public CNetBase, 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();
@@ -251,20 +251,20 @@ class CClientManager : public CNetBase, 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
@@ -344,7 +344,7 @@ class CClientManager : public CNetBase, public singleton<CClientManager>
void SendAllLoginToBilling();
void SendLoginToBilling(CLoginData * pkLD, bool bLogin);
// 결혼
// 결혼
void MarriageAdd(TPacketMarriageAdd * p);
void MarriageUpdate(TPacketMarriageUpdate * p);
void MarriageRemove(TPacketMarriageRemove * p);
@@ -354,20 +354,20 @@ class CClientManager : public CNetBase, 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);
void MyshopPricelistUpdate(const TItemPriceListTable* 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
@@ -387,7 +387,7 @@ class CClientManager : public CNetBase, public singleton<CClientManager>
private:
int m_looping;
socket_t m_fdAccept; // 접속 받는 소켓
socket_t m_fdAccept; // 접속 받는 소켓
TPeerList m_peerList;
CPeer * m_pkAuthPeer;
@@ -404,7 +404,7 @@ class CClientManager : public CNetBase, 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;
@@ -436,14 +436,14 @@ class CClientManager : public CNetBase, public singleton<CClientManager>
bool m_bShutdowned;
TPlayerTableCacheMap m_map_playerCache; // 플레이어 id가 key
TPlayerTableCacheMap m_map_playerCache; // 플레이어 id가 key
TItemCacheMap m_map_itemCache; // 아이템 id가 key
TItemCacheSetPtrMap m_map_pkItemCacheSetPtr; // 플레이어 id가 key, 이 플레이어가 어떤 아이템 캐쉬를 가지고 있나?
TItemCacheMap m_map_itemCache; // 아이템 id가 key
TItemCacheSetPtrMap m_map_pkItemCacheSetPtr; // 플레이어 id가 key, 이 플레이어가 어떤 아이템 캐쉬를 가지고 있나?
// MYSHOP_PRICE_LIST
/// 플레이어별 아이템 가격정보 리스트 map. key: 플레이어 ID, value: 가격정보 리스트 캐시
TItemPriceListCacheMap m_mapItemPriceListCache; ///< 플레이어별 아이템 가격정보 리스트
/// 플레이어별 아이템 가격정보 리스트 map. key: 플레이어 ID, value: 가격정보 리스트 캐시
TItemPriceListCacheMap m_mapItemPriceListCache; ///< 플레이어별 아이템 가격정보 리스트
// END_OF_MYSHOP_PRICE_LIST
TChannelStatusMap m_mChannelStatus;
@@ -481,7 +481,7 @@ class CClientManager : public CNetBase, public singleton<CClientManager>
//BOOT_LOCALIZATION
public:
/* 로컬 정보 초기화
/* 로컬 정보 초기화
**/
bool InitializeLocalization();

View File

@@ -1,4 +1,4 @@
// vim:ts=4 sw=4
// vim:ts=4 sw=4
#include <map>
#include <algorithm>
#include "stdafx.h"
@@ -172,42 +172,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'))
{
fprintf(stderr, "mob_names.txt 파일을 읽어오지 못했습니다\n");
fprintf(stderr, "mob_names.txt 파일을 읽어오지 못했습니다\n");
isNameFile = false;
} else {
nameData.Next(); //설명row 생략.
nameData.Next(); //설명row 생략.
while(nameData.Next()) {
localMap[atoi(nameData.AsStringByIndex(0))] = nameData.AsStringByIndex(1);
}
@@ -216,35 +216,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'))
{
fprintf(stderr, "테스트 파일이 없습니다. 그대로 진행합니다.\n");
fprintf(stderr, "테스트 파일이 없습니다. 그대로 진행합니다.\n");
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))
{
fprintf(stderr, "몹 프로토 테이블 셋팅 실패.\n");
fprintf(stderr, "몹 프로토 테이블 셋팅 실패.\n");
}
test_map_mobTableByVnum.insert(std::map<DWORD, TMobTable *>::value_type(test_mob_table->dwVnum, test_mob_table));
@@ -255,22 +255,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')) {
fprintf(stderr, "mob_proto.txt 파일을 읽어오지 못했습니다\n");
fprintf(stderr, "mob_proto.txt 파일을 읽어오지 못했습니다\n");
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));
@@ -280,15 +280,15 @@ bool CClientManager::InitializeMobTable()
addNumber++;
}
}
//data를 다시 첫줄로 옮긴다.(다시 읽어온다;;)
//data를 다시 첫줄로 옮긴다.(다시 읽어온다;;)
data.Destroy();
if(!data.Load("mob_proto.txt",'\t'))
{
fprintf(stderr, "mob_proto.txt 파일을 읽어오지 못했습니다\n");
fprintf(stderr, "mob_proto.txt 파일을 읽어오지 못했습니다\n");
return false;
}
data.Next(); //맨 윗줄 제외 (아이템 칼럼을 설명하는 부분)
//2.2 크기에 맞게 mob_table 생성
data.Next(); //맨 윗줄 제외 (아이템 칼럼을 설명하는 부분)
//2.2 크기에 맞게 mob_table 생성
if (!m_vec_mobTable.empty())
{
sys_log(0, "RELOAD: mob_proto");
@@ -297,18 +297,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;
@@ -379,13 +379,13 @@ bool CClientManager::InitializeMobTable()
if (!Set_Proto_Mob_Table(mob_table, data, localMap))
{
fprintf(stderr, "몹 프로토 테이블 셋팅 실패.\n");
fprintf(stderr, "몹 프로토 테이블 셋팅 실패.\n");
}
}
//셋에 vnum 추가
//셋에 vnum 추가
vnumSet.insert(mob_table->dwVnum);
@@ -396,22 +396,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'))
{
fprintf(stderr, "테스트 파일이 없습니다. 그대로 진행합니다.\n");
fprintf(stderr, "테스트 파일이 없습니다. 그대로 진행합니다.\n");
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()) {
@@ -420,7 +420,7 @@ bool CClientManager::InitializeMobTable()
if (!Set_Proto_Mob_Table(mob_table, test_data, localMap))
{
fprintf(stderr, "몹 프로토 테이블 셋팅 실패.\n");
fprintf(stderr, "몹 프로토 테이블 셋팅 실패.\n");
}
sys_log(0, "MOB #%-5d %-24s %-24s level: %-3u rank: %u empire: %d", mob_table->dwVnum, mob_table->szName, mob_table->szLocaleName, mob_table->bLevel, mob_table->bRank, mob_table->bEmpire);
@@ -448,8 +448,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)
@@ -488,7 +488,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];
@@ -561,7 +561,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);
@@ -572,39 +572,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'))
{
fprintf(stderr, "item_names.txt 파일을 읽어오지 못했습니다\n");
fprintf(stderr, "item_names.txt 파일을 읽어오지 못했습니다\n");
isNameFile = false;
} else {
nameData.Next();
@@ -615,32 +615,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'))
{
fprintf(stderr, "item_proto_test.txt 파일을 읽어오지 못했습니다\n");
fprintf(stderr, "item_proto_test.txt 파일을 읽어오지 못했습니다\n");
//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))
{
fprintf(stderr, "아이템 프로토 테이블 셋팅 실패.\n");
fprintf(stderr, "아이템 프로토 테이블 셋팅 실패.\n");
}
test_map_itemTableByVnum.insert(std::map<DWORD, TItemTable *>::value_type(test_item_table->dwVnum, test_item_table));
@@ -652,25 +652,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'))
{
fprintf(stderr, "item_proto.txt 파일을 읽어오지 못했습니다\n");
fprintf(stderr, "item_proto.txt 파일을 읽어오지 못했습니다\n");
return false;
}
data.Next(); //맨 윗줄 제외 (아이템 칼럼을 설명하는 부분)
data.Next(); //맨 윗줄 제외 (아이템 칼럼을 설명하는 부분)
if (!m_vec_itemTable.empty())
{
@@ -679,8 +679,8 @@ bool CClientManager::InitializeItemTable()
m_map_itemTableByVnum.clear();
}
//===== 아이템 테이블 생성 =====//
//새로 추가되는 갯수를 파악한다.
//===== 아이템 테이블 생성 =====//
//새로 추가되는 갯수를 파악한다.
int addNumber = 0;
while(data.Next()) {
int vnum = atoi(data.AsStringByIndex(0));
@@ -690,14 +690,14 @@ bool CClientManager::InitializeItemTable()
addNumber++;
}
}
//data를 다시 첫줄로 옮긴다.(다시 읽어온다;;)
//data를 다시 첫줄로 옮긴다.(다시 읽어온다;;)
data.Destroy();
if(!data.Load("item_proto.txt",'\t'))
{
fprintf(stderr, "item_proto.txt 파일을 읽어오지 못했습니다\n");
fprintf(stderr, "item_proto.txt 파일을 읽어오지 못했습니다\n");
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());
@@ -712,16 +712,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))
{
fprintf(stderr, "아이템 프로토 테이블 셋팅 실패.\n");
fprintf(stderr, "아이템 프로토 테이블 셋팅 실패.\n");
}
} else { //$$$$$$$$$$$$$$$$$$$$$$$ 테스트 아이템 정보가 있다!
} else { //$$$$$$$$$$$$$$$$$$$$$$$ 테스트 아이템 정보가 있다!
TItemTable *tempTable = it_map_itemTable->second;
item_table->dwVnum = tempTable->dwVnum;
@@ -778,19 +778,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'))
{
fprintf(stderr, "item_proto_test.txt 파일을 읽어오지 못했습니다\n");
fprintf(stderr, "item_proto_test.txt 파일을 읽어오지 못했습니다\n");
//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()) {
@@ -799,7 +799,7 @@ bool CClientManager::InitializeItemTable()
if (!Set_Proto_Item_Table(item_table, test_data, localMap))
{
fprintf(stderr, "아이템 프로토 테이블 셋팅 실패.\n");
fprintf(stderr, "아이템 프로토 테이블 셋팅 실패.\n");
}

View File

@@ -1,4 +1,4 @@
// vim:ts=4 sw=4
// vim:ts=4 sw=4
#include "stdafx.h"
#include "ClientManager.h"
#include "Main.h"

View File

@@ -1,4 +1,4 @@
// vim:ts=4 sw=4
// vim:ts=4 sw=4
#include "stdafx.h"
#include "ClientManager.h"
#include "Main.h"
@@ -126,13 +126,13 @@ const char* __GetWarType(int n)
switch (n)
{
case 0 :
return "패왕";
return "패왕";
case 1 :
return "맹장";
return "맹장";
case 2 :
return "수호";
return "수호";
default :
return "없는 번호";
return "없는 번호";
}
}
@@ -161,7 +161,7 @@ void CClientManager::GuildWar(CPeer* peer, TPacketGuildWar* p)
case GUILD_WAR_WAIT_START:
sys_log(0, "GuildWar: GUILD_WAR_WAIT_START type(%s) guild(%d - %d)", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
case GUILD_WAR_RESERVE: // 길드전 예약
case GUILD_WAR_RESERVE: // 길드전 예약
if (p->bWar != GUILD_WAR_WAIT_START)
sys_log(0, "GuildWar: GUILD_WAR_RESERVE type(%s) guild(%d - %d)", __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: // 길드전을 시작 시킨다. (필드전은 바로 시작 됨)
sys_log(0, "GuildWar: GUILD_WAR_ON_WAR type(%s) guild(%d - %d)", __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: // 길드전 정상 종료
sys_log(0, "GuildWar: GUILD_WAR_OVER type(%s) guild(%d - %d)", __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: // 길드전 비정상 종료
sys_log(0, "GuildWar: GUILD_WAR_END type(%s) guild(%d - %d)", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);
CGuildManager::instance().RecvWarEnd(p->dwGuildFrom, p->dwGuildTo);
return; // NOTE: RecvWarEnd에서 패킷을 보내므로 따로 브로드캐스팅 하지 않는다.
return; // NOTE: RecvWarEnd에서 패킷을 보내므로 따로 브로드캐스팅 하지 않는다.
case GUILD_WAR_CANCEL :
sys_log(0, "GuildWar: GUILD_WAR_CANCEL type(%s) guild(%d - %d)", __GetWarType(p->bType), p->dwGuildFrom, p->dwGuildTo);

View File

@@ -1,4 +1,4 @@
// vim:ts=4 sw=4
// vim:ts=4 sw=4
#include "stdafx.h"
#include "ClientManager.h"

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "ClientManager.h"
@@ -249,7 +249,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));
@@ -373,7 +373,7 @@ void CClientManager::RESULT_LOGIN(CPeer * peer, SQLMsg * msg)
if (info->account_index == 0)
{
// 계정이 없네?
// 계정이 없네?
if (msg->Get()->uiNumRows == 0)
{
sys_log(0, "RESULT_LOGIN: no account");
@@ -415,14 +415,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))
{
sys_log(0, "RESULT_LOGIN: already logon %s", info->pAccountTable->login);

View File

@@ -1,4 +1,4 @@
// vim:ts=4 sw=4
// vim:ts=4 sw=4
#include "stdafx.h"
#include "ClientManager.h"
#include "Config.h"

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "ClientManager.h"
@@ -32,7 +32,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;
@@ -159,7 +159,7 @@ size_t CreatePlayerSaveQuery(char * pszQuery, size_t querySize, TPlayerTable * p
pkTab->horse.sStamina,
pkTab->horse_skill_point);
// Binary 로 바꾸기 위한 임시 공간
// Binary 로 바꾸기 위한 임시 공간
static char text[8192 + 1];
CDBManager::instance().EscapeString(text, pkTab->skills, sizeof(pkTab->skills));
@@ -211,7 +211,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
TPlayerTable * pTab;
//
// 한 계정에 속한 모든 캐릭터들 캐쉬처리
// 한 계정에 속한 모든 캐릭터들 캐쉬처리
//
CLoginData * pLoginData = GetLoginDataByAID(packet->account_id);
@@ -223,12 +223,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)))
{
@@ -268,13 +268,13 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
sys_log(0, "[PLAYER_LOAD] ID %s pid %d gold %d ", 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)
{
@@ -289,7 +289,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이 없으면 삭제된 아이템이다.
thecore_memcpy(&s_items[dwCount++], p, sizeof(TPlayerItem));
}
@@ -316,7 +316,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
{
@@ -350,7 +350,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
//return;
}
//----------------------------------
// 2. 유저정보가 DBCache 에 없음 : DB에서
// 2. 유저정보가 DBCache 에 없음 : DB에서
//----------------------------------
else
{
@@ -359,7 +359,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad
char queryStr[QUERY_MAX_LEN];
//--------------------------------------------------------------
// 캐릭터 정보 얻어오기 : 무조건 DB에서
// 캐릭터 정보 얻어오기 : 무조건 DB에서
//--------------------------------------------------------------
snprintf(queryStr, sizeof(queryStr),
"SELECT "
@@ -375,7 +375,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 "
@@ -384,15 +384,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",
@@ -409,21 +409,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)); // command 얻기
if( !(strcmp(command,"GIFT") )) // command 가 GIFT이면
strcpy(command,GetCommand(cmdStr)); // 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));
}
}
@@ -444,7 +444,7 @@ char* 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));
@@ -531,11 +531,11 @@ bool CreatePlayerTableFromRes(MYSQL_RES * res, TPlayerTable * pkTab)
int max_point = pkTab->level - 9;
int skill_point =
MIN(20, pkTab->skills[121].bLevel) + // SKILL_LEADERSHIP 통솔력
MIN(20, pkTab->skills[124].bLevel) + // SKILL_MINING 채광
MIN(10, pkTab->skills[131].bLevel) + // SKILL_HORSE_SUMMON 말소환
MIN(20, pkTab->skills[141].bLevel) + // SKILL_ADD_HP HP보강
MIN(20, pkTab->skills[142].bLevel); // SKILL_RESIST_PENETRATE 관통저항
MIN(20, pkTab->skills[121].bLevel) + // SKILL_LEADERSHIP 통솔력
MIN(20, pkTab->skills[124].bLevel) + // SKILL_MINING 채광
MIN(10, pkTab->skills[131].bLevel) + // SKILL_HORSE_SUMMON 말소환
MIN(20, pkTab->skills[141].bLevel) + // SKILL_ADD_HP HP보강
MIN(20, pkTab->skills[142].bLevel); // SKILL_RESIST_PENETRATE 관통저항
pkTab->sub_skill_point = max_point - skill_point;
}
@@ -575,13 +575,13 @@ void CClientManager::RESULT_COMPOSITE_PLAYER(CPeer * peer, SQLMsg * pMsg, DWORD
{
sys_log(0, "QID_QUEST %u", 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 )
@@ -672,14 +672,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
@@ -691,7 +691,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를 넣는다.
}
}
@@ -699,7 +699,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;
@@ -796,7 +796,7 @@ void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerC
int queryLen;
int player_id;
// 한 계정에 X초 내로 캐릭터 생성을 할 수 없다.
// 한 계정에 X초 내로 캐릭터 생성을 할 수 없다.
time_by_id_map_t::iterator it = s_createTimeByAccountID.find(packet->account_id);
if (it != s_createTimeByAccountID.end())
@@ -1027,7 +1027,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)
{
@@ -1078,14 +1078,14 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
return;
}
// 삭제 성공
// 삭제 성공
sys_log(0, "PLAYER_DELETE SUCCESS %u", 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)
@@ -1094,7 +1094,7 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
delete pkPlayerCache;
}
// 아이템들을 캐쉬에서 삭제한다.
// 아이템들을 캐쉬에서 삭제한다.
TItemCacheSet * pSet = GetItemCacheSet(pi->player_id);
if (pSet)
@@ -1157,7 +1157,7 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg)
}
else
{
// 삭제 실패
// 삭제 실패
sys_log(0, "PLAYER_DELETE FAIL NO ROW");
peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1);
peer->EncodeBYTE(pi->account_index);
@@ -1242,7 +1242,7 @@ void CClientManager::RESULT_HIGHSCORE_REGISTER(CPeer * pkPeer, SQLMsg * msg)
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);
@@ -1277,7 +1277,7 @@ void CClientManager::RESULT_HIGHSCORE_REGISTER(CPeer * pkPeer, SQLMsg * msg)
CDBManager::instance().AsyncQuery(buf);
}
}
// TODO: 이곳에서 하이스코어가 업데이트 되었는지 체크하여 공지를 뿌려야한다.
// TODO: 이곳에서 하이스코어가 업데이트 되었는지 체크하여 공지를 뿌려야한다.
delete pi;
}
@@ -1285,10 +1285,10 @@ void CClientManager::InsertLogoutPlayer(DWORD pid)
{
TLogoutPlayerMap::iterator it = m_map_logout.find(pid);
// 존재하지 않을경우 추가
// 존재하지 않을경우 추가
if (it != m_map_logout.end())
{
// 존재할경우 시간만 갱신
// 존재할경우 시간만 갱신
if (g_log)
sys_log(0, "LOGOUT: Update player time pid(%d)", pid);

View File

@@ -1,4 +1,4 @@
#ifndef __INC_CONFIG_H__
#ifndef __INC_CONFIG_H__
#define __INC_CONFIG_H__
typedef std::map<std::string, std::string> TValueMap;

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "CsvReader.h"
#include <fstream>
#include <algorithm>
@@ -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
{

View File

@@ -1,4 +1,4 @@
#ifndef __CSVFILE_H__
#ifndef __CSVFILE_H__
#define __CSVFILE_H__
#include <string>
@@ -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; }
};

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "DBManager.h"
#include "ClientManager.h"

View File

@@ -1,4 +1,4 @@
#ifndef __INC_METIN2_DB_DBMANAGER_H__
#ifndef __INC_METIN2_DB_DBMANAGER_H__
#define __INC_METIN2_DB_DBMANAGER_H__
#include <mysql.h>

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "GuildManager.h"
#include "Main.h"
#include "ClientManager.h"
@@ -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, long lWarPrice)
{
@@ -571,7 +571,7 @@ void CGuildManager::RecvWarOver(DWORD dwGuildWinner, DWORD dwGuildLoser, bool bD
void CGuildManager::RecvWarEnd(DWORD GID1, DWORD GID2)
{
sys_log(0, "GuildWar: RecvWarEnded : %u vs %u", 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)
sys_log(0, "GuildManager::ChangeLadderPoint %u %d", GID, r.ladder_point);
sys_log(0, "%s", 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[MIN(GUILD_MAX_LEVEL, k1.level)];
@@ -1026,7 +1026,7 @@ bool CGuildManager::ReserveWar(TPacketGuildWar * p)
t.lPowerFrom = (long) polyPower.Eval();
sys_log(0, "GuildWar: %u lvp %d rkp %d alv %d mc %d power %d", GID1, lvp, rkp, alv, mc, t.lPowerFrom);
// 파워 계산
// 파워 계산
TGuild & k2 = TouchGuild(GID2);
lvp = c_aiScoreByLevel[MIN(GUILD_MAX_LEVEL, k2.level)];
@@ -1042,7 +1042,7 @@ bool CGuildManager::ReserveWar(TPacketGuildWar * p)
t.lPowerTo = (long) polyPower.Eval();
sys_log(0, "GuildWar: %u lvp %d rkp %d alv %d mc %d power %d", 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 = (long) polyHandicap.Eval();
sys_log(0, "GuildWar: handicap %d", 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("%s 길드와 %s 길드의 전쟁이 약 %d분 후 시작 됩니다!", 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("%s 곤삔뵨 %s 곤삔돨곤삔濫轢쉥瞳 %d롸爐빈역迦!", 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% 세금 공제 후 분배
sys_log(0, "WAR_REWARD: %s %u ratio %f", it->first.c_str(), it->second.second, ratio);
DWORD dwGold = (DWORD) (dwTotalBet * ratio * 0.9);

View File

@@ -1,4 +1,4 @@
// vim:ts=8 sw=4
// vim:ts=8 sw=4
#ifndef __INC_GUILD_MANAGER_H
#define __INC_GUILD_MANAGER_H
@@ -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;

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "HB.h"
#include "Main.h"
#include "DBManager.h"
@@ -30,7 +30,7 @@ bool PlayerHB::Initialize()
}
//
// @version 05/07/05 Bang2ni - id 에 해당하는 data 가 없을 때 쿼리하고 data 를 insert 하는코드 추가.
// @version 05/07/05 Bang2ni - id 에 해당하는 data 가 없을 때 쿼리하고 data 를 insert 하는코드 추가.
//
void PlayerHB::Put(DWORD id)
{
@@ -48,7 +48,7 @@ void PlayerHB::Put(DWORD id)
}
//
// @version 05/07/05 Bang2ni - Query string 버퍼가 작아서 늘려줌.
// @version 05/07/05 Bang2ni - Query string 버퍼가 작아서 늘려줌.
//
bool PlayerHB::Query(DWORD id)
{

View File

@@ -1,4 +1,4 @@
// vim:ts=8 sw=4
// vim:ts=8 sw=4
#ifndef __INC_METIN_II_PLAYERHB_H__
#define __INC_METIN_II_PLAYERHB_H__

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "QID.h"
#include "DBManager.h"
#include "ItemAwardManager.h"
@@ -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)); // command 얻기
strcpy(command,CClientManager::instance().GetCommand(cmdStr)); // command 얻기
//sys_err("%d, %s",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));
}
}

View File

@@ -1,4 +1,4 @@
// vim:ts=8 sw=4
// vim:ts=8 sw=4
#ifndef __INC_ITEM_AWARD_H
#define __INC_ITEM_AWARD_H
#include <map>

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "ItemIDRangeManager.h"
#include "Main.h"
#include "DBManager.h"

View File

@@ -1,4 +1,4 @@
// vim:ts=4 sw=4
// vim:ts=4 sw=4
#ifndef __INC_METIN_II_ITEM_ID_RANGE_MANAGER_H__
#define __INC_METIN_II_ITEM_ID_RANGE_MANAGER_H__

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "Lock.h"
CLock::CLock()

View File

@@ -1,4 +1,4 @@
// vim:ts=8 sw=4
// vim:ts=8 sw=4
#ifndef __INC_LOCK_H__
#define __INC_LOCK_H__

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "LoginData.h"
#include "ClientManager.h"

View File

@@ -1,4 +1,4 @@
// vim:ts=8 sw=4
// vim:ts=8 sw=4
#ifndef __INC_METIN_II_DB_LOGINDATA_H__
#define __INC_METIN_II_DB_LOGINDATA_H__

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "Config.h"
#include "Peer.h"
#include "DBManager.h"
@@ -30,11 +30,11 @@ 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;
int g_log = 1;
@@ -123,13 +123,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()
{

View File

@@ -1,4 +1,4 @@
#ifndef __INC_MAIN_H__
#ifndef __INC_MAIN_H__
#define __INC_MAIN_H__
int Start();

View File

@@ -1,4 +1,4 @@
// vim: ts=4 sw=4
// vim: ts=4 sw=4
#ifndef __MARRIAGE_H
#define __MARRIAGE_H
@@ -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;

View File

@@ -1,4 +1,4 @@
// vim: ts=4 sw=4
// vim: ts=4 sw=4
#ifndef METIN2_MONARCH_H
#define METIN2_MONARCH_H

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "MoneyLog.h"
#include "ClientManager.h"
#include "Peer.h"

View File

@@ -1,4 +1,4 @@
// vim: ts=8 sw=4
// vim: ts=8 sw=4
#ifndef __INC_MONEY_LOG
#define __INC_MONEY_LOG

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "NetBase.h"
#include "Config.h"
#include "ClientManager.h"

View File

@@ -1,4 +1,4 @@
// vim: ts=8 sw=4
// vim: ts=8 sw=4
#ifndef __INC_NETWORKBASE_H__
#define __INC_NETWORKBASE_H__

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "Peer.h"
#include "ItemIDRangeManager.h"

View File

@@ -1,4 +1,4 @@
// vim: ts=8 sw=4
// vim: ts=8 sw=4
#ifndef __INC_PEER_H__
#define __INC_PEER_H__
@@ -66,9 +66,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[32]; // 어떤 맵을 관장하고 있는가?
WORD m_wListenPort; // 게임서버가 클라이언트를 위해 listen 하는 포트
WORD m_wP2PPort; // 게임서버가 게임서버 P2P 접속을 위해 listen 하는 포트
long m_alMaps[32]; // 어떤 맵을 관장하고 있는가?
TItemIDRangeTable m_itemRange;
TItemIDRangeTable m_itemSpareRange;

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "PeerBase.h"
CPeerBase::CPeerBase() : m_fd(INVALID_SOCKET), m_BytesRemain(0), m_outBuffer(NULL), m_inBuffer(NULL)

View File

@@ -1,4 +1,4 @@
// vim: ts=8 sw=4
// vim: ts=8 sw=4
#ifndef __INC_PEERBASE_H__
#define __INC_PEERBASE_H__

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "PrivManager.h"
#include "ClientManager.h"
@@ -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
{

View File

@@ -1,4 +1,4 @@
// vim: ts=8 sw=4
// vim: ts=8 sw=4
#ifndef __INC_PRIV_MANAGER_H
#define __INC_PRIV_MANAGER_H
@@ -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>
{

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include <math.h>
#include "ProtoReader.h"
@@ -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)
{
sys_err("SubType : Out of range!! (type_value: %d, count of registered subtype: %d", 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()) {
@@ -750,11 +750,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];
@@ -778,7 +778,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()) {

View File

@@ -1,4 +1,4 @@
#ifndef __Item_CSV_READER_H__
#ifndef __Item_CSV_READER_H__
#define __Item_CSV_READER_H__
#include <iostream>
@@ -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);

View File

@@ -1,8 +1,8 @@
#ifndef __INC_METIN_II_DB_QID_H__
#ifndef __INC_METIN_II_DB_QID_H__
#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
{
@@ -29,10 +29,10 @@ enum QID
QID_GUILD_RANKING, // 20
// MYSHOP_PRICE_LIST
QID_ITEMPRICE_SAVE, ///< 21, 아이템 가격정보 저장 쿼리
QID_ITEMPRICE_DESTROY, ///< 22, 아이템 가격정보 삭제 쿼리
QID_ITEMPRICE_LOAD_FOR_UPDATE, ///< 23, 가격정보 업데이트를 위한 아이템 가격정보 로드 쿼리
QID_ITEMPRICE_LOAD, ///< 24, 아이템 가격정보 로드 쿼리
QID_ITEMPRICE_SAVE, ///< 21, 아이템 가격정보 저장 쿼리
QID_ITEMPRICE_DESTROY, ///< 22, 아이템 가격정보 삭제 쿼리
QID_ITEMPRICE_LOAD_FOR_UPDATE, ///< 23, 가격정보 업데이트를 위한 아이템 가격정보 로드 쿼리
QID_ITEMPRICE_LOAD, ///< 24, 아이템 가격정보 로드 쿼리
// END_OF_MYSHOP_PRICE_LIST
};

View File

@@ -1,4 +1,4 @@
#include <string.h>
#include <string.h>
#include <stdio.h>
#include "../../libthecore/include/memcpy.h"
#include "../../common/stl.h"
@@ -29,7 +29,7 @@ void CGrid::Clear()
int CGrid::FindBlank(int w, int h)
{
// 크기가 더 크다면 확인할 필요 없이 그냥 리턴
// 크기가 더 크다면 확인할 필요 없이 그냥 리턴
if (w > m_iWidth || h > m_iHeight)
return -1;
@@ -87,7 +87,7 @@ bool CGrid::IsEmpty(int iPos, int w, int h)
{
int iRow = iPos / m_iWidth;
// Grid 안쪽인가를 먼저 검사
// Grid 안쪽인가를 먼저 검사
if (iRow + h > m_iHeight)
return false;

View File

@@ -1,4 +1,4 @@
// vim: ts=8 sw=4
// vim: ts=8 sw=4
#ifndef __INC_METIN_II_GRID_H__
#define __INC_METIN_II_GRID_H__

View File

@@ -1,4 +1,4 @@
#ifndef __INC_METiN_II_DBSERV_STDAFX_H__
#ifndef __INC_METiN_II_DBSERV_STDAFX_H__
#define __INC_METiN_II_DBSERV_STDAFX_H__
#include "../../libthecore/include/stdafx.h"

View File

@@ -1,4 +1,4 @@
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
void WriteVersion()

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "constants.h"
#include "BattleArena.h"
#include "start_position.h"
@@ -102,14 +102,14 @@ EVENTFUNC(battle_arena_event)
case 0:
{
++pInfo->state;
BroadcastNotice(LC_TEXT("몬스터들의 공격까지 5분 남았습니다!!!"));
BroadcastNotice(LC_TEXT("몬스터들의 공격까지 5분 남았습니다!!!"));
}
return test_server ? PASSES_PER_SEC(60) : PASSES_PER_SEC(60*4);
case 1:
{
++pInfo->state;
BroadcastNotice(LC_TEXT("몬스터들의 공격까지 1분 남았습니다!!!"));
BroadcastNotice(LC_TEXT("몬스터들의 공격까지 1분 남았습니다!!!"));
}
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("몬스터들이 성을 공격하기 시작했습니다."));
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("중앙 제단에 악의 기운이 모여듭니다."), 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("몬스터들이 물러갈 조짐을 보입니다."), 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("몬스터들이 물러가기 시작했습니다."), pInfo->nMapIndex, false);
SendNoticeMap(LC_TEXT("잠시 후 마을로 돌아갑니다."), 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("몬스터들의 대장이 나타났습니다."), pInfo->nMapIndex, false);
SendNoticeMap(LC_TEXT("30분 내로 귀목령주를 물리쳐주세요."), 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("귀목령주와 그의 부하들을 모두 물리쳤습니다."), pInfo->nMapIndex, false);
SendNoticeMap(LC_TEXT("잠시 후 마을로 돌아갑니다."), 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("귀목령주가 퇴각하였습니다."), pInfo->nMapIndex, false);
SendNoticeMap(LC_TEXT("잠시 후 마을로 돌아갑니다."), 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("%s의 성으로 몬스터들이 진군하고 있습니다."), EMPIRE_NAME(m_nEmpire));
BroadcastNotice(szBuf);
BroadcastNotice(LC_TEXT("10분 뒤 성을 공격할 예정입니다."));
BroadcastNotice(LC_TEXT("10분 뒤 성을 공격할 예정입니다."));
if (m_pEvent != NULL) {
event_cancel(&m_pEvent);

View File

@@ -1,4 +1,4 @@
const static int nBATTLE_ARENA_MAP[] = { 0, 190, 191, 192 };
const static std::string strRegen[] =
{

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "BlueDragon.h"

View File

@@ -1,4 +1,4 @@
extern int BlueDragon_StateBattle (LPCHARACTER);
extern time_t UseBlueDragonSkill (LPCHARACTER, unsigned int);
extern int BlueDragon_Damage (LPCHARACTER me, LPCHARACTER attacker, int dam);

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "BlueDragon_Binder.h"

View File

@@ -1,4 +1,4 @@
enum BLUEDRAGON_STONE_EFFECT
{
DEF_BONUS = 1,

View File

@@ -1,4 +1,4 @@
struct FSkillBreath
{
EJobs Set1;

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "ClientPackageCryptInfo.h"
#include "../../common/stl.h"

View File

@@ -1,4 +1,4 @@
#ifndef __INC_CLIENTPACKAGE_CRYPTINFO_H
#ifndef __INC_CLIENTPACKAGE_CRYPTINFO_H
#define __INC_CLIENTPACKAGE_CRYPTINFO_H
#include <unordered_map>

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "DragonLair.h"
@@ -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("용가리가 %d 초만에 죽어써효ㅠㅠ"), pInfo->pLair->GetEstimatedTime());
SendNoticeMap(buf, pInfo->InstanceMapIndex, true);
pInfo->step++;
@@ -146,7 +146,7 @@ DWORD CDragonLair::GetEstimatedTime() const
void CDragonLair::OnDragonDead(LPCHARACTER pDragon)
{
sys_log(0, "DragonLair: 도라곤이 죽어써효");
sys_log(0, "DragonLair: 도라곤이 죽어써효");
LogManager::instance().DragonSlayLog( GuildID_, pDragon->GetMobTable().dwVnum, StartTime_, get_global_time() );
}
@@ -239,7 +239,7 @@ void CDragonLairManager::OnDragonDead(LPCHARACTER pDragon, DWORD KillerGuildID)
iter->second->OnDragonDead( pDragon );
// 애들 다 집으로 보내고 맵 없애기
// 애들 다 집으로 보내고 맵 없애기
tag_DragonLair_Collapse_EventInfo* info;
info = AllocEventInfo<tag_DragonLair_Collapse_EventInfo>();

View File

@@ -1,4 +1,4 @@
#include <unordered_map>
#include "../../common/stl.h"

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "constants.h"
#include "item.h"
#include "item_manager.h"
@@ -37,7 +37,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();
@@ -73,11 +73,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)
@@ -175,7 +175,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))
{
@@ -321,14 +321,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("착용 중인 용혼석은 추출할 수 없습니다."));
return false;
}
@@ -372,7 +372,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("용심 추출에 실패하였습니다."));
return false;
}
else
@@ -399,12 +399,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("용심 추출에 성공하였습니다."));
return true;
}
}
// 특정 용혼석을 장비창에서 제거할 때에 성공 여부를 결정하고, 실패시 부산물을 주는 함수.
// 특정 용혼석을 장비창에서 제거할 때에 성공 여부를 결정하고, 실패시 부산물을 주는 함수.
bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM pExtractor)
{
if (NULL == ch || NULL == pItem)
@@ -413,13 +413,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("소지품에 빈 공간이 없습니다."));
return false;
}
else
@@ -437,14 +437,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);
@@ -461,7 +461,7 @@ bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM
bSuccess = fDice <= (fProb * (100 + iBonus) / 100.f);
}
// 캐릭터의 용혼석 추출 및 추가 혹은 제거. 부산물 제공.
// 캐릭터의 용혼석 추출 및 추가 혹은 제거. 부산물 제공.
{
char buf[128];
@@ -476,7 +476,7 @@ bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM
sprintf(buf, "dice(%d) prob(%d)", fDice, 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("용혼석 추출에 성공하였습니다."));
pItem->AddToCharacter(ch, DestCell);
return true;
}
@@ -497,12 +497,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("용혼석 추출에 실패하여 %s를 얻었습니다."), pByProduct->GetName());
else
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용혼석 추출에 실패하였습니다."));
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용혼석 추출에 실패하였습니다."));
}
else
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용혼석 추출에 실패하였습니다."));
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용혼석 추출에 실패하였습니다."));
}
}
@@ -526,8 +526,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++)
{
@@ -536,10 +536,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("등급 개량에 필요한 재료가 아닙니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
return false;
@@ -564,7 +564,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;
@@ -573,7 +573,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("등급 개량할 수 없는 용혼석입니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
return false;
@@ -583,8 +583,8 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL
{
LPITEM pItem = *it;
// 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에,
// 별도의 알림 처리는 안함.
// 클라 ui에서 장착한 아이템은 개량창에 올릴 수 없도록 막았기 때문에,
// 별도의 알림 처리는 안함.
if (pItem->IsEquipped())
{
return false;
@@ -592,14 +592,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("등급 개량에 필요한 재료가 아닙니다."));
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)
{
sys_err ("Possiblity of invalid client. Name %s", ch->GetName());
@@ -610,7 +610,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("개량을 하기 위한 돈이 부족합니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS);
return false;
}
@@ -655,7 +655,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("등급 개량에 성공했습니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_SUCCEED, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell()));
return true;
}
@@ -664,7 +664,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("등급 개량에 실패했습니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell()));
return false;
}
@@ -686,18 +686,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("단계 개량에 필요한 재료가 아닙니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
return false;
}
@@ -720,7 +720,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;
@@ -728,7 +728,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("단계 개량할 수 없는 용혼석입니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
return false;
}
@@ -737,21 +737,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("단계 개량에 필요한 재료가 아닙니다."));
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)
{
sys_err ("Possiblity of invalid client. Name %s", ch->GetName());
@@ -762,7 +762,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("개량을 하기 위한 돈이 부족합니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS);
return false;
}
@@ -807,7 +807,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("단계 개량에 성공했습니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_SUCCEED, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell()));
return true;
}
@@ -816,7 +816,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("단계 개량에 실패했습니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell()));
return false;
}
@@ -847,8 +847,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++)
{
@@ -870,15 +870,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)
@@ -899,7 +899,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("강화에 필요한 재료가 아닙니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell()));
return false;
}
@@ -919,17 +919,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("강화할 수 없는 용혼석입니다."));
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("강화할 수 없는 용혼석입니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell()));
return false;
}
@@ -938,7 +938,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("강화할 수 없는 용혼석입니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell()));
return false;
@@ -946,7 +946,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("개량을 하기 위한 돈이 부족합니다."));
SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS);
return false;
}
@@ -974,7 +974,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("강화에 성공했습니다."));
ch->AutoGiveItem(pResult, true);
bSubHeader = DS_SUB_HEADER_REFINE_SUCCEED;
}
@@ -995,10 +995,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("강화에 실패했습니다."));
pDragonSoul->SetCount(pDragonSoul->GetCount() - 1);
pRefineStone->SetCount(pRefineStone->GetCount() - 1);
if (NULL != pResult)
@@ -1036,12 +1036,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;
@@ -1053,12 +1053,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;

View File

@@ -1,4 +1,4 @@
#ifndef __INC_METIN_II_GAME_DRAGON_SOUL_H__
#ifndef __INC_METIN_II_GAME_DRAGON_SOUL_H__
#define __INC_METIN_II_GAME_DRAGON_SOUL_H__
#include "../../common/length.h"
@@ -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);

View File

@@ -1,4 +1,4 @@
// Local Includes
// Local Includes
#include <cassert>
#include <cstdlib>

View File

@@ -1,4 +1,4 @@
#ifndef _fsm_fsm_h
#ifndef _fsm_fsm_h
#define _fsm_fsm_h
// Local Includes

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "FileMonitor_FreeBSD.h"
#include "../../libthecore/include/log.h"

View File

@@ -1,4 +1,4 @@
#ifndef FILEMONITOR_FREEBSD_INCLUDED
#ifndef FILEMONITOR_FREEBSD_INCLUDED
#define FILEMONITOR_FREEBSD_INCLUDED
#include "IFileMonitor.h"

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "HackShield.h"

View File

@@ -1,4 +1,4 @@
#ifndef HACK_SHIELD_MANAGER_H_
#define HACK_SHIELD_MANAGER_H_

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "HackShield_Impl.h"

View File

@@ -1,4 +1,4 @@
#ifndef HACK_SHIELD_IMPL_H_
#define HACK_SHIELD_IMPL_H_

View File

@@ -1,4 +1,4 @@
#ifndef IFILEMONITOR_INCLUDED
#ifndef IFILEMONITOR_INCLUDED
#define IFILEMONITOR_INCLUDED
//#include <boost/function.hpp>

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "MarkManager.h"
#ifdef OS_WINDOWS
@@ -30,14 +30,14 @@ static Pixel * LoadOldGuildMarkImageFile()
bool GuildMarkConvert(const std::vector<DWORD> & vecGuildID)
{
// 폴더 생성
// 폴더 생성
#ifndef OS_WINDOWS
mkdir("mark", S_IRWXU);
#else
_mkdir("mark");
#endif
// 인덱스 파일이 있나?
// 인덱스 파일이 있나?
#ifndef OS_WINDOWS
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 OS_WINDOWS
system("mv -f guild_mark.idx guild_mark.idx.removable");
system("mv -f guild_mark.tga guild_mark.tga.removable");

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "MarkImage.h"
#include "crc32.h"
@@ -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];
sys_log(0, "GuildMarkImage::BuildAllBlocks");

View File

@@ -1,4 +1,4 @@
#ifndef __INC_METIN_II_MARKIMAGE_H__
#ifndef __INC_METIN_II_MARKIMAGE_H__
#define __INC_METIN_II_MARKIMAGE_H__
#include <IL/il.h>
@@ -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);

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "MarkManager.h"
#include "crc32.h"
@@ -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];
@@ -178,7 +178,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;
@@ -264,7 +264,7 @@ void CGuildMarkManager::GetDiffBlocks(DWORD imgIdx, const DWORD * crcList, std::
{
mapDiffBlocks.clear();
// 클라이언트에서 서버에 없는 이미지를 요청할 수는 없다.
// 클라이언트에서 서버에 없는 이미지를 요청할 수는 없다.
if (m_mapIdx_Image.end() == m_mapIdx_Image.find(imgIdx))
{
sys_err("invalid idx %u", imgIdx);
@@ -291,7 +291,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))
{
sys_err("invalid idx %u", imgIdx);

View File

@@ -1,4 +1,4 @@
#ifndef __INC_METIN_II_GUILDLIB_MARK_MANAGER_H__
#ifndef __INC_METIN_II_GUILDLIB_MARK_MANAGER_H__
#define __INC_METIN_II_GUILDLIB_MARK_MANAGER_H__
#include "MarkImage.h"
@@ -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);

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "constants.h"
#include "config.h"
#include "questmanager.h"
@@ -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("") : LC_TEXT("거짓"));
}
}
pkChar->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("醚 柠令 荐: %d"), c);
pkChar->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("총 퀴즈 수: %d"), c);
return true;
}
@@ -197,31 +197,31 @@ EVENTFUNC(oxevent_timer)
switch (flag)
{
case 0:
SendNoticeMap(LC_TEXT("10檬第 魄沥窍摆嚼聪促."), OXEVENT_MAP_INDEX, true);
SendNoticeMap(LC_TEXT("10초뒤 판정하겠습니다."), OXEVENT_MAP_INDEX, true);
flag++;
return PASSES_PER_SEC(10);
case 1:
SendNoticeMap(LC_TEXT("沥翠篮"), OXEVENT_MAP_INDEX, true);
SendNoticeMap(LC_TEXT("정답은"), OXEVENT_MAP_INDEX, true);
if (info->answer == true)
{
COXEventManager::instance().CheckAnswer(true);
SendNoticeMap(LC_TEXT("O 涝聪促"), OXEVENT_MAP_INDEX, true);
SendNoticeMap(LC_TEXT("O 입니다"), OXEVENT_MAP_INDEX, true);
}
else
{
COXEventManager::instance().CheckAnswer(false);
SendNoticeMap(LC_TEXT("X 涝聪促"), OXEVENT_MAP_INDEX, true);
SendNoticeMap(LC_TEXT("X 입니다"), OXEVENT_MAP_INDEX, true);
}
if (LC_IsJapan())
{
SendNoticeMap("娫堘偊偨曽乆傪奜偵堏摦偝偣傑偡丅", OXEVENT_MAP_INDEX, true);
SendNoticeMap("듩댾궑궫뺴갲귩둖궸댷벍궠궧귏궥갃", OXEVENT_MAP_INDEX, true);
}
else
{
SendNoticeMap(LC_TEXT("5檬 第 撇府脚 盒甸阑 官冰栏肺 捞悼 矫虐摆嚼聪促."), OXEVENT_MAP_INDEX, true);
SendNoticeMap(LC_TEXT("5초 뒤 틀리신 분들을 바깥으로 이동 시키겠습니다."), OXEVENT_MAP_INDEX, true);
}
flag++;
@@ -230,7 +230,7 @@ EVENTFUNC(oxevent_timer)
case 2:
COXEventManager::instance().WarpToAudience();
COXEventManager::instance().SetStatus(OXEVENT_CLOSE);
SendNoticeMap(LC_TEXT("促澜 巩力 霖厚秦林技夸."), OXEVENT_MAP_INDEX, true);
SendNoticeMap(LC_TEXT("다음 문제 준비해주세요."), OXEVENT_MAP_INDEX, true);
flag = 0;
break;
}
@@ -247,9 +247,9 @@ bool COXEventManager::Quiz(unsigned char level, int timelimit)
int idx = number(0, m_vec_quiz[level].size()-1);
SendNoticeMap(LC_TEXT("巩力 涝聪促."), OXEVENT_MAP_INDEX, true);
SendNoticeMap(LC_TEXT("문제 입니다."), 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("맞으면 O, 틀리면 X로 이동해주세요"), OXEVENT_MAP_INDEX, true);
if (m_timedEvent != NULL) {
event_cancel(&m_timedEvent);
@@ -312,17 +312,17 @@ bool COXEventManager::CheckAnswer(bool answer)
}
else
{
pkChar->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("沥翠涝聪促!"));
pkChar->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("정답입니다!"));
// pkChar->CreateFly(number(FLY_FIREWORK1, FLY_FIREWORK6), pkChar);
char chatbuf[256];
int len = snprintf(chatbuf, sizeof(chatbuf),
"%s %u %u", number(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;

View File

@@ -1,4 +1,4 @@
#define OXEVENT_MAP_INDEX 113
struct tag_Quiz
@@ -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
};

View File

@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "utils.h"
#include "vector.h"
#include "char.h"
@@ -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(number(0, 359)); // 방향은 랜덤으로 설정
//m_pkChar->SetRotation(number(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 > number(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;

View File

@@ -1,10 +1,10 @@
#ifndef __HEADER_PET_SYSTEM__
#ifndef __HEADER_PET_SYSTEM__
#define __HEADER_PET_SYSTEM__
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;
};

Some files were not shown because too many files have changed in this diff Show More