Page 1 of 1

Harvesting bug

Posted: Sat Aug 26, 2017 3:28 am
by Ememjr
finally harvesting T2 in frostfang, i getting glowing material way to often and sometime getting 3, on live you never get more that minimum # of one (old days) or 2 new days
also seems to be trigguring way to often
most likely the RNG but ill turn on some additaonla checks here, and tets and post a fix

Re: Harvesting bug

Posted: Sat Aug 26, 2017 4:15 am
by Ememjr
ok after some digging in the DB found that the imbue item is entered the same way that normal on imbue items are, so that would explain why getting them often and also able to get multiples in a single harvest it glowing material is in the list as rare = 0

i ill work on this, but here is some of the issue

this is in groundspawn.cpp
in this section of code that is checking each item in the groundspawn list means that no item will be award if the rnd of the harvest roll matched imbue
becuase imbue is harvest_type 4 but the groundspawn entry has rare = 0 so we need to identify the imbue in the DB as an imbue

i would also recommend and will change here for testing that the grounspawns items table either
1. add a field for is_imbue or
2. use the is_rare field 1 = rare, 2= imbue item, 3 = something else if we ever decide to have it

then change the code to dish out the proper item based on that

Code: Select all

// if this is a Rare, or an Imbue, but is_rare flag is 0, skip item
					if( (harvest_type == 5 || harvest_type == 4) && entry->is_rare == 0 )
						continue;

Re: Harvesting bug

Posted: Sat Aug 26, 2017 7:17 pm
by Ememjr
here is a fix for the harvesting issues, it fixes the not getting an imbue issue and not getting a single rare issue,
in order for this to work you in ground spawn items the imbue harvest item needs is_rare set to 2

Code: Select all

