Rework of NPC::PickPocket() - added stacking ability

This commit is contained in:
Uleat 2016-02-27 20:27:11 -05:00
parent 2268e6ed34
commit 63cce6875f
2 changed files with 100 additions and 140 deletions

View File

@ -126,6 +126,7 @@ RULE_INT(Character, InvSnapshotMinIntervalM, 180) // Minimum time (in minutes) b
RULE_INT(Character, InvSnapshotMinRetryM, 30) // Time (in minutes) to re-attempt an inventory snapshot after a failure RULE_INT(Character, InvSnapshotMinRetryM, 30) // Time (in minutes) to re-attempt an inventory snapshot after a failure
RULE_INT(Character, InvSnapshotHistoryD, 30) // Time (in days) to keep snapshot entries RULE_INT(Character, InvSnapshotHistoryD, 30) // Time (in days) to keep snapshot entries
RULE_BOOL(Character, RestrictSpellScribing, false) // Restricts spell scribing to allowable races/classes of spell scroll, if true RULE_BOOL(Character, RestrictSpellScribing, false) // Restricts spell scribing to allowable races/classes of spell scroll, if true
RULE_BOOL(Character, UseStackablePickPocketing, true) // Allows stackable pickpocketed items to stack instead of only being allowed in empty inventory slots
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Mercs) RULE_CATEGORY(Mercs)

View File

