474 lines
15 KiB
C++
474 lines
15 KiB
C++
#include "stdafx.h"
|
|
|
|
#include "PacketStruct_AW.h"
|
|
#include "PacketStruct_DW.h"
|
|
|
|
#include "../Lotto.h"
|
|
|
|
#include "ActiveState.h"
|
|
|
|
// implemented by __NA_001359_20090619_HEIM_LOTTO_SYSTEM
|
|
|
|
void LottoActiveState::OnEnter()
|
|
{
|
|
SUNLOG(eFULL_LOG, "[Lotto] Entering ACTIVE_STATE");
|
|
|
|
totalAccum_ = 0;
|
|
|
|
accumNotiTimer_.SetTimer(10 * 1000); // 10초
|
|
accumNotiTimer_.EnableCheckTime();
|
|
|
|
// 다음 추첨 일정 얻기
|
|
lotto_.config_.ScheduleNextDraw(schedule_);
|
|
if (schedule_.IsValid()) {
|
|
tickTimer_.SetTimer(0); // 최초 1회는 강제로 Expired 상태로
|
|
tickTimer_.EnableCheckTime();
|
|
reminderIndex_ = 0;
|
|
}
|
|
else {
|
|
SUNLOG(eCRITICAL_LOG, "[Lotto] ERROR scheduling the next draw");
|
|
}
|
|
|
|
#ifdef _NA_20101011_HEIM_LOTTO_CASH_TICKET
|
|
// 시작시 관련 트랜잭션 정보 초기화
|
|
lotto_.GetTicketActivationXactions().Clear();
|
|
#endif
|
|
|
|
// 하임 로또 시작 공지
|
|
int currentDrawNum = lotto_.GetCurrentDrawNum();
|
|
if (currentDrawNum != 0) {
|
|
BroadcastLottoStart(currentDrawNum);
|
|
}
|
|
|
|
// 시작 적립액 공지
|
|
BroadcastTotalAccum(lotto_.GetCurrentTotalAccum(), false);
|
|
}
|
|
|
|
void LottoActiveState::OnExit()
|
|
{
|
|
SUNLOG(eFULL_LOG, "[Lotto] Exiting ACTIVE_STATE");
|
|
|
|
// 현 회차 최종 적립액 공지
|
|
BroadcastTotalAccum(lotto_.GetCurrentTotalAccum());
|
|
|
|
if (schedule_.IsValid()) {
|
|
tickTimer_.DisableCheckTime();
|
|
}
|
|
|
|
accumNotiTimer_.DisableCheckTime();
|
|
}
|
|
|
|
void LottoActiveState::OnTick()
|
|
{
|
|
if (schedule_.IsValid()) {
|
|
if (tickTimer_.IsExpired())
|
|
{
|
|
SYSTEMTIME st;
|
|
util::TimeSync::GetLocalTime(&st);
|
|
|
|
// 다음 추첨 일정까지 남은 시간(초)을 계산한다
|
|
int remainingSeconds = schedule_.SecondsTo(&st);
|
|
|
|
DWORD timerInterval = tickTimer_.GetBaseIntervalTime();
|
|
if (timerInterval == 0 || timerInterval > 1000) {
|
|
SUNLOG(eFULL_LOG, "[Lotto] Next draw on %s : %d seconds left", \
|
|
schedule_.ToString(), remainingSeconds);
|
|
}
|
|
|
|
// 다음 추첨까지 아직 시간이 남아 있으면
|
|
if (remainingSeconds > 0)
|
|
{
|
|
const ReminderList& reminders = lotto_.config_.GetReminders();
|
|
// 다음 카운트다운 공지 기준 시간(초)보다 적게 남았으면 카운트다운 공지
|
|
if ( reminderIndex_ < reminders.size() && remainingSeconds <= reminders[reminderIndex_] )
|
|
{
|
|
// 10% 이상 늦은 공지는 보내지 않는다
|
|
if ( remainingSeconds > (reminders[reminderIndex_] - (int)(reminders[reminderIndex_] * 0.1f)) )
|
|
{
|
|
SUNLOG(eFULL_LOG, "[Lotto] Countdown #%d : %d second(s) remaining", \
|
|
(reminderIndex_ + 1), reminders[reminderIndex_]);
|
|
|
|
BroadcastCountdown(reminders[reminderIndex_]);
|
|
}
|
|
else {
|
|
SUNLOG(eFULL_LOG, "[Lotto] Skipping obsolete countdown #%d : %d second(s)", \
|
|
(reminderIndex_ + 1), reminders[reminderIndex_]);
|
|
}
|
|
++reminderIndex_;
|
|
}
|
|
}
|
|
// 추첨 시간이 되었으면
|
|
else {
|
|
SUNLOG(eFULL_LOG, "[Lotto] Starting scheduled draw");
|
|
|
|
lotto_.TransitState(Lotto::DRAWING_STATE);
|
|
}
|
|
|
|
// 추첨 시간 체크 타이머 리셋
|
|
if (timerInterval > 1000) {
|
|
tickTimer_.Reset();
|
|
}
|
|
else if (timerInterval > 0) {
|
|
if (st.wSecond > 0) {
|
|
tickTimer_.Reset();
|
|
}
|
|
else {
|
|
tickTimer_.SetTimer(60 * 1000); // 체크 주기를 1분으로
|
|
}
|
|
}
|
|
else {
|
|
tickTimer_.SetTimer(1000); // 처음엔 1초 간격으로
|
|
}
|
|
}
|
|
}
|
|
|
|
if (accumNotiTimer_.IsExpired())
|
|
{
|
|
INT64 totalAccum = lotto_.GetCurrentTotalAccum();
|
|
|
|
// 총 적립액에 변동이 있으면
|
|
if (totalAccum != totalAccum_)
|
|
{
|
|
BroadcastTotalAccum(totalAccum);
|
|
|
|
totalAccum_ = totalAccum; // 변경 감지를 위해 최종 값 기억
|
|
}
|
|
|
|
// 적립액 공지 타이머 리셋
|
|
accumNotiTimer_.Reset();
|
|
}
|
|
}
|
|
|
|
void LottoActiveState::OnInfoRequest(CHARGUID charGuid, MSG_BASE* packet)
|
|
{
|
|
MSG_CW_LOTTO_INFO_SYN* pRecvMsg = static_cast<MSG_CW_LOTTO_INFO_SYN*>(packet);
|
|
|
|
LottoEntry* entry = lotto_.FindEntry(charGuid);
|
|
if (entry == NULL) {
|
|
SUNLOG(eMIDDLE_LOG, "[Lotto] WARNING : Entry not found for character [%d]", charGuid);
|
|
RequestEntryLoad(charGuid, pRecvMsg->bFlag);
|
|
return;
|
|
}
|
|
SendInfoResponse(charGuid, pRecvMsg->bFlag);
|
|
}
|
|
|
|
void LottoActiveState::OnEntryRequest(CHARGUID charGuid, MSG_BASE* packet)
|
|
{
|
|
MSG_CW_LOTTO_ENTRY_SYN* pRecvMsg = static_cast<MSG_CW_LOTTO_ENTRY_SYN*>(packet);
|
|
|
|
int drawNum = pRecvMsg->wDrawNum;
|
|
bool isAuto = (pRecvMsg->bAuto != 0);
|
|
BYTE* pickedNum = pRecvMsg->bPickedNum;
|
|
|
|
lotto_.Sort(pickedNum); // 응모 번호 정렬
|
|
|
|
int errorCode = MSG_CW_LOTTO_ENTRY_NAK::UNKNOWN;
|
|
bool result = true;
|
|
if (!isAuto) {
|
|
result = Lotto::AreValidPicks(pickedNum); // 응모 번호 범위 및 중복 검사
|
|
}
|
|
|
|
#ifndef _NA_0_20100115_HEIM_LOTTO_TICKET_PURCHASE
|
|
// 복권용지 직접 구입 기능을 사용하지 않을 때는 여기서 바로 응모 처리
|
|
int status;
|
|
if (result) {
|
|
result = lotto_.ProcessTicket(charGuid, drawNum, isAuto, pickedNum, &status, &errorCode);
|
|
if (result) {
|
|
RequestEntrySave(charGuid, pRecvMsg->bAuto, (BYTE)status, pickedNum);
|
|
}
|
|
}
|
|
#else
|
|
// 복권용지 직접 구입 기능을 사용할 때는
|
|
// 응모 제한 횟수 점검
|
|
LottoEntry* entry = lotto_.FindEntry(charGuid);
|
|
if (entry != NULL)
|
|
{
|
|
if (entry->numUsedTickets >= LottoConfig::MAX_TICKETS)
|
|
{
|
|
errorCode = MSG_CW_LOTTO_ENTRY_NAK::OUT_OF_TICKET;
|
|
result = false;
|
|
}
|
|
}
|
|
// 잔액 차감을 위해 게임 서버로 전달
|
|
if (result)
|
|
{
|
|
MSG_AW_USER_LOTTO_TICKET_PURCHASE_SYN syn;
|
|
syn.iCharGuid = charGuid;
|
|
syn.wDrawNum = (WORD)drawNum;
|
|
syn.bAuto = (isAuto ? 1 : 0);
|
|
for (int i = 0; i < LOTTO_NUM_PICKS; ++i) {
|
|
syn.bPickedNum[i] = pickedNum[i];
|
|
}
|
|
syn.i64TicketPrice = lotto_.config_.GetTicketPrice();
|
|
result = SendToAgentServer(charGuid, (BYTE*)&syn, (WORD)sizeof(syn));
|
|
}
|
|
#endif // _NA_0_20100115_HEIM_LOTTO_TICKET_PURCHASE
|
|
|
|
if (!result)
|
|
{
|
|
MSG_CW_LOTTO_ENTRY_NAK nak;
|
|
nak.iCharGuid = charGuid;
|
|
nak.bReason = (BYTE)errorCode;
|
|
SendToClient(charGuid, (BYTE*)&nak, (WORD)sizeof(nak));
|
|
}
|
|
}
|
|
|
|
#ifdef _NA_0_20100115_HEIM_LOTTO_TICKET_PURCHASE
|
|
void LottoActiveState::OnTicketPurchase(MSG_BASE* packet)
|
|
{
|
|
MSG_AW_USER_LOTTO_TICKET_PURCHASE_ACK* pRecvMsg = \
|
|
static_cast<MSG_AW_USER_LOTTO_TICKET_PURCHASE_ACK*>(packet);
|
|
|
|
int result_code = pRecvMsg->iResult;
|
|
CHARGUID charGuid = pRecvMsg->iCharGuid;
|
|
int drawNum = pRecvMsg->wDrawNum;
|
|
bool isAuto = (pRecvMsg->bAuto != 0);
|
|
BYTE* pickedNum = pRecvMsg->bPickedNum;
|
|
|
|
int error_code = MSG_CW_LOTTO_ENTRY_NAK::UNKNOWN;
|
|
bool result = false;
|
|
|
|
if (result_code == MSG_AW_USER_LOTTO_TICKET_PURCHASE_ACK::RESULT_OK)
|
|
{
|
|
LottoEntry* entry = lotto_.FindEntry(charGuid);
|
|
if (entry != NULL)
|
|
{
|
|
// 응모 정보 임시 저장
|
|
entry->temp.drawNum = drawNum;
|
|
entry->temp.status = (isAuto ? 1 : 0);
|
|
entry->temp.pickedNum1 = pickedNum[0];
|
|
entry->temp.pickedNum2 = pickedNum[1];
|
|
entry->temp.pickedNum3 = pickedNum[2];
|
|
entry->temp.pickedNum4 = pickedNum[3];
|
|
// 복권용지 획득
|
|
RequestTicketAdd(charGuid, 1);
|
|
result = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (result_code)
|
|
{
|
|
case MSG_AW_USER_LOTTO_TICKET_PURCHASE_ACK::ERROR_NOT_ENOUGH_MONEY:
|
|
error_code = MSG_CW_LOTTO_ENTRY_NAK::NOT_ENOUGH_MONEY;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!result)
|
|
{
|
|
MSG_CW_LOTTO_ENTRY_NAK nak;
|
|
nak.iCharGuid = charGuid;
|
|
nak.bReason = (BYTE)error_code;
|
|
SendToClient(charGuid, (BYTE*)&nak, (WORD)sizeof(nak));
|
|
}
|
|
}
|
|
#endif // _NA_0_20100115_HEIM_LOTTO_TICKET_PURCHASE
|
|
|
|
#ifdef _NA_20101011_HEIM_LOTTO_CASH_TICKET
|
|
// 캐시 아이템을 사용해 로또 응모 용지 활성화
|
|
void LottoActiveState::OnTicketActivation(MSG_BASE* packet)
|
|
{
|
|
MSG_AW_ITEM_USE_HEIM_LOTTO_TICKET_SYN* msg = \
|
|
static_cast<MSG_AW_ITEM_USE_HEIM_LOTTO_TICKET_SYN*>(packet);
|
|
|
|
LottoEntry* entry = lotto_.FindEntry(msg->char_guid);
|
|
if (entry == NULL)
|
|
{
|
|
MSG_AW_ITEM_USE_HEIM_LOTTO_TICKET_ACK ack;
|
|
ack.result_code = static_cast<WORD>(RC::RC_ITEM_HEIM_LOTTO_UNAVAILABLE);
|
|
ack.char_guid = msg->char_guid;
|
|
ack.index = msg->index;
|
|
ack.pos = msg->pos;
|
|
SendToAgentServer(msg->char_guid, (BYTE*)&ack, (WORD)sizeof(ack));
|
|
return;
|
|
}
|
|
|
|
// 당 회차에 사용한 용지 수와 사용 가능한 용지 수의 합이 최대값에 도달했으면 실패
|
|
int num_total_tickets = entry->numRemainingTickets + entry->numUsedTickets;
|
|
if (num_total_tickets >= LottoConfig::MAX_TICKETS)
|
|
{
|
|
MSG_AW_ITEM_USE_HEIM_LOTTO_TICKET_ACK ack;
|
|
ack.result_code = static_cast<WORD>(RC::RC_ITEM_HEIM_LOTTO_TICKET_MAX_REACHED);
|
|
ack.char_guid = msg->char_guid;
|
|
ack.index = msg->index;
|
|
ack.pos = msg->pos;
|
|
SendToAgentServer(msg->char_guid, (BYTE*)&ack, (WORD)sizeof(ack));
|
|
return;
|
|
}
|
|
|
|
// 트랜잭션 정보 설정
|
|
TicketActivationXactions& xactions = lotto_.GetTicketActivationXactions();
|
|
xactions.Add(msg->char_guid, msg->index, msg->pos);
|
|
|
|
RequestTicketAdd(msg->char_guid, entry->numRemainingTickets + 1);
|
|
}
|
|
#endif // _NA_20101011_HEIM_LOTTO_CASH_TICKET
|
|
|
|
void LottoActiveState::OnEntrySave(MSG_BASE* packet)
|
|
{
|
|
MSG_DW_LOTTO_SAVE_ENTRY_ACK* pRecvMsg = \
|
|
static_cast<MSG_DW_LOTTO_SAVE_ENTRY_ACK*>(packet);
|
|
|
|
CHARGUID charGuid = pRecvMsg->iCharGuid;
|
|
int drawNum = pRecvMsg->wDrawNum;
|
|
int status = pRecvMsg->bStatus;
|
|
BYTE* pickedNum = pRecvMsg->bPickedNum;
|
|
|
|
if (pRecvMsg->iResult != 0) {
|
|
SUNLOG(eCRITICAL_LOG, "[Lotto] ERROR : Failed to save an entry of character [%d]", charGuid);
|
|
MSG_CW_LOTTO_ENTRY_NAK nak;
|
|
nak.iCharGuid = charGuid;
|
|
nak.bReason = (BYTE)MSG_CW_LOTTO_ENTRY_NAK::UNKNOWN;
|
|
SendToClient(charGuid, (BYTE*)&nak, (WORD)sizeof(MSG_CW_LOTTO_ENTRY_NAK));
|
|
return;
|
|
}
|
|
|
|
lotto_.EnterTicket(charGuid, drawNum, status, pickedNum);
|
|
LottoEntry* entry = lotto_.FindEntry(charGuid);
|
|
if (entry == NULL) {
|
|
SUNLOG(eMIDDLE_LOG, "[Lotto] WARNING : Entry not found for character [%d]", charGuid);
|
|
return;
|
|
}
|
|
|
|
MSG_CW_LOTTO_ENTRY_ACK ack;
|
|
ack.iCharGuid = charGuid;
|
|
ack.wDrawNum = (WORD)drawNum;
|
|
ack.bNumTickets = (BYTE)entry->numRemainingTickets;
|
|
ack.bAuto = pRecvMsg->bIsAuto;
|
|
for (int i = 0; i < LottoConfig::NUM_PICKS; ++i) {
|
|
ack.bPickedNum[i] = pickedNum[i];
|
|
}
|
|
#ifdef _NA_0_20100115_HEIM_LOTTO_TICKET_PURCHASE
|
|
ack.i64TicketPrice = lotto_.config_.GetTicketPrice();
|
|
#endif
|
|
SendToClient(charGuid, (BYTE*)&ack, (WORD)sizeof(ack));
|
|
}
|
|
|
|
void LottoActiveState::OnTicketAcquisition(MSG_BASE* packet)
|
|
{
|
|
MSG_DW_LOTTO_ADD_TICKET_ACK* pRecvMsg = \
|
|
static_cast<MSG_DW_LOTTO_ADD_TICKET_ACK*>(packet);
|
|
|
|
CHARGUID charGuid = pRecvMsg->iCharGuid;
|
|
|
|
if (pRecvMsg->iResult != 0) {
|
|
SUNLOG(eCRITICAL_LOG, "[Lotto] ERROR : Failed to give ticket(s) to character [%d]", charGuid);
|
|
return;
|
|
}
|
|
|
|
LottoEntry* entry = lotto_.FindEntry(charGuid);
|
|
if (entry == NULL) {
|
|
SUNLOG(eCRITICAL_LOG, "[Lotto] ERROR : Entry not found for character [%d]", charGuid);
|
|
return;
|
|
}
|
|
|
|
int numRemainingTickets = pRecvMsg->bNumRemainingTickets;
|
|
// DB 처리가 완료되면 캐릭터의 증가된 복권 용지 개수를 저장하고
|
|
entry->numRemainingTickets = (WORD)numRemainingTickets;
|
|
|
|
#ifndef _NA_0_20100115_HEIM_LOTTO_TICKET_PURCHASE
|
|
// 클라이언트로 알려준다
|
|
NotifyTicketAcquisition(charGuid, numRemainingTickets);
|
|
#ifdef _NA_20101011_HEIM_LOTTO_CASH_TICKET
|
|
// Agent 서버로 캐시 아이템 사용에 대한 응답 전송
|
|
TicketActivationXactions& xactions = lotto_.GetTicketActivationXactions();
|
|
const TicketActivationXactionInfo* xaction_info = xactions.Find(charGuid);
|
|
MSG_AW_ITEM_USE_HEIM_LOTTO_TICKET_ACK ack;
|
|
if (xaction_info != NULL)
|
|
{
|
|
ack.result_code = RC::RC_ITEM_SUCCESS;
|
|
ack.index = xaction_info->index;
|
|
ack.pos = xaction_info->pos;
|
|
}
|
|
else
|
|
{
|
|
ack.result_code = RC::RC_ITEM_INVALIDSTATEOFPLAYER;
|
|
}
|
|
ack.char_guid = charGuid;
|
|
SendToAgentServer(charGuid, (BYTE*)&ack, (WORD)sizeof(ack));
|
|
// 트랜잭션 정보 제거
|
|
xactions.Remove(charGuid);
|
|
#endif // _NA_20101011_HEIM_LOTTO_CASH_TICKET
|
|
#else
|
|
// 임시 저장된 응모 정보 가져오기
|
|
int draw_num = entry->temp.drawNum;
|
|
bool is_auto = (entry->temp.status != 0);
|
|
BYTE picked_num[4];
|
|
picked_num[0] = entry->temp.pickedNum1;
|
|
picked_num[1] = entry->temp.pickedNum2;
|
|
picked_num[2] = entry->temp.pickedNum3;
|
|
picked_num[3] = entry->temp.pickedNum4;
|
|
|
|
// 응모 처리
|
|
int status, error_code;
|
|
bool result = lotto_.ProcessTicket(charGuid, draw_num, is_auto, picked_num, &status, &error_code);
|
|
if (result) {
|
|
RequestEntrySave(charGuid, (is_auto ? 1 : 0), (BYTE)status, picked_num);
|
|
}
|
|
if (!result)
|
|
{
|
|
MSG_CW_LOTTO_ENTRY_NAK nak;
|
|
nak.iCharGuid = charGuid;
|
|
nak.bReason = (BYTE)error_code;
|
|
SendToClient(charGuid, (BYTE*)&nak, (WORD)sizeof(nak));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void LottoActiveState::OnHeimConsumption(MSG_BASE* packet)
|
|
{
|
|
MSG_AW_USER_STATUS_HEIM_CONSUMPTION_NTF* pRecvMsg = \
|
|
static_cast<MSG_AW_USER_STATUS_HEIM_CONSUMPTION_NTF*>(packet);
|
|
|
|
CHARGUID charGuid = pRecvMsg->m_CharGuid;
|
|
eHEIM_CONSUMPTION_TYPE type = (eHEIM_CONSUMPTION_TYPE)pRecvMsg->m_byConsumptionType;
|
|
INT64 amount = (INT64)pRecvMsg->m_Amount;
|
|
int percentage = -1;
|
|
//_NA_0_20091119_HEIM_LOTTO_ACCUM_CTRL_BY_SHOP
|
|
percentage = pRecvMsg->m_LottoAccumRatio;
|
|
|
|
int numRemainingTickets = \
|
|
lotto_.OnHeimConsumption(charGuid, type, amount, percentage);
|
|
|
|
if (numRemainingTickets >= 0) {
|
|
RequestTicketAdd(charGuid, numRemainingTickets);
|
|
}
|
|
}
|
|
|
|
void LottoActiveState::OnTotalAccumChange(INT64 delta)
|
|
{
|
|
INT64 totalAccum = lotto_.AddCurrentTotalAccum(delta);
|
|
|
|
// 총 적립액에 변동이 있으면
|
|
if (totalAccum != totalAccum_)
|
|
{
|
|
BroadcastTotalAccum(totalAccum);
|
|
|
|
totalAccum_ = totalAccum; // 변경 감지를 위해 최종 값 기억
|
|
}
|
|
|
|
// 적립액 공지 타이머 리셋
|
|
accumNotiTimer_.Reset();
|
|
}
|
|
|
|
void LottoActiveState::BroadcastTotalAccum(INT64 totalAccum, bool dbWrite)
|
|
{
|
|
SUNLOG(eFULL_LOG, "[Lotto] Notifying Total Accumulation Update : Draw # = %d, Total = %I64d",
|
|
lotto_.GetCurrentDrawNum(), totalAccum);
|
|
|
|
if (dbWrite) {
|
|
// DB 총 적립액 업데이트 요청
|
|
RequestAccumulate((WORD)lotto_.GetCurrentDrawNum(), totalAccum);
|
|
}
|
|
|
|
// 클라이언트들에게 통지
|
|
MSG_CW_LOTTO_ACCUM_BRD sendMsg;
|
|
sendMsg.wDrawNum = (WORD)lotto_.GetCurrentDrawNum();
|
|
sendMsg.i64TotalAccum = totalAccum;
|
|
BroadcastToClients((BYTE*)&sendMsg, (WORD)sizeof(MSG_CW_LOTTO_ACCUM_BRD));
|
|
}
|
|
|