I will share you the code I've got from reversing binaries, but ofc this aint from 2005
Code:
void Monster::DropMedicine(uint32_t idOwner)
{
int roll = FastRandom::NextInt32(100);
int count;
if (roll < 2) count = 8;
else if (roll < 3) count = 6;
else if (roll < 5) count = 5;
else if (roll < 8) count = 4;
else if (roll < 10) count = 3;
else if (roll < 25) count = 2;
else count = 1;
for (int i = 0; i < count; ++i)
{
uint32_t dropMedicine = FastRandom::ChanceCalc(50) ? m_type->dropHp : m_type->dropMp;
DropItem(dropMedicine, idOwner);
}
}
bool Monster::GetDropItem(DropItemRecord& itemRecord, uint32_t valueBase, int qualityOverride)
{
if (valueBase < 1)
{
return false;
}
int quality;
if (qualityOverride > -1)
{
quality = qualityOverride;
}
else
{
int random = FastRandom::NextInt32(100);
if (random < 30)
{
quality = 5;
}
else if (random < 70)
{
quality = 4;
}
else
{
quality = 3;
}
}
int32_t itemSubTypeRng = FastRandom::NextInt32(1200);
uint32_t itemSubType;
uint32_t itemLev;
uint8_t itemColor = 3;
if (itemSubTypeRng < 20)
{
// shoes and talismans
static constexpr uint32_t specialType[] = {160, 201, 202};
if (m_type->dropShoes == 99)
{
return false;
}
itemSubType = specialType[FastRandom::NextInt32(_countof(specialType) - 1)]; // max inclusive
itemLev = m_type->dropShoes;
if (itemSubType == 201 || itemSubType == 202)
{
itemLev = 0;
}
}
else if (itemSubTypeRng < 50)
{
// necklace and bag
static constexpr uint32_t dropTypes[] = {120, 121};
if (m_type->dropNecklace == 99)
{
return false;
}
itemSubType = dropTypes[FastRandom::NextInt32(_countof(dropTypes) - 1)];
itemLev = m_type->dropNecklace;
}
else if (itemSubTypeRng < 100)
{
// ring, heavy ring and bracelet
static constexpr uint32_t dropTypes[] = {150, 151, 152};
if (m_type->dropRing == 99)
{
return false;
}
itemSubType = dropTypes[FastRandom::NextInt32(_countof(dropTypes) - 1)];
itemLev = m_type->dropRing;
}
else if (itemSubTypeRng < 400)
{
// helmets
static constexpr uint32_t dropTypes[] = {111, 112, 113, 114, 117, 118, 123, 141, 142};
if (m_type->dropArmet == 99)
{
return false;
}
itemSubType = dropTypes[FastRandom::NextInt32(_countof(dropTypes) - 1)];
itemLev = m_type->dropArmet;
itemColor = static_cast<uint8_t>(FastRandom::NextUInt32(3, 9));
}
else if (itemSubTypeRng < 700)
{
// armors
static constexpr uint32_t dropTypes[] = {130, 131, 132, 133, 134, 135};
if (m_type->dropArmor == 99)
{
return false;
}
itemSubType = dropTypes[FastRandom::NextInt32(_countof(dropTypes) - 1)];
itemLev = m_type->dropArmor;
itemColor = static_cast<uint8_t>(FastRandom::NextUInt32(3, 9));
}
else
{
if (m_type->dropWeapon == 99)
{
return false;
}
// drop weapons
int dropRng = FastRandom::NextInt32(100);
if (dropRng < 20)
{
// drop backsword
itemSubType = 421;
itemLev = m_type->dropWeapon;
}
else if (dropRng < 40)
{
// drop nothing
return false;
}
else if (dropRng < 80)
{
// single hand weapons and bow
static constexpr uint32_t dropTypes[] = {410, 420, 430, 440, 450, 460, 480, 481, 490, 500, 601};
itemSubType = dropTypes[FastRandom::NextInt32(_countof(dropTypes) - 1)];
itemLev = m_type->dropWeapon;
}
else
{
// double hand and shield
static constexpr uint32_t dropTypes[] = {510, 530, 560, 580, 900};
itemSubType = dropTypes[FastRandom::NextInt32(_countof(dropTypes) - 1)];
itemLev = m_type->dropWeapon;
}
itemColor = static_cast<uint8_t>(FastRandom::NextUInt32(3, 9));
}
if (itemLev == 99)
{
return false;
}
int levelAdustment = FastRandom::NextInt32(100);
if (levelAdustment < 50)
{
int adjusted = (int)itemLev / 3 + FastRandom::NextInt32((int)itemLev / 2);
itemLev = adjusted > 0 ? adjusted - 1 : 0;
}
else if (levelAdustment < 80)
{
// keep level
}
else
{
bool isLowTier = (itemSubType >= 110 && itemSubType <= 114)
|| (itemSubType >= 130 && itemSubType <= 134)
|| (itemSubType >= 900 && itemSubType <= 999);
uint32_t cap = isLowTier ? 9 : 23;
itemLev = __min(itemLev + 1, cap);
}
uint32_t itemTypeId = itemSubType * 1000 + itemLev * 10 + quality;
const ItemTypeStr* itemType = ItemManager().GetItemType(itemTypeId);
if (!itemType)
{
return false;
}
memset(&itemRecord, 0, sizeof(DropItemRecord));
itemRecord.type = itemTypeId;
float amountLimit = (float)itemType->amountLimit;
int64_t amountLimitScaled = (int64_t)(FastRandom::NextFloat(0.7f, 1.3f) * amountLimit);
if (amountLimitScaled < 1)
{
amountLimitScaled = 1;
}
itemRecord.amountLimit = (uint32_t)amountLimitScaled;
itemRecord.amount = (uint32_t)amountLimitScaled;
if (quality <= 5)
{
uint32_t price = itemType->price;
if (price == 0) price = 1;
uint32_t amount = 3 * itemType->amount * itemType->amountLimit / price;
itemRecord.amount = __max(1u, __min(itemRecord.amountLimit, amount));
}
else
{
itemRecord.amount = itemRecord.amountLimit * (FastRandom::NextUInt32(50) + 50) / 100;
}
if (itemTypeId >= 400000 && itemTypeId < 600000)
{
int socketChance = FastRandom::NextInt32(100);
if (socketChance < 5)
{
itemRecord.socketNum = 2;
}
else if (socketChance < 20)
{
itemRecord.socketNum = 1;
}
}
// AddLev 0.33% chance.
if (FastRandom::NextInt32(300) == 123)
{
itemRecord.magic3 = 1;
}
if (itemRecord.socketNum == 0)
{
int divisor = Item::IsBow(itemTypeId) ? 60 : 300;
if (FastRandom::NextInt32(divisor) == 13)
{
if (FastRandom::ChanceCalc(30))
{
itemRecord.bless = 5;
}
else
{
itemRecord.bless = 3;
}
}
}
itemRecord.color = itemColor;
if (itemSubType == 201 || itemSubType == 202)
{
itemRecord.bless = 0;
}
return true;
}
void Monster::DropEquipment(uint32_t itemTypeId, uint32_t idOwner, int quality)
{
CHECK(itemTypeId != 0);
if (itemTypeId < 100)
{
DropMoney(itemTypeId, idOwner);
return;
}
DropItemRecord itemRecord{};
if (!GetDropItem(itemRecord, itemTypeId, quality))
{
return;
}
POINT pos;
pos.x = GetMapX();
pos.y = GetMapY();
if (!GetMap()->FindDropItemCell(2, pos))
{
return;
}
itemTypeId = itemRecord.type;
User* pKiller = (User*)GetMap()->QueryUser(idOwner);
if (pKiller)
{
bool effect = false;
if (itemTypeId % 10 == 9)
{
pKiller->SendSysMsg("STR_LUCK_ULTRA_EQ");
effect = true;
}
else if (itemTypeId == TYPE_DRAGONBALL)
{
pKiller->SendSysMsg("STR_LUCK_DRAGON_BALL");
effect = true;
}
else if (itemTypeId == TYPE_DIVOICEITEM)
{
pKiller->SendSysMsg("STR_LUCK_SHT_STAR_TEAR");
effect = true;
}
if (effect)
{
pKiller->BroadcastEffect(LUCKY_GUY);
}
// A looted +N item (magic3 = add-level > 0) credits the looter's
// mentor(s) with composition/add-level points. The value comes from
// cq_student_type.Addlevel; magic3 only gates the event.
if (itemRecord.magic3 > 0)
{
if (IGuideProvider* guide = QueryGuideProvider(ModuleManager().GetProvider(ModuleId::Guide)))
guide->AwardAddLevel(pKiller, itemRecord.magic3);
}
}
uint32_t newId = RoleManager().GetNextMapItemId();
MapItem* pMapItem = MapItem::CreateNew();
if (pMapItem->Create(newId, GetMap(), pos, itemRecord, idOwner))
{
return;
}
GM_LOG("gmlog/dropitem", "Monster::DropEquipment(): monster_type[%d], item_type[%u]", GetTypeId(), itemTypeId);
pMapItem->Release();
RoleManager().RecycleMapItemId(newId);
}
void Monster::BeKill(IRole* pAttacker)
{
if (IsDeleted())
{
return;
}
if (statusSet_)
{
statusSet_->AddKeepEffect1(KEEPEFFECT_FADE | KEEPEFFECT_GHOST);
}
uint32_t idOwnerItem = 0;
GameMap* pMap = GetMap();
User* pUser = nullptr;
if (pAttacker->QueryObj(OBJ_USER, IPP_OF(pUser)))
{
idOwnerItem = pUser->GetId();
}
if (GetId() >= CALLPETID_FIRST && GetId() <= CALLPETID_LAST)
{
// call pet bomb logic like my_server
}
uint32_t dropMoney = m_type->dropMoney;
int seed = (int)dropMoney * 2;
if (GetLevel() > 60)
{
int r = FastRandom::NextInt32(100);
if (r < 3)
{
uint32_t budget = 1320u * seed / 100u;
int splits;
switch (FastRandom::NextInt32(4))
{
case 0: splits = 5;
break;
case 1: splits = 6;
break;
case 2: splits = 7;
break;
default: splits = 8;
break;
}
int perPacket = budget / splits;
for (int i = 0; i < splits; ++i)
{
uint32_t amount = (uint32_t)(FastRandom::NextFloat(0.8f) * perPacket);
if (FastRandom::NextInt32(100) >= 40)
{
DropMoney(amount, idOwnerItem);
}
else
{
DropEquipment(amount, idOwnerItem);
}
}
}
else if (r < 35)
{
uint32_t budget = 180 * seed / 100u;
int r2 = FastRandom::NextInt32(100);
int splits;
if (r2 > 40)
{
splits = 1;
}
else if (r2 >= 10)
{
splits = 2;
}
else
{
splits = 1;
}
int perPacket = budget / splits;
for (int i = 0; i < splits; ++i)
{
uint32_t amount = (uint32_t)(FastRandom::NextFloat(0.8f) * perPacket);
if (FastRandom::NextInt32(100) >= 40)
{
DropMoney(amount, idOwnerItem);
}
else
{
DropEquipment(amount, idOwnerItem);
}
}
}
// no drop at all
}
else
{
int r = FastRandom::NextInt32(100);
if (r < 2)
{
uint32_t budget = 2000u * seed / 100u;
int splits;
switch (FastRandom::NextInt32(4))
{
case 0: splits = 5;
break;
case 1: splits = 6;
break;
case 2: splits = 7;
break;
default: splits = 8;
break;
}
int perPacket = budget / splits;
for (int i = 0; i < splits; ++i)
{
uint32_t amount = (uint32_t)(FastRandom::NextFloat(0.8f) * perPacket);
if (FastRandom::NextInt32(100) >= 40)
{
DropMoney(amount, idOwnerItem);
}
else
{
DropEquipment(amount, idOwnerItem);
}
}
}
else if (r < 27)
{
uint32_t budget = 240 * seed / 100u;
int r2 = FastRandom::NextInt32(100);
int splits;
if (r2 > 40)
{
splits = 1;
}
else if (r2 >= 10)
{
splits = 2;
}
else
{
splits = 1;
}
int perPacket = budget / splits;
for (int i = 0; i < splits; ++i)
{
uint32_t amount = (uint32_t)(FastRandom::NextFloat(0.8f) * perPacket);
if (FastRandom::NextInt32(100) >= 40)
{
DropMoney(amount, idOwnerItem);
}
else
{
DropEquipment(amount, idOwnerItem);
}
}
}
// no drop at all
}
// equipment drop
int qualityItemRng = FastRandom::NextInt32(50000);
if (qualityItemRng < 1)
{
bool doDrop;
if (GetLevel() <= 80)
{
doDrop = FastRandom::NextInt32(3) == 1;
}
else
{
doDrop = FastRandom::NextInt32(10) == 7;
}
if (doDrop)
{
uint32_t amount = 100u * GetLevel();
DropEquipment(amount, idOwnerItem, ITEMQUALITY_SUPER);
}
}
else if (qualityItemRng < 6)
{
if (GetLevel() <= 80
&& FastRandom::NextInt32(5) == 3)
{
uint32_t amount = 100u * GetLevel();
DropEquipment(amount, idOwnerItem, ITEMQUALITY_ELITE);
}
}
else if (qualityItemRng < 31)
{
if (GetLevel() <= 80
&& FastRandom::NextInt32(3) == 1)
{
uint32_t amount = 50u * GetLevel();
DropEquipment(amount, idOwnerItem, ITEMQUALITY_UNIQUE);
}
}
else if (qualityItemRng < 131)
{
uint32_t amount = 30u * GetLevel();
DropEquipment(amount, idOwnerItem, ITEMQUALITY_REFINED);
}
if (FastRandom::ChanceCalc(3))
{
DropMedicine(idOwnerItem);
}
if (pMap)
{
if (FastRandom::NextInt32(750) == 123)
{
DropItem(TYPE_SHOOTINGSTAR, idOwnerItem);
}
if (FastRandom::NextInt32(300000) == 123)
{
DropItem(TYPE_DRAGONBALL, idOwnerItem);
if (pUser)
{
pUser->BroadcastRoomMsg("STR_DRAGON_BALL_DROP", pUser->GetName());
GM_LOG("gmlog/emoney_buy", "%u\t%s\t%u\t%u", pUser->GetId(), pUser->GetName(), TYPE_DRAGONBALL, 1);
}
}
}
int gemRandChance;
if (GetLevel() < 117)
{
if (pUser
&& pUser->GetLevel() <= GetLevel() + 5)
{
gemRandChance = 900;
}
else
{
gemRandChance = 9000;
}
}
else
{
gemRandChance = 1400;
}
if (FastRandom::NextInt32(gemRandChance) == 13)
{
int gemRoll = FastRandom::NextInt32(1200);
uint32_t itemType;
if (gemRoll < 100) itemType = 700011;
else if (gemRoll < 200) itemType = 700001;
else if (gemRoll < 300) itemType = 700031;
else if (gemRoll < 400) itemType = 700101;
else if (gemRoll < 500) itemType = 700121;
else if (gemRoll < 675) itemType = 700061;
else if (gemRoll < 850) itemType = 700051;
else if (gemRoll < 1025) itemType = 700041;
else itemType = 700021;
DropItem(itemType, idOwnerItem);
}
if (GetId() < CALLPETID_FIRST || GetId() > CALLPETID_LAST)
{
DropCommonItem(idOwnerItem);
}
if (pUser)
{
GameAction::ExecuteAction(m_type->action, pUser, this);
}
if (m_type->type == 25) // unsure what this would mean
{
User* pOwner = (User*)QueryUser();
if (pOwner)
{
pOwner->SetAttributes(USERATTRIB_LIFE, 0, SYNCHRO_TRUE);
pOwner->BeKill(pAttacker);
}
}
DelMonster(false);
}