void GroundSpawn::ProcessHarvest(Client* client)
{
	LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Process harvesting for player '%s' (%u)", client->GetPlayer()->GetName(), client->GetPlayer()->GetID());

	MHarvest.lock();

	vector<GroundSpawnEntry*>* groundspawn_entries = GetZone()->GetGroundSpawnEntries(groundspawn_id);
	vector<GroundSpawnEntryItem*>* groundspawn_items = GetZone()->GetGroundSpawnEntryItems(groundspawn_id);

	Item*	master_item = 0;
	Item*	master_rare = 0;
	Item*	item = 0;
	Item*	item_rare = 0;

	int16	lowest_skill_level = 0;
	int16	table_choice = 0;
	int32	item_choice = 0;
	int32	rare_choice = 0;
	int8	harvest_type = 0;
	int32	item_harvested = 0;
	int8	reward_total = 1;
	int32	rare_harvested = 0;
	int8	rare_item = 0;
	bool	is_collection = false;

	if(!groundspawn_entries || !groundspawn_items) 
	{
		LogWrite(GROUNDSPAWN__ERROR, 3, "GSpawn", "No groundspawn entries or items assigned to groundspawn id: %u", groundspawn_id);
		client->Message(CHANNEL_COLOR_RED, "Error: There are no groundspawn entries or items assigned to groundspawn id: %u", groundspawn_id);
		MHarvest.unlock();
		return;
	}

	if(number_harvests == 0) 
	{
		LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Total harvests depleated for groundspawn id: %u", groundspawn_id);
		client->SimpleMessage(CHANNEL_COLOR_RED, "Error: This spawn has nothing more to harvest!");
		MHarvest.unlock();
		return;
	}

	Skill* skill = 0;
	if (collection_skill == "Collecting")
	{
		skill = client->GetPlayer()->GetSkillByName("Gathering");
		is_collection = true;
	}
	else
		skill = client->GetPlayer()->GetSkillByName(collection_skill.c_str(), true);
	if(!skill) 
	{
		LogWrite(GROUNDSPAWN__WARNING, 3, "GSpawn", "Player '%s' lacks the skill: '%s'", client->GetPlayer()->GetName(), collection_skill.c_str());
		client->Message(CHANNEL_COLOR_RED, "Error: You do not have the '%s' skill!", collection_skill.c_str());
		MHarvest.unlock();
		return;
	}

	for(int8 i=0;i<num_attempts_per_harvest; i++) 
	{
		vector<GroundSpawnEntry*> mod_groundspawn_entries;

		if(groundspawn_entries) 
		{
			vector<GroundSpawnEntry*> highest_match;
			vector<GroundSpawnEntry*>::iterator itr;

			GroundSpawnEntry* entry = 0;			// current data
			GroundSpawnEntry* selected_table = 0;	// selected table data

			// first, iterate through groundspawn_entries, discard tables player cannot use
			for(itr = groundspawn_entries->begin(); itr != groundspawn_entries->end(); itr++) 
			{
				entry = *itr;

				// if player lacks skill, skip table
				if( entry->min_skill_level > skill->current_val ) 
					continue;
				// if bonus, but player lacks level, skip table
				if( entry->bonus_table && (client->GetPlayer()->GetLevel() < entry->min_adventure_level) )
					continue;

				// build modified entries table
				mod_groundspawn_entries.push_back(entry);
				LogWrite(GROUNDSPAWN__DEBUG, 5, "GSpawn", "Keeping groundspawn_entry: %i", entry->min_skill_level);
			}

			// if anything remains, find lowest min_skill_level in remaining set(s)
			if(mod_groundspawn_entries.size() > 0) 
			{
				vector<GroundSpawnEntry*>::iterator itr;
				GroundSpawnEntry* entry = 0;

				for(itr = mod_groundspawn_entries.begin(); itr != mod_groundspawn_entries.end(); itr++) 
				{
					entry = *itr;

					// find the low range of available tables for random roll
					if(lowest_skill_level > entry->min_skill_level || lowest_skill_level == 0)
						lowest_skill_level = entry->min_skill_level;
				}
				LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Lowest Skill Level: %i", lowest_skill_level);
			}
			else
			{
				// if no tables chosen, you must lack the skills
				// TODO: move this check to LUA when harvest command is first selected
				client->Message(CHANNEL_COLOR_RED, "You lack the skills to harvest this node!");
				LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "All groundspawn_entry tables tossed! No Skills? Something broke?");
				MHarvest.unlock();
				return;
			}

			// now roll to see which table to use
			table_choice = MakeRandomInt(lowest_skill_level, skill->current_val);
			LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Random INT for Table by skill level: %i", table_choice);

			int16 highest_score = 0;
			for(itr = mod_groundspawn_entries.begin(); itr != mod_groundspawn_entries.end(); itr++) 
			{
				entry = *itr;

				// determines the highest min_skill_level in the current set of tables (if multiple tables)
				if(table_choice >= entry->min_skill_level && (highest_score == 0 || highest_score < table_choice))
				{
					// removes old highest for the new one
					highest_match.clear();
					highest_score = entry->min_skill_level;
				}
				// if the score = level, push into highest_match set
				if(highest_score == entry->min_skill_level)
					highest_match.push_back(entry);
			}

			// if there is STILL more than 1 table player qualifies for, rand() and pick one
			if(highest_match.size() > 1){
				int16 rand_index = rand()%highest_match.size();
				selected_table = highest_match.at(rand_index);
			}
			else if(highest_match.size() > 0)
				selected_table = highest_match.at(0);

			// by this point, we should have 1 table who's min skill matches the score (selected_table)
			if(selected_table)
			{
				LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Using Table: %i, %i, %i, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %i", 
					selected_table->min_skill_level,
					selected_table->min_adventure_level,
					selected_table->bonus_table,
					selected_table->harvest1,
					selected_table->harvest3,
					selected_table->harvest5,
					selected_table->harvest_imbue,
					selected_table->harvest_rare,
					selected_table->harvest10,
					selected_table->harvest_coin);


				// roll 1-100 for chance-to-harvest percentage
				float chance = MakeRandomFloat(0, 100);
				LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Random FLOAT for harvest percentages: %.2f", chance);

				// starting with the lowest %, select a harvest type + reward qty
				if(chance <= selected_table->harvest10 && is_collection == false) 
				{
					LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Harvest 10 items + Rare Item from table : %i", selected_table->min_skill_level);
					harvest_type = 6;
					reward_total = 10;
				}
				else if(chance <= selected_table->harvest_rare && is_collection == false) 
				{
					LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Harvest Rare Item from table : %i", selected_table->min_skill_level);
					harvest_type = 5;
				}
				else if(chance <= selected_table->harvest_imbue && is_collection == false) 
				{
					LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Harvest Imbue Item from table : %i", selected_table->min_skill_level);
					harvest_type = 4;
				}
				else if(chance <= selected_table->harvest5 && is_collection == false) 
				{
					LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Harvest 5 Items from table : %i", selected_table->min_skill_level);
					harvest_type = 3;
					reward_total = 5;
				}
				else if(chance <= selected_table->harvest3 && is_collection == false) 
				{
					LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Harvest 3 Items from table : %i", selected_table->min_skill_level);
					harvest_type = 2;
					reward_total = 3;
				}
				else if( chance <= selected_table->harvest1 || skill->current_val == skill->max_val || is_collection ) 
				{
					LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Harvest 1 Item from table : %i", selected_table->min_skill_level);
					harvest_type = 1;
				}
				else
					LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Harvest nothing...");
			}

			// once you know how many and what type of item to harvest, pick an item from the list
			if(harvest_type) 
			{
				vector<GroundSpawnEntryItem*> mod_groundspawn_items;
				vector<GroundSpawnEntryItem*> mod_groundspawn_rares;
				vector<GroundSpawnEntryItem*> mod_groundspawn_imbue;

				vector<GroundSpawnEntryItem*>::iterator itr;
				GroundSpawnEntryItem* entry = 0;

				// iterate through groundspawn_items, discard items player cannot roll for
				for(itr = groundspawn_items->begin(); itr != groundspawn_items->end(); itr++) 
				{
					entry = *itr;

					// if this is a Rare, or an Imbue, but is_rare flag is 0, skip item
					if( (harvest_type == 5 || harvest_type == 4) && entry->is_rare == 0 )
						continue;
					// if it is a 1, 3, or 5 and is_rare = 1, skip
					else if( harvest_type < 4 && entry->is_rare == 1 )
						continue;

					// if the grid_id on the item matches player grid, or is 0, keep the item
					if( !entry->grid_id || (entry->grid_id == client->GetPlayer()->appearance.pos.grid_id) )
					{
						// build modified entries table
						if ((entry->is_rare == 1 && harvest_type == 5) || (entry->is_rare == 1 && harvest_type == 6))
						{
							// if the matching item is rare, or harvest10 push to mod rares
							mod_groundspawn_rares.push_back(entry);
							LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Keeping groundspawn_rare_item: %u", entry->item_id);
						}
						if (entry->is_rare == 0 && harvest_type != 4 && harvest_type != 5)
						{
							// if the matching item is normal,or harvest 10 push to mod items
							mod_groundspawn_items.push_back(entry);
							LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Keeping groundspawn_common_item: %u", entry->item_id);
						}
						if (entry->is_rare == 2 && harvest_type == 4)
						 {
							 // if the matching item is imbue item, push to mod imbue
							 mod_groundspawn_imbue.push_back(entry);
							 LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Keeping groundspawn_imbue_item: %u", entry->item_id);
						 }
					}
				}

				// if any items remain in the list, random to see which one gets awarded
				if(mod_groundspawn_items.size() > 0) 
				{
					// roll to see which item index to use
					item_choice = rand()%mod_groundspawn_items.size();
					LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Random INT for which item to award: %i", item_choice);

					// set item_id to be awarded
					item_harvested = mod_groundspawn_items[item_choice]->item_id;

					// if reward is rare, set flag
					rare_item = mod_groundspawn_items[item_choice]->is_rare;

					LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Item ID to award: %u, Rare = %i", item_harvested, item_rare);

					// if 10+rare, handle additional "rare" reward
					if( harvest_type == 6 )
					{
						// make sure there is a rare table to choose from!
						if( mod_groundspawn_rares.size() > 0 ) 
						{
							// roll to see which rare index to use
							rare_choice = rand()%mod_groundspawn_rares.size();

							// set (rare) item_id to be awarded 
							rare_harvested = mod_groundspawn_rares[rare_choice]->item_id;

							// we're picking a rare here, so obviously this is true ;)
							rare_item = 1;

							LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "RARE Item ID to award: %u", rare_harvested);
						}
						else
						{
							// all rare entries were eliminated above, or none are assigned. Either way, shouldn't be here!
							LogWrite(GROUNDSPAWN__ERROR, 3, "GSpawn", "Groundspawn Entry for '%s' (%i) has no RARE items!", GetName(), GetID());
						}
					}
				}
				else if (mod_groundspawn_rares.size() > 0)
				{
					// roll to see which rare index to use
					item_choice = rand() % mod_groundspawn_rares.size();

					// set (rare) item_id to be awarded 
					item_harvested = mod_groundspawn_rares[item_choice]->item_id;

					// we're picking a rare here, so obviously this is true ;)
					rare_item = 1;

					LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "RARE Item ID to award: %u", rare_harvested);
				}
				else if (mod_groundspawn_imbue.size() > 0)
				{
					// roll to see which rare index to use
					item_choice = rand() % mod_groundspawn_imbue.size();

					// set (rare) item_id to be awarded 
					item_harvested = mod_groundspawn_imbue[item_choice]->item_id;

					// we're picking a rare here, so obviously this is true ;)
					rare_item = 0;

					LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "imbue Item ID to award: %u", rare_harvested);
				}




				else
				{
					// all item entries were eliminated above, or none are assigned. Either way, shouldn't be here!
					LogWrite(GROUNDSPAWN__ERROR, 0, "GSpawn", "Groundspawn Entry for '%s' (%i) has no items!", GetName(), GetID());
				}
				
				// if an item was harvested, send updates to client, add item to inventory
				if(item_harvested)
				{
					char tmp[200] = {0};

					// set Normal item harvested
					master_item = master_item_list.GetItem(item_harvested);
					if(master_item)
					{
						// set details of Normal item
						item = new Item(master_item);
						// set how many of this item the player receives
						item->details.count = reward_total;

						// chat box update for normal item (todo: verify output text)
						client->Message(CHANNEL_COLOR_HARVEST, "You %s %i \\aITEM %u %u:%s\\/a from the %s.", GetHarvestMessageName(true).c_str(), item->details.count, item->details.item_id, item->details.unique_id, item->name.c_str(), GetName());
						// add Normal item to player inventory
						client->AddItem(item);
						//Check if the player has a harvesting quest for this
						client->GetPlayer()->CheckQuestsHarvestUpdate(item, reward_total);



						// if this is a 10+rare, handle sepErately
						if(harvest_type == 6 && rare_item == 1)
						{
							LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Item ID %u is Normal. Qty %i", item_harvested, item->details.count);

							// send Normal harvest message to client
							sprintf(tmp, "\\#64FFFFYou have %s:\12\\#C8FFFF%i %s", GetHarvestMessageName().c_str(), item->details.count, item->name.c_str());
							client->SendPopupMessage(10, tmp, "ui_harvested_normal", 2.25, 0xFF, 0xFF, 0xFF);
							client->GetPlayer()->UpdatePlayerStatistic(STAT_PLAYER_ITEMS_HARVESTED, item->details.count);

							// set Rare item harvested
							master_rare = master_item_list.GetItem(rare_harvested);
							if(master_rare)
							{
								// set details of Rare item
								item_rare = new Item(master_rare);
								// count of Rare is always 1
								item_rare->details.count = 1;

								LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Item ID %u is RARE!", rare_harvested);

								// send Rare harvest message to client
								sprintf(tmp, "\\#FFFF6ERare item found!\12%s: \\#C8FFFF%i %s", GetHarvestMessageName().c_str(), item_rare->details.count, item_rare->name.c_str());
								client->Message(CHANNEL_COLOR_HARVEST, "You have found a rare item!");
								client->SendPopupMessage(11, tmp, "ui_harvested_rare", 2.25, 0xFF, 0xFF, 0xFF);
								client->GetPlayer()->UpdatePlayerStatistic(STAT_PLAYER_RARES_HARVESTED, item_rare->details.count);

								// chat box update for rare item (todo: verify output text)
								client->Message(CHANNEL_COLOR_HARVEST, "You %s %i \\aITEM %u %u:%s\\/a from the %s.", GetHarvestMessageName(true).c_str(), item_rare->details.count, item_rare->details.item_id, item_rare->details.unique_id, item_rare->name.c_str(), GetName());
								// add Rare item to player inventory
								client->AddItem(item_rare);
								//Check if the player has a harvesting quest for this
								client->GetPlayer()->CheckQuestsHarvestUpdate(item_rare, 1);
							}
						}
						else if(rare_item == 1)	
						{
							// if harvest signaled rare or imbue type
							LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Item ID %u is RARE! Qty: %i", item_harvested, item->details.count);

							// send Rare harvest message to client
							sprintf(tmp, "\\#FFFF6ERare item found!\12%s: \\#C8FFFF%i %s", GetHarvestMessageName().c_str(), item->details.count, item->name.c_str());
							client->Message(CHANNEL_COLOR_HARVEST, "You have found a rare item!");
							client->SendPopupMessage(11, tmp, "ui_harvested_rare", 2.25, 0xFF, 0xFF, 0xFF);
							client->GetPlayer()->UpdatePlayerStatistic(STAT_PLAYER_RARES_HARVESTED, item->details.count);
						}
						else
						{
							// send Normal harvest message to client
							LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Item ID %u is Normal. Qty %i", item_harvested, item->details.count);
							sprintf(tmp, "\\#64FFFFYou have %s:\12\\#C8FFFF%i %s", GetHarvestMessageName().c_str(), item->details.count, item->name.c_str());
							client->SendPopupMessage(10, tmp, "ui_harvested_normal", 2.25, 0xFF, 0xFF, 0xFF);
							client->GetPlayer()->UpdatePlayerStatistic(STAT_PLAYER_ITEMS_HARVESTED, item->details.count);
						}
						
					}
					else
					{
						// error!
						LogWrite(GROUNDSPAWN__ERROR, 0, "GSpawn", "Error: Item ID Not Found - %u", item_harvested);
						client->Message(CHANNEL_COLOR_RED, "Error: Unable to find item id %u", item_harvested);
					}
					// decrement # of pulls on this node before it despawns
					number_harvests--;
				}
				else
				{
					// if no item harvested
					LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "No item_harvested");
					client->Message(CHANNEL_COLOR_HARVEST, "You failed to %s anything from %s.", GetHarvestMessageName(true, true).c_str(), GetName());
				}
			}
			else
			{
				// if no harvest type
				LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "No harvest_type");
				client->Message(CHANNEL_COLOR_HARVEST, "You failed to %s anything from %s.", GetHarvestMessageName(true, true).c_str(), GetName());
			}
		}
	} // cycle through num_attempts_per_harvest
	MHarvest.unlock();

	LogWrite(GROUNDSPAWN__DEBUG, 0, "GSpawn", "Process harvest complete for player '%s' (%u)", client->GetPlayer()->GetName(), client->GetPlayer()->GetID());
}

Re: Harvesting bug

Posted: Thu Nov 23, 2017 4:54 pm
by Jabantiz
Committed to dev svn.


Side not I noticed in the GroundSpawnEntryItem struct is_rare was an int32, changed it to an int8