void Client::ForageItem(bool guarantee) { int skill_level = GetSkill(EQEmu::skills::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 EQEmu::ItemData* food_item = database.GetItem(foragedfood); if(!food_item) { Log.Out(Logs::General, Logs::Error, "nullptr returned from database.GetItem in ClientForageItem"); return; } if(foragedfood == 13106) stringid = FORAGE_GRUBS; else switch(food_item->ItemType) { case EQEmu::item::ItemTypeFood: stringid = FORAGE_FOOD; break; case EQEmu::item::ItemTypeDrink: if(strstr(food_item->Name, "ater")) stringid = FORAGE_WATER; else stringid = FORAGE_DRINK; break; default: break; } Message_StringID(MT_Skills, stringid); EQEmu::ItemInstance* 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(EQEmu::inventory::slotCursor, inst, ItemPacketLimbo); if(RuleB(TaskSystem, EnableTaskSystem)) UpdateTasksForItem(ActivityForage, foragedfood); safe_delete(inst); inst = m_inv.GetItem(EQEmu::inventory::slotCursor); } 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(EQEmu::skills::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(EQEmu::skills::SkillFishing); //will take into account skill bonuses on pole & bait //make sure we still have a fishing pole on: int32 bslot = m_inv.HasItemByUse(EQEmu::item::ItemTypeFishingBait, 1, invWhereWorn | invWherePersonal); const EQEmu::ItemInstance* Bait = nullptr; if (bslot != INVALID_INDEX) Bait = m_inv.GetItem(bslot); //if the bait isnt equipped, need to add its skill bonus if (bslot >= EQEmu::legacy::GENERAL_BEGIN && Bait != nullptr && Bait->GetItem()->SkillModType == EQEmu::skills::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.LoadNPCTypesData(npc_id); if(tmp != nullptr) { auto positionNPC = GetPosition(); positionNPC.x = positionNPC.x + 3; auto npc = new NPC(tmp, nullptr, positionNPC, 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 EQEmu::ItemData* food_item = database.GetItem(food_id); Message_StringID(MT_Skills, FISHING_SUCCESS); EQEmu::ItemInstance* 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(EQEmu::inventory::slotCursor, inst, ItemPacketLimbo); if(RuleB(TaskSystem, EnableTaskSystem)) UpdateTasksForItem(ActivityFish, food_id); safe_delete(inst); inst = m_inv.GetItem(EQEmu::inventory::slotCursor); } 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(EQEmu::inventory::slotPrimary, 0, true); } if (CheckIncreaseSkill(EQEmu::skills::SkillFishing, nullptr, 5)) { if (title_manager.IsNewTradeSkillTitleAvailable(EQEmu::skills::SkillFishing, GetRawSkill(EQEmu::skills::SkillFishing))) NotifyNewTitlesAvailable(); } }