// Internal Method: Checks an inventory queue type bucket for a particular item int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity) { iter_queue it; iter_contents itb; uint8 quantity_found = 0; // Read-only iteration of queue for (it = iqueue.begin(); it != iqueue.end(); ++it) { ItemInst* inst = *it; if (inst) { if (inst->GetID() == item_id) { quantity_found += (inst->GetCharges() <= 0) ? 1 : inst->GetCharges(); if (quantity_found >= quantity) return SLOT_CURSOR; } } // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb = inst->_begin(); itb != inst->_end(); ++itb) { ItemInst* baginst = itb->second; if (baginst->GetID() == item_id) { quantity_found += (baginst->GetCharges() <= 0) ? 1 : baginst->GetCharges(); if (quantity_found >= quantity) return Inventory::CalcSlotId(SLOT_CURSOR, itb->first); } } } } // Not found return SLOT_INVALID; }
// Internal Method: Checks an inventory bucket for a particular item int16 Inventory::_HasItem(std::map<int16, ItemInst*>& bucket, uint32 item_id, uint8 quantity) { iter_inst it; iter_contents itb; ItemInst* inst = nullptr; uint8 quantity_found = 0; // Check item: After failed checks, check bag contents (if bag) for (it = bucket.begin(); it != bucket.end(); ++it) { inst = it->second; if (inst) { if (inst->GetID() == item_id) { quantity_found += (inst->GetCharges() <= 0) ? 1 : inst->GetCharges(); if (quantity_found >= quantity) return it->first; } } // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb = inst->_begin(); itb != inst->_end(); ++itb) { ItemInst* baginst = itb->second; if (baginst->GetID() == item_id) { quantity_found += (baginst->GetCharges() <= 0) ? 1 : baginst->GetCharges(); if (quantity_found >= quantity) return Inventory::CalcSlotId(it->first, itb->first); } } } } // Not found return SLOT_INVALID; }
// Internal Method: Checks an inventory bucket for a particular item sint16 Inventory::_HasItem(map<sint16, ItemInst*>& bucket, uint32 item_id, uint8 quantity) { iter_inst it; iter_contents itb; ItemInst* inst = NULL; uint8 quantity_found = 0; // Check item: After failed checks, check bag contents (if bag) for (it=bucket.begin(); it!=bucket.end(); it++) { inst = it->second; if (inst) { if (inst->GetID() == item_id) { quantity_found += (inst->GetCharges()<=0) ? 1 : inst->GetCharges(); if (quantity_found >= quantity) return it->first; } for(int i = 0; i < MAX_AUGMENT_SLOTS; i++) { if (inst->GetAugmentItemID(i) == item_id && quantity <= 1) return SLOT_AUGMENT; // Only one augment per slot. } } // Go through bag, if bag if (inst && inst->IsType(ItemClassContainer)) { for (itb=inst->_begin(); itb!=inst->_end(); itb++) { ItemInst* baginst = itb->second; if (baginst->GetID() == item_id) { quantity_found += (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges(); if (quantity_found >= quantity) return Inventory::CalcSlotId(it->first, itb->first); } for(int i = 0; i < MAX_AUGMENT_SLOTS; i++) { if (baginst->GetAugmentItemID(i) == item_id && quantity <= 1) return SLOT_AUGMENT; // Only one augment per slot. } } } } // Not found return SLOT_INVALID; }
void Client::ForageItem(bool guarantee) { int skill_level = GetSkill(SkillForage); //be wary of the string ids in switch below when changing this. uint32 common_food_ids[MAX_COMMON_FOOD_IDS] = { 13046, // Fruit 13045, // Berries 13419, // Vegetables 13048, // Rabbit Meat 13047, // Roots 13044, // Pod Of Water 14905, // mushroom 13106 // Fishing Grubs }; // these may need to be fine tuned, I am just guessing here if (guarantee || zone->random.Int(0,199) < skill_level) { uint32 foragedfood = 0; uint32 stringid = FORAGE_NOEAT; if (zone->random.Roll(25)) { foragedfood = database.GetZoneForage(m_pp.zone_id, skill_level); } //not an else in case theres no DB food if(foragedfood == 0) { uint8 index = 0; index = zone->random.Int(0, MAX_COMMON_FOOD_IDS-1); foragedfood = common_food_ids[index]; } const Item_Struct* food_item = database.GetItem(foragedfood); if(!food_item) { LogFile->write(EQEMuLog::Error, "nullptr returned from database.GetItem in ClientForageItem"); return; } if(foragedfood == 13106) stringid = FORAGE_GRUBS; else switch(food_item->ItemType) { case ItemTypeFood: stringid = FORAGE_FOOD; break; case ItemTypeDrink: if(strstr(food_item->Name, "ater")) stringid = FORAGE_WATER; else stringid = FORAGE_DRINK; break; default: break; } Message_StringID(MT_Skills, stringid); ItemInst* inst = database.CreateItem(food_item, 1); if(inst != nullptr) { // check to make sure it isn't a foraged lore item if(CheckLoreConflict(inst->GetItem())) { Message_StringID(0, DUP_LORE); safe_delete(inst); } else { PushItemOnCursor(*inst); SendItemPacket(MainCursor, inst, ItemPacketSummonItem); if(RuleB(TaskSystem, EnableTaskSystem)) UpdateTasksForItem(ActivityForage, foragedfood); safe_delete(inst); inst = m_inv.GetItem(MainCursor); } if(inst) { std::vector<EQEmu::Any> args; args.push_back(inst); parse->EventPlayer(EVENT_FORAGE_SUCCESS, this, "", inst->GetID(), &args); } } int ChanceSecondForage = aabonuses.ForageAdditionalItems + itembonuses.ForageAdditionalItems + spellbonuses.ForageAdditionalItems; if(!guarantee && zone->random.Roll(ChanceSecondForage)) { Message_StringID(MT_Skills, FORAGE_MASTERY); ForageItem(true); } } else { Message_StringID(MT_Skills, FORAGE_FAILED); parse->EventPlayer(EVENT_FORAGE_FAILURE, this, "", 0); } CheckIncreaseSkill(SkillForage, nullptr, 5); }
void Client::GoFish() { //TODO: generate a message if we're already fishing /*if (!fishing_timer.Check()) { //this isn't the right check, may need to add something to the Client class like 'bool is_fishing' Message_StringID(0, ALREADY_FISHING); //You are already fishing! return; }*/ fishing_timer.Disable(); //we're doing this a second time (1st in Client::Handle_OP_Fishing) to make sure that, between when we started fishing & now, we're still able to fish (in case we move, change equip, etc) if (!CanFish()) //if we can't fish here, we don't need to bother with the rest return; //multiple entries yeilds higher probability of dropping... uint32 common_fish_ids[MAX_COMMON_FISH_IDS] = { 1038, // Tattered Cloth Sandals 1038, // Tattered Cloth Sandals 1038, // Tattered Cloth Sandals 13019, // Fresh Fish 13076, // Fish Scales 13076, // Fish Scales 7007, // Rusty Dagger 7007, // Rusty Dagger 7007 // Rusty Dagger }; //success formula is not researched at all int fishing_skill = GetSkill(SkillFishing); //will take into account skill bonuses on pole & bait //make sure we still have a fishing pole on: int32 bslot = m_inv.HasItemByUse(ItemTypeFishingBait, 1, invWhereWorn|invWherePersonal); const ItemInst* Bait = nullptr; if (bslot != INVALID_INDEX) Bait = m_inv.GetItem(bslot); //if the bait isnt equipped, need to add its skill bonus if(bslot >= EmuConstants::GENERAL_BEGIN && Bait->GetItem()->SkillModType == SkillFishing) { fishing_skill += Bait->GetItem()->SkillModValue; } if (fishing_skill > 100) { fishing_skill = 100+((fishing_skill-100)/2); } if (zone->random.Int(0,175) < fishing_skill) { uint32 food_id = 0; //25% chance to fish an item. if (zone->random.Int(0, 399) <= fishing_skill ) { uint32 npc_id = 0; uint8 npc_chance = 0; food_id = database.GetZoneFishing(m_pp.zone_id, fishing_skill, npc_id, npc_chance); //check for add NPC if(npc_chance > 0 && npc_id) { if(npc_chance < zone->random.Int(0, 99)) { const NPCType* tmp = database.GetNPCType(npc_id); if(tmp != nullptr) { NPC* npc = new NPC(tmp, nullptr, GetX()+3, GetY(), GetZ(), GetHeading(), FlyMode3); npc->AddLootTable(); npc->AddToHateList(this, 1, 0, false); //no help yelling entity_list.AddNPC(npc); Message(MT_Emote, "You fish up a little more than you bargained for..."); } } } } //consume bait, should we always consume bait on success? DeleteItemInInventory(bslot, 1, true); //do we need client update? if(food_id == 0) { int index = zone->random.Int(0, MAX_COMMON_FISH_IDS-1); food_id = common_fish_ids[index]; } const Item_Struct* food_item = database.GetItem(food_id); Message_StringID(MT_Skills, FISHING_SUCCESS); ItemInst* inst = database.CreateItem(food_item, 1); if(inst != nullptr) { if(CheckLoreConflict(inst->GetItem())) { Message_StringID(0, DUP_LORE); safe_delete(inst); } else { PushItemOnCursor(*inst); SendItemPacket(MainCursor, inst, ItemPacketSummonItem); if(RuleB(TaskSystem, EnableTaskSystem)) UpdateTasksForItem(ActivityFish, food_id); safe_delete(inst); inst = m_inv.GetItem(MainCursor); } if(inst) { std::vector<EQEmu::Any> args; args.push_back(inst); parse->EventPlayer(EVENT_FISH_SUCCESS, this, "", inst->GetID(), &args); } } } else { //chance to use bait when you dont catch anything... if (zone->random.Int(0, 4) == 1) { DeleteItemInInventory(bslot, 1, true); //do we need client update? Message_StringID(MT_Skills, FISHING_LOST_BAIT); //You lost your bait! } else { if (zone->random.Int(0, 15) == 1) //give about a 1 in 15 chance to spill your beer. we could make this a rule, but it doesn't really seem worth it //TODO: check for & consume an alcoholic beverage from inventory when this triggers, and set it as a rule that's disabled by default Message_StringID(MT_Skills, FISHING_SPILL_BEER); //You spill your beer while bringing in your line. else Message_StringID(MT_Skills, FISHING_FAILED); //You didn't catch anything. } parse->EventPlayer(EVENT_FISH_FAILURE, this, "", 0); } //chance to break fishing pole... //this is potentially exploitable in that they can fish //and then swap out items in primary slot... too lazy to fix right now if (zone->random.Int(0, 49) == 1) { Message_StringID(MT_Skills, FISHING_POLE_BROKE); //Your fishing pole broke! DeleteItemInInventory(MainPrimary, 0, true); } if(CheckIncreaseSkill(SkillFishing, nullptr, 5)) { if(title_manager.IsNewTradeSkillTitleAvailable(SkillFishing, GetRawSkill(SkillFishing))) NotifyNewTitlesAvailable(); } }
uint32 Client::CalcCurrentWeight() { const Item_Struct* TempItem = 0; ItemInst* ins; uint32 Total = 0; int x; for (x = MainCursor; x <= EmuConstants::GENERAL_END; x++) { TempItem = 0; ins = GetInv().GetItem(x); if (ins) TempItem = ins->GetItem(); if (TempItem) Total += TempItem->Weight; ItemInst* baginst = ins; ItemInst* inst; const Item_Struct* Item = 0; if (baginst && baginst->GetItem() && baginst->IsType(ItemClassContainer)) { uint32 bag_weight = 0; int i; for (i = 0; i < baginst->GetItem()->BagSlots; i++) { inst = GetInv().GetItem(m_inv.CalcSlotId(x, i)); if (inst) Item = inst->GetItem(); if (Item) { bag_weight += Item->Weight; } } int reduction = baginst->GetItem()->BagWR; if (reduction > 0 && bag_weight > 0) bag_weight -= bag_weight*reduction/100; Total += bag_weight; } } uint32 coin_weight = (m_pp.platinum + m_pp.gold + m_pp.silver + m_pp.copper) / 4; // Coin purses only work when in a main inventory slot const Item_Struct* CoinItem = 0; ItemInst* cins; uint32 coin_reduction = 0; for (x = EmuConstants::GENERAL_BEGIN; x <= EmuConstants::GENERAL_END; x++) { CoinItem = 0; cins = GetInv().GetItem(x); if (cins && cins->GetID() >= 17201 && cins->GetID() <= 17230) { CoinItem = cins->GetItem(); if(CoinItem) coin_reduction = CoinItem->BagWR > coin_reduction ? CoinItem->BagWR : coin_reduction; } } coin_weight -= coin_weight*coin_reduction/100; Total += coin_weight; float Packrat = (float)spellbonuses.Packrat + (float)aabonuses.Packrat + (float)itembonuses.Packrat; if (Packrat > 0) Total = (uint32)((float)Total * (1.0f - ((Packrat * 1.0f) / 100.0f))); //AndMetal: 1% per level, up to 5% (calculated from Titanium client). verified thru client that it reduces coin weight by the same % //without casting to float & back to uint32, this didn't work right return Total; }