@ -1425,13 +1425,13 @@ uint32 NPC::GetMaxDamage(uint8 tlevel)
return dmg; return dmg;
} }
void NPC::PickPocket(Client* thief) { void NPC::PickPocket(Client* thief)
{
thief->CheckIncreaseSkill(SkillPickPockets, nullptr, 5); thief->CheckIncreaseSkill(SkillPickPockets, nullptr, 5);
//make sure were allowed to targte them: //make sure were allowed to target them:
int olevel = GetLevel(); int over_level = GetLevel();
if(olevel > (thief->GetLevel() + THIEF_PICKPOCKET_OVER)) { if(over_level > (thief->GetLevel() + THIEF_PICKPOCKET_OVER)) {
thief->Message(13, "You are too inexperienced to pick pocket this target"); thief->Message(13, "You are too inexperienced to pick pocket this target");
thief->SendPickPocketResponse(this, 0, PickPocketFailed); thief->SendPickPocketResponse(this, 0, PickPocketFailed);
//should we check aggro //should we check aggro
@ -1447,150 +1447,109 @@ void NPC::PickPocket(Client* thief) {
} }
int steal_skill = thief->GetSkill(SkillPickPockets); int steal_skill = thief->GetSkill(SkillPickPockets);
int stealchance = steal_skill*100/(5*olevel+5); int steal_chance = steal_skill * 100 / (5 * over_level + 5);
ItemInst* inst = 0;
int x = 0;
int slot[50];
int steal_items[50];
int charges[50];
int money[4];
money[0] = GetPlatinum();
money[1] = GetGold();
money[2] = GetSilver();
money[3] = GetCopper();
if (steal_skill < 125)
money[0] = 0;
if (steal_skill < 60)
money[1] = 0;
memset(slot,0,50);
memset(steal_items,0,50);
memset(charges,0,50);
//Determine wheter to steal money or an item. //Determine wheter to steal money or an item.
bool no_coin = ((money[0] + money[1] + money[2] + money[3]) == 0); int money[6] = { 0, ((steal_skill >= 125) ? (GetPlatinum()) : (0)), ((steal_skill >= 60) ? (GetGold()) : (0)), GetSilver(), GetCopper(), 0 };
bool steal_item = (zone->random.Roll(50) || no_coin); bool has_coin = ((money[PickPocketPlatinum] | money[PickPocketGold] | money[PickPocketSilver] | money[PickPocketCopper]) != 0);
if (steal_item) bool steal_item = (steal_skill >= steal_chance && (zone->random.Roll(50) || !has_coin));
{
ItemList::iterator cur,end; // still needs to have FindFreeSlot vs PutItemInInventory issue worked out
cur = itemlist.begin(); while (steal_item) {
end = itemlist.end(); std::vector<std::pair<const Item_Struct*, uint16>> loot_selection; // <const Item_Struct*, charges>
for(; cur != end && x < 49; ++cur) { for (auto item_iter : itemlist) {
ServerLootItem_Struct* citem = *cur; if (!item_iter || !item_iter->item_id)
const Item_Struct* item = database.GetItem(citem->item_id); continue;
if (item)
{ auto item_test = database.GetItem(item_iter->item_id);
inst = database.CreateItem(item, citem->charges); if (item_test->Magic || !item_test->NoDrop || item_test->ItemType == ItemClassContainer || thief->CheckLoreConflict(item_test))
bool is_arrow = (item->ItemType == ItemTypeArrow) ? true : false; continue;
int slot_id = thief->GetInv().FindFreeSlot(false, true, inst->GetItem()->Size, is_arrow);
if (/*!Equipped(item->ID) &&*/ loot_selection.push_back(std::make_pair(item_test, ((item_test->Stackable) ? (1) : (item_iter->charges))));
!item->Magic && item->NoDrop != 0 && !inst->IsType(ItemClassContainer) && slot_id != INVALID_INDEX
/*&& steal_skill > item->StealSkill*/ )
{
slot[x] = slot_id;
steal_items[x] = item->ID;
if (inst->IsStackable())
charges[x] = 1;
else
charges[x] = citem->charges;
x++;
}
}
} }
if (x > 0) if (loot_selection.empty()) {
{
int random = zone->random.Int(0, x-1);
inst = database.CreateItem(steal_items[random], charges[random]);
if (inst)
{
const Item_Struct* item = inst->GetItem();
if (item)
{
if (/*item->StealSkill || */steal_skill >= stealchance)
{
thief->PutItemInInventory(slot[random], *inst);
thief->SendItemPacket(slot[random], inst, ItemPacketTrade);
RemoveItem(item->ID);
thief->SendPickPocketResponse(this, 0, PickPocketItem, item);
}
else
steal_item = false;
}
else
steal_item = false;
}
else
steal_item = false;
}
else if (!no_coin)
{
steal_item = false; steal_item = false;
} break;
else
{
thief->Message(0, "This target's pockets are empty");
thief->SendPickPocketResponse(this, 0, PickPocketFailed);
}
}
if (!steal_item) //Steal money
{
uint32 amt = zone->random.Int(1, (steal_skill/25)+1);
int steal_type = 0;
if (!money[0])
{
steal_type = 1;
if (!money[1])
{
steal_type = 2;
if (!money[2])
{
steal_type = 3;
}
}
} }
if (zone->random.Roll(stealchance)) int random = zone->random.Int(0, (loot_selection.size() - 1));
{ uint16 slot_id = thief->GetInv().FindFreeSlot(false, true, (loot_selection[random].first->Size), (loot_selection[random].first->ItemType == ItemTypeArrow));
switch (steal_type) if (slot_id == INVALID_INDEX) {
{ steal_item = false;
case 0:{ break;
if (amt > GetPlatinum()) }
amt = GetPlatinum();
SetPlatinum(GetPlatinum()-amt); auto item_inst = database.CreateItem(loot_selection[random].first, loot_selection[random].second);
thief->AddMoneyToPP(0,0,0,amt,false); if (item_inst == nullptr) {
thief->SendPickPocketResponse(this, amt, PickPocketPlatinum); steal_item = false;
break; break;
} }
case 1:{
if (amt > GetGold()) // Successful item pickpocket
amt = GetGold(); if (item_inst->IsStackable() && RuleB(Character, UseStackablePickPocketing)) {
SetGold(GetGold()-amt); if (!thief->TryStacking(item_inst, ItemPacketTrade, false, false)) {
thief->AddMoneyToPP(0,0,amt,0,false); thief->PutItemInInventory(slot_id, *item_inst);
thief->SendPickPocketResponse(this, amt, PickPocketGold); thief->SendItemPacket(slot_id, item_inst, ItemPacketTrade);
break;
}
case 2:{
if (amt > GetSilver())
amt = GetSilver();
SetSilver(GetSilver()-amt);
thief->AddMoneyToPP(0,amt,0,0,false);
thief->SendPickPocketResponse(this, amt, PickPocketSilver);
break;
}
case 3:{
if (amt > GetCopper())
amt = GetCopper();
SetCopper(GetCopper()-amt);
thief->AddMoneyToPP(amt,0,0,0,false);
thief->SendPickPocketResponse(this, amt, PickPocketCopper);
break;
}
} }
} }
else else {
{ thief->PutItemInInventory(slot_id, *item_inst);
thief->SendPickPocketResponse(this, 0, PickPocketFailed); thief->SendItemPacket(slot_id, item_inst, ItemPacketTrade);
} }
RemoveItem(item_inst->GetID());
thief->SendPickPocketResponse(this, 0, PickPocketItem, item_inst->GetItem());
return;
} }
safe_delete(inst);
while (!steal_item && has_coin) {
uint32 coin_amount = zone->random.Int(1, (steal_skill / 25) + 1);
int coin_type = PickPocketPlatinum;
while (coin_type <= PickPocketCopper) {
if (money[coin_type]) {
if (coin_amount > money[coin_type])
coin_amount = money[coin_type];
break;
}
++coin_type;
}
if (coin_type > PickPocketCopper)
break;
memset(money, 0, (sizeof(int) * 6));
money[coin_type] = coin_amount;
if (zone->random.Roll(steal_chance)) { // Successful coin pickpocket
switch (coin_type) {
case PickPocketPlatinum:
SetPlatinum(GetPlatinum() - coin_amount);
break;
case PickPocketGold:
SetGold(GetGold() - coin_amount);
break;
case PickPocketSilver:
SetSilver(GetSilver() - coin_amount);
break;
case PickPocketCopper:
SetCopper(GetCopper() - coin_amount);
break;
default: // has_coin..but, doesn't have coin?
thief->SendPickPocketResponse(this, 0, PickPocketFailed);
return;
}
thief->AddMoneyToPP(money[3], money[2], money[1], money[0], false);
thief->SendPickPocketResponse(this, coin_amount, coin_type);
return;
}
thief->SendPickPocketResponse(this, 0, PickPocketFailed);
return;
}
thief->Message(0, "This target's pockets are empty");
thief->SendPickPocketResponse(this, 0, PickPocketFailed);
} }
void Mob::NPCSpecialAttacks(const char* parse, int permtag, bool reset, bool remove) { void Mob::NPCSpecialAttacks(const char* parse, int permtag, bool reset, bool remove) {