Bueno, como el título lo informa les vengo a compartir toda la información relacionada al charset y cómo distribuye los bytes a nivel bit.
Que conste que esto es sólo para los que entiendan del tema, ya que esto es lo que trabaja el charset utilizando máscaras y operadores binarios para distribuir todo el preview del personaje a lo largo de 17/18 bytes.
Esto está basado en la fuente oficial del main liberado Season 5 CHS, por lo que no se contemplan las customs (Por ejemplo: CustomWings)
//////////////////////////////////////////////////////////////////////////
//Expand Item index
//////////////////////////////////////////////////////////////////////////
void ChangeCharacterExt(int Key, BYTE* Equipment, CHARACTER* pCharacter, OBJECT* pHelper)
{
CHARACTER* c;
if (pCharacter == NULL)
{
c = &CharactersClient[Key];
}
else
{
c = pCharacter;
}
OBJECT* o = &c->Object;
if (o->Type != MODEL_PLAYER)
{
return;
}
BYTE Type = 0;
#ifdef KWAK_FIX_COMPILE_LEVEL4_WARNING
#else // KWAK_FIX_COMPILE_LEVEL4_WARNING
BYTE ExtBit = 0;
#endif // KWAK_FIX_COMPILE_LEVEL4_WARNING
short ExtType = 0;
//check the right hand weapon
Type = Equipment[0];
ExtType = Equipment[11] & 240; // 11th byte 4bit son-in-law determines right-handed weapon excellent option
ExtType = (ExtType << 4) | Type;
#ifdef YDG_FIX_VIEWPORT_HAND_CHECK
if (ExtType == 0x0FFF)
#else // YDG_FIX_VIEWPORT_HAND_CHECK
if (ExtType == 0x1FFF)
#endif // YDG_FIX_VIEWPORT_HAND_CHECK
{
c->Weapon[0].Type = -1;
c->Weapon[0].Option1 = 0;
c->Weapon[0].ExtOption = 0;
}
else
{
c->Weapon[0].Type = MODEL_SWORD + ExtType;
}
//check the left hand weapon
Type = Equipment[1];
ExtType = Equipment[12] & 240; // 12th byte son-in-law 4bit determines right-handed weapon excellent option
ExtType = (ExtType << 4) | Type;
#ifdef YDG_FIX_VIEWPORT_HAND_CHECK
if (ExtType == 0x0FFF)
#else // YDG_FIX_VIEWPORT_HAND_CHECK
if (ExtType == 0x1FFF)
#endif // YDG_FIX_VIEWPORT_HAND_CHECK
{
c->Weapon[1].Type = -1;
c->Weapon[1].Option1 = 0;
c->Weapon[1].ExtOption = 0;
}
else
{
// Dark Spirit can be a left-handed weapon.
#ifdef PET_SYSTEM
if (GetBaseClass(c->Class) == CLASS_DARK_LORD && ((MODEL_STAFF + 5) - MODEL_SWORD) == ExtType)
{
#ifdef PBG_FIX_DARKPET_RENDER
// Receive Dark Spirit's level information from the left-handed weapon on the server and use it.
// Currently not receiving any information. It is set to the initial value.!!! Correction request!!!
// Since it will be used only for rendering, it is irrelevant to receive only level information.
ITEM* pEquipmentItemSlot = &CharacterMachine->Equipment[EQUIPMENT_WEAPON_LEFT];
PET_INFO* pPetInfo = giPetManager::GetPetInfo(pEquipmentItemSlot);
giPetManager::CreatePetDarkSpirit(c);
if (!InChaosCastle())
{
((CSPetSystem*)c->m_pPet)->SetPetInfo(pPetInfo);
}
#else //PBG_FIX_DARKPET_RENDER
c->Weapon[1].Type = MODEL_HELPER + 5; //-1;
giPetManager::CreatePetDarkSpirit(c);
#endif //PBG_FIX_DARKPET_RENDER
}
else
#endif //PET_SYSTEM
{
c->Weapon[1].Type = MODEL_SWORD + ExtType;
}
}
//check the wings
Type = (Equipment[4] >> 2) & 3;
#ifdef PBG_ADD_NEWCHAR_MONK_ITEM
// Change the structure of the wing index expansion due to the addition of a new character
if (Type == 1) // 1st wing
{
Type = Equipment[8] & 0x07;
switch (Type)
{
case 4:
{
c->Wing.Type = MODEL_WING + 41;
break;
}
default:
{
c->Wing.Type = MODEL_WING + Type - 1;
break;
}
}
}
else if (Type == 2) //second wing
{
Type = Equipment[8] & 0x07;
switch (Type)
{
case 5:
{
c->Wing.Type = MODEL_HELPER + 30;
break;
}
case 6:
{
c->Wing.Type = MODEL_WING + 42;
break;
}
case 7:
{
c->Wing.Type = MODEL_WING + 49;
break;
}
default:
{
c->Wing.Type = MODEL_WING + 2 + Type;
break;
}
}
}
else if (Type == 3) //3rd wing
{
Type = Equipment[8] & 0x07;
switch (Type)
{
case 0: // small wings
{
Type = (Equipment[16] >> 5);
c->Wing.Type = MODEL_WING + 129 + Type;
break;
}
case 6:
{
c->Wing.Type = MODEL_WING + 43;
break;
}
case 7:
{
c->Wing.Type = MODEL_WING + 50;
break;
}
default:
{
c->Wing.Type = MODEL_WING + 35 + Type;
break;
}
}
}
else // without wings type == 0
{
c->Wing.Type = -1;
c->Wing.Option1 = 0;
c->Wing.ExtOption = 0;
}
#else //PBG_ADD_NEWCHAR_MONK_ITEM
if (Type == 3)
{
Type = Equipment[8] & 0x07;
if (Type != 0)
{
#ifdef ADD_ALICE_WINGS_1
switch (Type)
{
case 5: // Cloak.
{
c->Wing.Type = MODEL_HELPER + 30;
break;
}
case 6: // Wings of disaster.
{
c->Wing.Type = MODEL_WING + 41;
break;
}
case 7: // Wings of Despair.
{
c->Wing.Type = MODEL_WING + 42;
break;
}
default:
{
c->Wing.Type = MODEL_WING + Type + 2;
}
}
#else //ADD_ALICE_WINGS_1
// Cloak. (Expandable to 6, 7).
if (Type == 5)
{
c->Wing.Type = MODEL_HELPER + 30;
}
else
{
c->Wing.Type = MODEL_WING + Type + 2;
}
#endif //ADD_ALICE_WINGS_1
}
else
{
c->Wing.Type = -1;
c->Wing.Option1 = 0;
c->Wing.ExtOption = 0;
}
}
else
{
c->Wing.Type = MODEL_WING + Type;
}
// 3rd wing item setting
Type = (Equipment[15] >> 2) & 0x07;
if (Type > 0)
{
#ifdef ADD_ALICE_WINGS_2
switch (Type)
{
case 6: // Dimensional wings.
{
c->Wing.Type = MODEL_WING + 43;
break;
}
default:
{
c->Wing.Type = MODEL_WING + 35 + Type;
}
}
#else //ADD_ALICE_WINGS_2
c->Wing.Type = MODEL_WING + 35 + Type;
#endif //ADD_ALICE_WINGS_2
}
#ifdef LDK_ADD_INGAMESHOP_SMALL_WING // little wings
Type = (Equipment[16] >> 5);
if (Type > 0)
{
switch (Type)
{
case 0x01: // Cloak of the Little Lord.
{
c->Wing.Type = MODEL_WING + 130;
break;
}
case 0x02: // Wings of little disaster.
{
c->Wing.Type = MODEL_WING + 131;
break;
}
case 0x03: // Little fairy's wings.
{
c->Wing.Type = MODEL_WING + 132;
break;
}
case 0x04: // Small Sky Wings.
{
c->Wing.Type = MODEL_WING + 133;
break;
}
case 0x05: // Little Satan's Wings.
{
c->Wing.Type = MODEL_WING + 134;
break;
}
}
}
#endif //LDK_ADD_INGAMESHOP_SMALL_WING
#endif //PBG_ADD_NEWCHAR_MONK_ITEM
// helper.
if (pHelper == NULL)
{
DeleteBug(o);
#ifdef LDK_ADD_NEW_PETPROCESS
ThePetProcess().DeletePet(c, c->Helper.Type, true);
#endif //LDK_ADD_NEW_PETPROCESS
}
else
{
pHelper->Live = false;
}
Type = Equipment[4] & 3; // The 4th index is also used on the wing side
if (Type == 3) // 4th byte is 0000 0011
{
Type = Equipment[9] & 0x01; // If the ninth index is 0000 0001, it's denorant.
if (Type == 1) // denorant
{
c->Helper.Type = MODEL_HELPER + 3;
if (pHelper == NULL)
{
CreateBug(MODEL_PEGASUS, o->Position, o);
}
else
{
CreateBugSub(MODEL_PEGASUS, o->Position, o, pHelper);
}
}
else
{
c->Helper.Type = -1;
c->Helper.Option1 = 0;
c->Helper.ExtOption = 0;
}
}
else // If the 4th byte is not 0000 0011, set Guardian Angel, Satan, Unilia, etc.
{
#if defined LDK_ADD_NEW_PETPROCESS // && defined LDK_ADD_PC4_GUARDIAN
BYTE _temp = Equipment[15] & 0xE0; // Demon 32, Guardian Angel 64
if (32 == _temp || 64 == _temp
#ifdef LDK_ADD_RUDOLPH_PET
|| 128 == _temp
#endif //LDK_ADD_RUDOLPH_PET
#ifdef PJH_ADD_PANDA_PET
|| 224 == _temp
#endif //PJH_ADD_PANDA_PET
#ifdef LDK_ADD_CS7_UNICORN_PET
|| 160 == _temp
#endif //LDK_ADD_CS7_UNICORN_PET
#ifdef YDG_ADD_SKELETON_PET
|| 96 == _temp // Skeleton Pet
#endif //YDG_ADD_SKELETON_PET
)
{
short _type = 0;
switch (_temp)
{
case 32:
{
_type = 64;
break;
}
case 64:
{
_type = 65;
break;
}
#ifdef LDK_ADD_RUDOLPH_PET
case 128:
{
_type = 67;
break;
}
#endif //LDK_ADD_RUDOLPH_PET
#ifdef PJH_ADD_PANDA_PET
case 224:
{
_type = 80;
break;
}
#endif //PJH_ADD_PANDA_PET
#ifdef LDK_ADD_CS7_UNICORN_PET
case 160:
{
_type = 106;
break;
}
#endif //LDK_ADD_CS7_UNICORN_PET
#ifdef YDG_ADD_SKELETON_PET
case 96: // Skeleton Pet
{
_type = 123;
break;
}
#endif //YDG_ADD_SKELETON_PET
}
c->Helper.Type = MODEL_HELPER + _type;
#if SELECTED_LANGUAGE == LANGUAGE_JAPANESE
#ifdef LDK_FIX_NOT_CREATE_NEW_PET
if ((_type != 64 && _type != 65) || (CHARACTER_SCENE == SceneFlag || c == Hero))
#else //LDK_FIX_NOT_CREATE_NEW_PET
if (CHARACTER_SCENE == SceneFlag || c == Hero)
#endif //LDK_FIX_NOT_CREATE_NEW_PET
#endif //SELECTED_LANGUAGE == LANGUAGE_JAPANESE
{
ThePetProcess().CreatePet(ITEM_HELPER + _type, c->Helper.Type, o->Position, c);
}
}
else
#endif //defined LDK_ADD_NEW_PETPROCESS // && defined LDK_ADD_PC4_GUARDIAN
{
c->Helper.Type = MODEL_HELPER + Type;
int HelperType = 0;
BOOL bCreateHelper = TRUE;
switch (Type)
{
case 0:
{
HelperType = MODEL_HELPER;
break;
}
case 2:
{
HelperType = MODEL_UNICON;
break;
}
case 3:
{
HelperType = MODEL_PEGASUS;
break;
}
default:
{
bCreateHelper = FALSE;
break;
}
}
if (bCreateHelper == TRUE)
{
if (pHelper == NULL)
{
CreateBug(HelperType, o->Position, o);
}
else
{
CreateBugSub(HelperType, o->Position, o, pHelper);
}
}
}
}
Type = Equipment[11] & 0x01; // If the 11th byte is 0000 0001, it is a dark horse
if (Type == 1) // Dark Horse.
{
c->Helper.Type = MODEL_HELPER + 4;
if (pHelper == NULL)
{
CreateBug(MODEL_DARK_HORSE, o->Position, o);
}
else
{
CreateBugSub(MODEL_DARK_HORSE, o->Position, o, pHelper);
}
}
// Fenryl Item Related
Type = Equipment[11] & 0x04; // If the 11th byte is 0000 0100, then the penrile
if (Type == 4) // Fenryl
{
c->Helper.Type = MODEL_HELPER + 37;
Type = Equipment[15] & 3; // Compare the 15th byte
int iFenrirType = Equipment[16] & 1; // If the 16th byte is 1, it is a welcome fenril.
if (iFenrirType == 1)
{
Type = 0x04;
}
c->Helper.Option1 = Type; // Assign the option value to the Option1 variable
if (Type == 0x01) // If 0000 0001 is black fenril
{
if (pHelper == NULL)
{
CreateBug(MODEL_FENRIR_BLACK, o->Position, o);
}
else
{
CreateBugSub(MODEL_FENRIR_BLACK, o->Position, o, pHelper);
}
}
else if (Type == 0x02) // If 0000 0010 is blue fenril
{
if (pHelper == NULL)
{
CreateBug(MODEL_FENRIR_BLUE, o->Position, o);
}
else
{
CreateBugSub(MODEL_FENRIR_BLUE, o->Position, o, pHelper);
}
}
else if (Type == 0x04)
{
if (pHelper == NULL)
{
CreateBug(MODEL_FENRIR_GOLD, o->Position, o);
}
else
{
CreateBugSub(MODEL_FENRIR_GOLD, o->Position, o, pHelper);
}
}
else // If it is any other value, the red penrile
{
if (pHelper == NULL)
{
CreateBug(MODEL_FENRIR_RED, o->Position, o);
}
else
{
CreateBugSub(MODEL_FENRIR_RED, o->Position, o, pHelper);
}
}
}
DeleteParts(c);
Type = (Equipment[11] >> 1) & 0x01;
if (Type == 1)
{
if (c->EtcPart <= 0 || c->EtcPart > 3)
{
c->EtcPart = PARTS_LION;
}
}
else
{
if (c->EtcPart <= 0 || c->EtcPart > 3)
{
c->EtcPart = 0;
}
}
hanguo_check1();
int Level = ((int)Equipment[5] << 16) + ((int)Equipment[6] << 8) + ((int)Equipment[7]);
c->Weapon[0].Level = LevelConvert((Level >> 0) & 7);
c->Weapon[1].Level = LevelConvert((Level >> 3) & 7);
c->Wing.Level = 0;
c->Helper.Level = 0;
if (c->Change)
{
return;
}
//pitching
ExtType = (Equipment[2] >> 4) + ((Equipment[8] >> 7) & 1) * 16 + (Equipment[12] & 15) * 32;
if (ExtType == 0x1FF)
{
c->BodyPart[BODYPART_HELM].Type = MODEL_BODY_HELM + GetSkinModelIndex(c->Class);
}
else
{
c->BodyPart[BODYPART_HELM].Type = MODEL_HELM + ExtType;
}
//Armor
ExtType = (Equipment[2] & 15) + ((Equipment[8] >> 6) & 1) * 16 + ((Equipment[13] >> 4) & 15) * 32;
if (ExtType == 0x1FF)
{
c->BodyPart[BODYPART_ARMOR].Type = MODEL_BODY_ARMOR + GetSkinModelIndex(c->Class);
}
else
{
c->BodyPart[BODYPART_ARMOR].Type = MODEL_ARMOR + ExtType;
}
//Pants
ExtType = (Equipment[3] >> 4) + ((Equipment[8] >> 5) & 1) * 16 + (Equipment[13] & 15) * 32;
if (ExtType == 0x1FF)
{
c->BodyPart[BODYPART_PANTS].Type = MODEL_BODY_PANTS + GetSkinModelIndex(c->Class);
}
else
{
c->BodyPart[BODYPART_PANTS].Type = MODEL_PANTS + ExtType;
}
//Gloves
ExtType = (Equipment[3] & 15) + ((Equipment[8] >> 4) & 1) * 16 + ((Equipment[14] >> 4) & 15) * 32;
if (ExtType == 0x1FF)
{
c->BodyPart[BODYPART_GLOVES].Type = MODEL_BODY_GLOVES + GetSkinModelIndex(c->Class);
}
else
{
c->BodyPart[BODYPART_GLOVES].Type = MODEL_GLOVES + ExtType;
}
//shoes
ExtType = (Equipment[4] >> 4) + ((Equipment[8] >> 3) & 1) * 16 + (Equipment[14] & 15) * 32;
if (ExtType == 0x1FF)
{
c->BodyPart[BODYPART_BOOTS].Type = MODEL_BODY_BOOTS + GetSkinModelIndex(c->Class);
}
else
{
c->BodyPart[BODYPART_BOOTS].Type = MODEL_BOOTS + ExtType;
}
c->BodyPart[BODYPART_HELM].Level = LevelConvert((Level >> 6) & 7);
c->BodyPart[BODYPART_ARMOR].Level = LevelConvert((Level >> 9) & 7);
c->BodyPart[BODYPART_PANTS].Level = LevelConvert((Level >> 12) & 7);
c->BodyPart[BODYPART_GLOVES].Level = LevelConvert((Level >> 15) & 7);
c->BodyPart[BODYPART_BOOTS].Level = LevelConvert((Level >> 18) & 7);
c->BodyPart[BODYPART_HELM].Option1 = (Equipment[9] & 128) / 128;
c->BodyPart[BODYPART_ARMOR].Option1 = (Equipment[9] & 64) / 64;
c->BodyPart[BODYPART_PANTS].Option1 = (Equipment[9] & 32) / 32;
c->BodyPart[BODYPART_GLOVES].Option1 = (Equipment[9] & 16) / 16;
c->BodyPart[BODYPART_BOOTS].Option1 = (Equipment[9] & 8) / 8;
c->BodyPart[BODYPART_HELM].ExtOption = (Equipment[10] & 128) / 128;
c->BodyPart[BODYPART_ARMOR].ExtOption = (Equipment[10] & 64) / 64;
c->BodyPart[BODYPART_PANTS].ExtOption = (Equipment[10] & 32) / 32;
c->BodyPart[BODYPART_GLOVES].ExtOption = (Equipment[10] & 16) / 16;
c->BodyPart[BODYPART_BOOTS].ExtOption = (Equipment[10] & 8) / 8;
c->Weapon[0].Option1 = (Equipment[9] & 4) / 4;
c->Weapon[1].Option1 = (Equipment[9] & 2) / 2;
c->Weapon[0].ExtOption = (Equipment[10] & 4) / 4;
c->Weapon[1].ExtOption = (Equipment[10] & 2) / 2;
c->ExtendState = Equipment[10] & 0x01;
#ifndef GUILD_WAR_EVENT
ChangeChaosCastleUnit(c);
#endif //GUILD_WAR_EVENT
SetCharacterScale(c);
}