issue-9: add classic sash gameplay support
This commit is contained in:
@@ -113,6 +113,7 @@ enum ECostumeSubTypes
|
||||
{
|
||||
COSTUME_BODY = ARMOR_BODY, // [중요!!] ECostumeSubTypes enum value는 종류별로 EArmorSubTypes의 그것과 같아야 함.
|
||||
COSTUME_HAIR = ARMOR_HEAD, // 이는 코스츔 아이템에 추가 속성을 붙이겠다는 사업부의 요청에 따라서 기존 로직을 활용하기 위함임.
|
||||
COSTUME_SASH = ARMOR_NUM_TYPES,
|
||||
COSTUME_NUM_TYPES,
|
||||
};
|
||||
|
||||
@@ -325,6 +326,7 @@ enum EItemWearableFlag
|
||||
WEARABLE_COSTUME_BODY = (1 << 12),
|
||||
WEARABLE_COSTUME_HAIR = (1 << 13),
|
||||
WEARABLE_BELT = (1 << 14),
|
||||
WEARABLE_COSTUME_SASH = (1 << 15),
|
||||
};
|
||||
|
||||
enum ELimitTypes
|
||||
|
||||
@@ -123,6 +123,7 @@ enum EWearPositions
|
||||
WEAR_RING2, // 22 : 신규 반지슬롯2 (오른쪽)
|
||||
|
||||
WEAR_BELT, // 23 : 신규 벨트슬롯
|
||||
WEAR_COSTUME_SASH, // 24
|
||||
|
||||
WEAR_MAX = 32 //
|
||||
};
|
||||
@@ -233,6 +234,7 @@ enum EParts
|
||||
PART_WEAPON,
|
||||
PART_HEAD,
|
||||
PART_HAIR,
|
||||
PART_ACCE,
|
||||
|
||||
PART_MAX_NUM,
|
||||
PART_WEAPON_SUB,
|
||||
|
||||
@@ -122,7 +122,7 @@ int get_Item_SubType_Value(int type_value, string inputString)
|
||||
"RESOURCE_STONE", "RESOURCE_METIN", "RESOURCE_ORE" };
|
||||
static string arSub16[] = { "UNIQUE_NONE", "UNIQUE_BOOK", "UNIQUE_SPECIAL_RIDE", "UNIQUE_3", "UNIQUE_4", "UNIQUE_5",
|
||||
"UNIQUE_6", "UNIQUE_7", "UNIQUE_8", "UNIQUE_9", "USE_SPECIAL"};
|
||||
static string arSub28[] = { "COSTUME_BODY", "COSTUME_HAIR" };
|
||||
static string arSub28[] = { "COSTUME_BODY", "COSTUME_HAIR", "COSTUME_SASH" };
|
||||
static string arSub29[] = { "DS_SLOT1", "DS_SLOT2", "DS_SLOT3", "DS_SLOT4", "DS_SLOT5", "DS_SLOT6" };
|
||||
static string arSub31[] = { "EXTRACT_DRAGON_SOUL", "EXTRACT_DRAGON_HEART" };
|
||||
|
||||
|
||||
@@ -973,6 +973,7 @@ void CHARACTER::EncodeInsertPacket(LPENTITY entity)
|
||||
addPacket.awPart[CHR_EQUIPPART_WEAPON] = GetPart(PART_WEAPON);
|
||||
addPacket.awPart[CHR_EQUIPPART_HEAD] = GetPart(PART_HEAD);
|
||||
addPacket.awPart[CHR_EQUIPPART_HAIR] = GetPart(PART_HAIR);
|
||||
addPacket.awPart[CHR_EQUIPPART_ACCE] = GetPart(PART_ACCE);
|
||||
|
||||
addPacket.bPKMode = m_bPKMode;
|
||||
addPacket.dwMountVnum = GetMountVnum();
|
||||
@@ -1110,6 +1111,7 @@ void CHARACTER::UpdatePacket()
|
||||
pack.awPart[CHR_EQUIPPART_WEAPON] = GetPart(PART_WEAPON);
|
||||
pack.awPart[CHR_EQUIPPART_HEAD] = GetPart(PART_HEAD);
|
||||
pack.awPart[CHR_EQUIPPART_HAIR] = GetPart(PART_HAIR);
|
||||
pack.awPart[CHR_EQUIPPART_ACCE] = GetPart(PART_ACCE);
|
||||
|
||||
pack.bMovingSpeed = GetLimitPoint(POINT_MOV_SPEED);
|
||||
pack.bAttackSpeed = GetLimitPoint(POINT_ATT_SPEED);
|
||||
@@ -1808,6 +1810,7 @@ void CHARACTER::SetPlayerProto(const TPlayerTable * t)
|
||||
|
||||
m_pointsInstant.bBasePart = t->part_base;
|
||||
SetPart(PART_HAIR, t->parts[PART_HAIR]);
|
||||
SetPart(PART_ACCE, t->parts[PART_ACCE]);
|
||||
|
||||
m_points.iRandomHP = t->sRandomHP;
|
||||
m_points.iRandomSP = t->sRandomSP;
|
||||
@@ -2310,6 +2313,7 @@ void CHARACTER::ComputePoints()
|
||||
SetPart(PART_WEAPON, GetOriginalPart(PART_WEAPON));
|
||||
SetPart(PART_HEAD, GetOriginalPart(PART_HEAD));
|
||||
SetPart(PART_HAIR, GetOriginalPart(PART_HAIR));
|
||||
SetPart(PART_ACCE, GetOriginalPart(PART_ACCE));
|
||||
|
||||
SetPoint(POINT_PARTY_ATTACKER_BONUS, lAttackerBonus);
|
||||
SetPoint(POINT_PARTY_TANKER_BONUS, lTankerBonus);
|
||||
@@ -4467,6 +4471,9 @@ WORD CHARACTER::GetOriginalPart(BYTE bPartPos) const
|
||||
case PART_HAIR:
|
||||
return GetPart(PART_HAIR);
|
||||
|
||||
case PART_ACCE:
|
||||
return GetPart(PART_ACCE);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6706,7 +6706,7 @@ void CHARACTER::BuffOnAttr_ValueChange(BYTE bType, BYTE bOldValue, BYTE bNewValu
|
||||
break;
|
||||
case POINT_COSTUME_ATTR_BONUS:
|
||||
{
|
||||
static BYTE abSlot[] = { WEAR_COSTUME_BODY, WEAR_COSTUME_HAIR };
|
||||
static BYTE abSlot[] = { WEAR_COSTUME_BODY, WEAR_COSTUME_HAIR, WEAR_COSTUME_SASH };
|
||||
static std::vector <BYTE> vec_slots (abSlot, abSlot + _countof(abSlot));
|
||||
pBuff = M2_NEW CBuffOnAttributes(this, bType, &vec_slots);
|
||||
}
|
||||
|
||||
@@ -212,6 +212,7 @@ ACMD(do_teleport_system);
|
||||
ACMD(do_autopickup);
|
||||
ACMD(do_stone_queue);
|
||||
ACMD(do_switchbot);
|
||||
ACMD(do_sash);
|
||||
|
||||
ACMD(do_click_mall);
|
||||
|
||||
@@ -473,6 +474,7 @@ struct command_info cmd_info[] =
|
||||
{ "autopickup", do_autopickup, 0, POS_DEAD, GM_PLAYER },
|
||||
{ "stone_queue", do_stone_queue, 0, POS_DEAD, GM_PLAYER },
|
||||
{ "switchbot", do_switchbot, 0, POS_DEAD, GM_PLAYER },
|
||||
{ "sash", do_sash, 0, POS_DEAD, GM_PLAYER },
|
||||
{ "siege", do_siege, 0, POS_DEAD, GM_LOW_WIZARD },
|
||||
{ "temp", do_temp, 0, POS_DEAD, GM_IMPLEMENTOR },
|
||||
{ "frog", do_frog, 0, POS_DEAD, GM_HIGH_WIZARD },
|
||||
|
||||
@@ -2124,6 +2124,161 @@ ACMD(do_switchbot)
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Unable to start switchbot slot."));
|
||||
}
|
||||
|
||||
static bool FN_is_sash_item(LPITEM item)
|
||||
{
|
||||
return item && item->GetType() == ITEM_COSTUME && item->GetSubType() == COSTUME_SASH;
|
||||
}
|
||||
|
||||
static bool FN_is_sash_absorb_source(LPITEM item)
|
||||
{
|
||||
if (!item)
|
||||
return false;
|
||||
|
||||
if (item->GetType() == ITEM_WEAPON)
|
||||
return item->GetSubType() != WEAPON_ARROW;
|
||||
|
||||
if (item->GetType() != ITEM_ARMOR)
|
||||
return false;
|
||||
|
||||
switch (item->GetSubType())
|
||||
{
|
||||
case ARMOR_BODY:
|
||||
case ARMOR_HEAD:
|
||||
case ARMOR_SHIELD:
|
||||
case ARMOR_WRIST:
|
||||
case ARMOR_FOOTS:
|
||||
case ARMOR_NECK:
|
||||
case ARMOR_EAR:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void FN_set_sash_attrs_from_source(LPITEM sash, LPITEM source, int absorbPct)
|
||||
{
|
||||
struct SAttrEntry
|
||||
{
|
||||
BYTE type;
|
||||
short value;
|
||||
};
|
||||
|
||||
std::vector<SAttrEntry> attrs;
|
||||
const TItemTable* proto = source->GetProto();
|
||||
if (!proto)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < ITEM_APPLY_MAX_NUM; ++i)
|
||||
{
|
||||
const TItemApply& apply = proto->aApplies[i];
|
||||
if (apply.bType == APPLY_NONE || apply.lValue == 0)
|
||||
continue;
|
||||
|
||||
long scaled = (apply.lValue * absorbPct) / 100;
|
||||
if (scaled == 0)
|
||||
scaled = (apply.lValue > 0) ? 1 : -1;
|
||||
|
||||
attrs.push_back({ apply.bType, static_cast<short>(scaled) });
|
||||
if (attrs.size() >= ITEM_ATTRIBUTE_MAX_NUM)
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < source->GetAttributeCount() && attrs.size() < ITEM_ATTRIBUTE_MAX_NUM; ++i)
|
||||
{
|
||||
const TPlayerItemAttribute& attr = source->GetAttribute(i);
|
||||
if (!attr.bType || !attr.sValue)
|
||||
continue;
|
||||
|
||||
bool duplicated = false;
|
||||
for (size_t j = 0; j < attrs.size(); ++j)
|
||||
{
|
||||
if (attrs[j].type == attr.bType)
|
||||
{
|
||||
duplicated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (duplicated)
|
||||
continue;
|
||||
|
||||
long scaled = (attr.sValue * absorbPct) / 100;
|
||||
if (scaled == 0)
|
||||
scaled = (attr.sValue > 0) ? 1 : -1;
|
||||
|
||||
attrs.push_back({ attr.bType, static_cast<short>(scaled) });
|
||||
}
|
||||
|
||||
sash->ClearAttribute();
|
||||
for (size_t i = 0; i < attrs.size(); ++i)
|
||||
sash->SetForceAttribute(static_cast<int>(i), attrs[i].type, attrs[i].value);
|
||||
}
|
||||
|
||||
ACMD(do_sash)
|
||||
{
|
||||
char action[256];
|
||||
argument = one_argument(argument, action, sizeof(action));
|
||||
|
||||
if (strcmp(action, "absorb"))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Usage: /sash absorb <sash_slot> <item_slot>"));
|
||||
return;
|
||||
}
|
||||
|
||||
char sashArg[256];
|
||||
char sourceArg[256];
|
||||
argument = one_argument(argument, sashArg, sizeof(sashArg));
|
||||
argument = one_argument(argument, sourceArg, sizeof(sourceArg));
|
||||
|
||||
int sashCell = -1;
|
||||
int sourceCell = -1;
|
||||
str_to_number(sashCell, sashArg);
|
||||
str_to_number(sourceCell, sourceArg);
|
||||
|
||||
if (sashCell < 0 || sashCell >= INVENTORY_MAX_NUM || sourceCell < 0 || sourceCell >= INVENTORY_MAX_NUM || sashCell == sourceCell)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Invalid sash slots."));
|
||||
return;
|
||||
}
|
||||
|
||||
LPITEM sash = ch->GetInventoryItem(sashCell);
|
||||
LPITEM source = ch->GetInventoryItem(sourceCell);
|
||||
|
||||
if (!FN_is_sash_item(sash))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The selected item is not a sash."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FN_is_sash_absorb_source(source))
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This item cannot be absorbed by a sash."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (sash->IsEquipped() || source->IsEquipped())
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Unequip items before absorbing bonuses."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (sash->GetSocket(0) != 0)
|
||||
{
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This sash already has absorbed bonuses."));
|
||||
return;
|
||||
}
|
||||
|
||||
int absorbPct = MINMAX(1, static_cast<int>(sash->GetValue(0)), 100);
|
||||
FN_set_sash_attrs_from_source(sash, source, absorbPct);
|
||||
|
||||
sash->SetSocket(0, source->GetVnum());
|
||||
sash->SetSocket(1, absorbPct);
|
||||
sash->SetSocket(2, static_cast<int32_t>(source->GetID()));
|
||||
|
||||
source->SetCount(0);
|
||||
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The sash absorbed bonuses successfully."));
|
||||
}
|
||||
|
||||
ACMD(do_in_game_mall)
|
||||
{
|
||||
if (LC_IsYMIR() == true || LC_IsKorea() == true)
|
||||
|
||||
@@ -523,6 +523,8 @@ int CItem::FindEquipCell(LPCHARACTER ch, int iCandidateCell)
|
||||
return WEAR_COSTUME_BODY;
|
||||
else if (GetSubType() == COSTUME_HAIR)
|
||||
return WEAR_COSTUME_HAIR;
|
||||
else if (GetSubType() == COSTUME_SASH)
|
||||
return WEAR_COSTUME_SASH;
|
||||
}
|
||||
else if (GetType() == ITEM_RING)
|
||||
{
|
||||
@@ -781,6 +783,11 @@ void CItem::ModifyPoints(bool bAdd)
|
||||
// [NOTE] 갑옷은 아이템 vnum을 보내고 헤어는 shape(value3)값을 보내는 이유는.. 기존 시스템이 그렇게 되어있음...
|
||||
toSetValue = (true == bAdd) ? this->GetValue(3) : 0;
|
||||
}
|
||||
else if (GetSubType() == COSTUME_SASH)
|
||||
{
|
||||
toSetPart = PART_ACCE;
|
||||
toSetValue = (true == bAdd) ? this->GetVnum() : 0;
|
||||
}
|
||||
|
||||
if (PART_MAX_NUM != toSetPart)
|
||||
{
|
||||
|
||||
@@ -583,6 +583,7 @@ enum ECharacterEquipmentPart
|
||||
CHR_EQUIPPART_WEAPON,
|
||||
CHR_EQUIPPART_HEAD,
|
||||
CHR_EQUIPPART_HAIR,
|
||||
CHR_EQUIPPART_ACCE,
|
||||
CHR_EQUIPPART_NUM,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user