1
0
forked from metin2/server
server/game/src/mining.cpp

449 lines
9.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "stdafx.h"
#include "mining.h"
#include "char.h"
#include "char_manager.h"
#include "item_manager.h"
#include "item.h"
#include "config.h"
#include "db.h"
#include "log.h"
#include "skill.h"
namespace mining
{
enum
{
MAX_ORE = 18,
MAX_FRACTION_COUNT = 9,
ORE_COUNT_FOR_REFINE = 100,
};
struct SInfo
{
DWORD dwLoadVnum;
DWORD dwRawOreVnum;
DWORD dwRefineVnum;
};
SInfo info[MAX_ORE] =
{
{ 20047, 50601, 50621 },
{ 20048, 50602, 50622 },
{ 20049, 50603, 50623 },
{ 20050, 50604, 50624 },
{ 20051, 50605, 50625 },
{ 20052, 50606, 50626 },
{ 20053, 50607, 50627 },
{ 20054, 50608, 50628 },
{ 20055, 50609, 50629 },
{ 20056, 50610, 50630 },
{ 20057, 50611, 50631 },
{ 20058, 50612, 50632 },
{ 20059, 50613, 50633 },
{ 30301, 50614, 50634 },
{ 30302, 50615, 50635 },
{ 30303, 50616, 50636 },
{ 30304, 50617, 50637 },
{ 30305, 50618, 50638 },
};
int fraction_info[MAX_FRACTION_COUNT][3] =
{
{ 20, 1, 10 },
{ 30, 11, 20 },
{ 20, 21, 30 },
{ 15, 31, 40 },
{ 5, 41, 50 },
{ 4, 51, 60 },
{ 3, 61, 70 },
{ 2, 71, 80 },
{ 1, 81, 90 },
};
int PickGradeAddPct[10] =
{
3, 5, 8, 11, 15, 20, 26, 32, 40, 50
};
int SkillLevelAddPct[SKILL_MAX_LEVEL + 1] =
{
0,
1, 1, 1, 1, // 1 - 4
2, 2, 2, 2, // 5 - 8
3, 3, 3, 3, // 9 - 12
4, 4, 4, 4, // 13 - 16
5, 5, 5, 5, // 17 - 20
6, 6, 6, 6, // 21 - 24
7, 7, 7, 7, // 25 - 28
8, 8, 8, 8, // 29 - 32
9, 9, 9, 9, // 33 - 36
10, 10, 10, // 37 - 39
11, // 40
};
DWORD GetRawOreFromLoad(DWORD dwLoadVnum)
{
for (int i = 0; i < MAX_ORE; ++i)
{
if (info[i].dwLoadVnum == dwLoadVnum)
return info[i].dwRawOreVnum;
}
return 0;
}
DWORD GetRefineFromRawOre(DWORD dwRawOreVnum)
{
for (int i = 0; i < MAX_ORE; ++i)
{
if (info[i].dwRawOreVnum == dwRawOreVnum)
return info[i].dwRefineVnum;
}
return 0;
}
int GetFractionCount()
{
int r = Random::get(1, 100);
for (int i = 0; i < MAX_FRACTION_COUNT; ++i)
{
if (r <= fraction_info[i][0])
return Random::get(fraction_info[i][1], fraction_info[i][2]);
else
r -= fraction_info[i][0];
}
return 0;
}
void OreDrop(LPCHARACTER ch, DWORD dwLoadVnum)
{
DWORD dwRawOreVnum = GetRawOreFromLoad(dwLoadVnum);
int iFractionCount = GetFractionCount();
if (iFractionCount == 0)
{
sys_err("Wrong ore fraction count");
return;
}
LPITEM item = ITEM_MANAGER::instance().CreateItem(dwRawOreVnum, GetFractionCount());
if (!item)
{
sys_err("cannot create item vnum %d", dwRawOreVnum);
return;
}
PIXEL_POSITION pos;
pos.x = ch->GetX() + Random::get(-200, 200);
pos.y = ch->GetY() + Random::get(-200, 200);
item->AddToGround(ch->GetMapIndex(), pos);
item->StartDestroyEvent();
item->SetOwnership(ch, 15);
DBManager::instance().SendMoneyLog(MONEY_LOG_DROP, item->GetVnum(), item->GetCount());
}
int GetOrePct(LPCHARACTER ch)
{
int defaultPct = 20;
int iSkillLevel = ch->GetSkillLevel(SKILL_MINING);
LPITEM pick = ch->GetWear(WEAR_WEAPON);
if (!pick || pick->GetType() != ITEM_PICK)
return 0;
return defaultPct + SkillLevelAddPct[std::clamp(iSkillLevel, 0, 40)] + PickGradeAddPct[std::clamp(pick->GetRefineLevel(), 0, 9)];
}
EVENTINFO(mining_event_info)
{
DWORD pid;
DWORD vid_load;
mining_event_info()
: pid( 0 )
, vid_load( 0 )
{
}
};
// REFINE_PICK
bool Pick_Check(CItem& item)
{
if (item.GetType() != ITEM_PICK)
return false;
return true;
}
int Pick_GetMaxExp(CItem& pick)
{
return pick.GetValue(2);
}
int Pick_GetCurExp(CItem& pick)
{
return pick.GetSocket(0);
}
void Pick_IncCurExp(CItem& pick)
{
int cur = Pick_GetCurExp(pick);
pick.SetSocket(0, cur + 1);
}
void Pick_MaxCurExp(CItem& pick)
{
int max = Pick_GetMaxExp(pick);
pick.SetSocket(0, max);
}
bool Pick_Refinable(CItem& item)
{
if (Pick_GetCurExp(item) < Pick_GetMaxExp(item))
return false;
return true;
}
bool Pick_IsPracticeSuccess(CItem& pick)
{
return (Random::get(1,pick.GetValue(1))==1);
}
bool Pick_IsRefineSuccess(CItem& pick)
{
return (Random::get(1,100) <= pick.GetValue(3));
}
int RealRefinePick(LPCHARACTER ch, LPITEM item)
{
if (!ch || !item)
return 2;
LogManager& rkLogMgr = LogManager::instance();
ITEM_MANAGER& rkItemMgr = ITEM_MANAGER::instance();
if (!Pick_Check(*item))
{
sys_err("REFINE_PICK_HACK pid(%u) item(%s:%d) type(%d)", ch->GetPlayerID(), item->GetName(), item->GetID(), item->GetType());
rkLogMgr.RefineLog(ch->GetPlayerID(), item->GetName(), item->GetID(), -1, 1, "PICK_HACK");
return 2;
}
CItem& rkOldPick = *item;
if (!Pick_Refinable(rkOldPick))
return 2;
int iAdv = rkOldPick.GetValue(0) / 10;
if (rkOldPick.IsEquipped() == true)
return 2;
if (Pick_IsRefineSuccess(rkOldPick))
{
rkLogMgr.RefineLog(ch->GetPlayerID(), rkOldPick.GetName(), rkOldPick.GetID(), iAdv, 1, "PICK");
LPITEM pkNewPick = ITEM_MANAGER::instance().CreateItem(rkOldPick.GetRefinedVnum(), 1);
if (pkNewPick)
{
BYTE bCell = rkOldPick.GetCell();
rkItemMgr.RemoveItem(item, "REMOVE (REFINE PICK)");
pkNewPick->AddToCharacter(ch, TItemPos(INVENTORY, bCell));
LogManager::instance().ItemLog(ch, pkNewPick, "REFINE PICK SUCCESS", pkNewPick->GetName());
return 1;
}
return 2;
}
else
{
rkLogMgr.RefineLog(ch->GetPlayerID(), rkOldPick.GetName(), rkOldPick.GetID(), iAdv, 0, "PICK");
LPITEM pkNewPick = ITEM_MANAGER::instance().CreateItem(rkOldPick.GetValue(4), 1);
if (pkNewPick)
{
BYTE bCell = rkOldPick.GetCell();
rkItemMgr.RemoveItem(item, "REMOVE (REFINE PICK)");
pkNewPick->AddToCharacter(ch, TItemPos(INVENTORY, bCell));
rkLogMgr.ItemLog(ch, pkNewPick, "REFINE PICK FAIL", pkNewPick->GetName());
return 0;
}
return 2;
}
}
void CHEAT_MAX_PICK(LPCHARACTER ch, LPITEM item)
{
if (!item)
return;
if (!Pick_Check(*item))
return;
CItem& pick = *item;
Pick_MaxCurExp(pick);
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>õ<EFBFBD><C3B5><EFBFBD> <20>ִ<EFBFBD>(%d)<29><> <20>Ǿ<EFBFBD><C7BE><EFBFBD><EFBFBD>ϴ<EFBFBD>."), Pick_GetCurExp(pick));
}
void PracticePick(LPCHARACTER ch, LPITEM item)
{
if (!item)
return;
if (!Pick_Check(*item))
return;
CItem& pick = *item;
if (pick.GetRefinedVnum()<=0)
return;
if (Pick_IsPracticeSuccess(pick))
{
if (Pick_Refinable(pick))
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD>̰<EFBFBD> <20>ִ<EFBFBD> <20><><EFBFBD>õ<EFBFBD><C3B5><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD><EFBFBD>ϴ<EFBFBD>."));
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>۸<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><EFBFBD>̷<EFBFBD> <20><><EFBFBD>׷<EFBFBD><D7B7>̵<EFBFBD> <20><> <20><> <20>ֽ<EFBFBD><D6BD>ϴ<EFBFBD>."));
}
else
{
Pick_IncCurExp(pick);
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>õ<EFBFBD><C3B5><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD><EFBFBD>ϴ<EFBFBD>! (%d/%d)"),
Pick_GetCurExp(pick), Pick_GetMaxExp(pick));
if (Pick_Refinable(pick))
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD>̰<EFBFBD> <20>ִ<EFBFBD> <20><><EFBFBD>õ<EFBFBD><C3B5><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD><EFBFBD>ϴ<EFBFBD>."));
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>۸<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><EFBFBD>̷<EFBFBD> <20><><EFBFBD>׷<EFBFBD><D7B7>̵<EFBFBD> <20><> <20><> <20>ֽ<EFBFBD><D6BD>ϴ<EFBFBD>."));
}
}
}
}
// END_OF_REFINE_PICK
EVENTFUNC(mining_event)
{
mining_event_info* info = dynamic_cast<mining_event_info*>( event->info );
if ( info == NULL )
{
sys_err( "mining_event_info> <Factor> Null pointer" );
return 0;
}
LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(info->pid);
LPCHARACTER load = CHARACTER_MANAGER::instance().Find(info->vid_load);
if (!ch)
return 0;
ch->mining_take();
LPITEM pick = ch->GetWear(WEAR_WEAPON);
// REFINE_PICK
if (!pick || !Pick_Check(*pick))
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD≯<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ʾƼ<CABE> Ķ <20><> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD>."));
return 0;
}
// END_OF_REFINE_PICK
if (!load)
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD><EFBFBD>̻<EFBFBD> ij<><C4B3> <20><> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD>."));
return 0;
}
int iPct = GetOrePct(ch);
if (Random::get(1, 100) <= iPct)
{
OreDrop(ch, load->GetRaceNum());
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("ä<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD><EFBFBD>ϴ<EFBFBD>."));
}
else
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("ä<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD><EFBFBD>ϴ<EFBFBD>."));
}
PracticePick(ch, pick);
return 0;
}
LPEVENT CreateMiningEvent(LPCHARACTER ch, LPCHARACTER load, int count)
{
mining_event_info* info = AllocEventInfo<mining_event_info>();
info->pid = ch->GetPlayerID();
info->vid_load = load->GetVID();
return event_create(mining_event, info, PASSES_PER_SEC(2 * count));
}
bool OreRefine(LPCHARACTER ch, LPCHARACTER npc, LPITEM item, int cost, int pct, LPITEM metinstone_item)
{
if (!ch || !npc)
return false;
if (item->GetOwner() != ch)
{
sys_err("wrong owner");
return false;
}
if (item->GetCount() < ORE_COUNT_FOR_REFINE)
{
sys_err("not enough count");
return false;
}
DWORD dwRefinedVnum = GetRefineFromRawOre(item->GetVnum());
if (dwRefinedVnum == 0)
return false;
ch->SetRefineNPC(npc);
item->SetCount(item->GetCount() - ORE_COUNT_FOR_REFINE);
int iCost = ch->ComputeRefineFee(cost, 1);
if (ch->GetGold() < iCost)
return false;
ch->PayRefineFee(iCost);
if (metinstone_item)
ITEM_MANAGER::instance().RemoveItem(metinstone_item, "REMOVE (MELT)");
if (Random::get(1, 100) <= pct)
{
ch->AutoGiveItem(dwRefinedVnum, 1);
return true;
}
return false;
}
bool IsVeinOfOre (DWORD vnum)
{
for (int i = 0; i < MAX_ORE; i++)
{
if (info[i].dwLoadVnum == vnum)
return true;
}
return false;
}
}