Beispiel #1
0
// Internal Method: Checks an inventory queue type bucket for a particular item
sint16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, 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 && inst->IsType(ItemClassCommon) && inst->GetItem()->ItemType == use) {
			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 && baginst->IsType(ItemClassCommon) && baginst->GetItem()->ItemType == use) {
					quantity_found += (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges();
					if (quantity_found >= quantity)
						return Inventory::CalcSlotId(SLOT_CURSOR, itb->first);
				}
			}
		}
	}
	
	// Not found
	return SLOT_INVALID;
}
Beispiel #2
0
// Retrieve item at specified slot; returns false if item not found
ItemInst* Inventory::GetItem(int16 slot_id) const
{
	ItemInst* result = nullptr;

	// Cursor
	if (slot_id == SLOT_CURSOR) {
		// Cursor slot
		result = m_cursor.peek_front();
	}

	// Non bag slots
	else if (slot_id >= 3000 && slot_id <= 3007) {
		// Trade slots
		result = _GetItem(m_trade, slot_id);
	}
	else if (slot_id >= 2000 && slot_id <= 2007) {
		// Bank slots
		result = _GetItem(m_bank, slot_id);
	}
	else if ((slot_id >= 22 && slot_id <= 29)) {
		// Personal inventory slots
		result = _GetItem(m_inv, slot_id);
	}
	else if ((slot_id >= 1 && slot_id <= 21)) {
		// Equippable slots (on body)
		result = _GetItem(m_worn, slot_id);
	}

	// Trade bag slots
	else if (slot_id >= 3030 && slot_id <= 3109) {
		// Trade bag slots
		ItemInst* inst = _GetItem(m_trade, Inventory::CalcSlotId(slot_id));
		if (inst && inst->IsType(ItemClassContainer)) {
			result = inst->GetItem(Inventory::CalcBagIdx(slot_id));
		}
	}
	else if (slot_id >= 2030 && slot_id <= 2109) {
		// Bank bag slots
		ItemInst* inst = _GetItem(m_bank, Inventory::CalcSlotId(slot_id));
		if (inst && inst->IsType(ItemClassContainer)) {
			result = inst->GetItem(Inventory::CalcBagIdx(slot_id));
		}
	}
	else if (slot_id >= 330 && slot_id <= 339) {
		// Cursor bag slots
		ItemInst* inst = m_cursor.peek_front();
		if (inst && inst->IsType(ItemClassContainer)) {
			result = inst->GetItem(Inventory::CalcBagIdx(slot_id));
		}
	}
	else if (slot_id >= 250 && slot_id <= 329) {
		// Personal inventory bag slots
		ItemInst* inst = _GetItem(m_inv, Inventory::CalcSlotId(slot_id));
		if (inst && inst->IsType(ItemClassContainer)) {
			result = inst->GetItem(Inventory::CalcBagIdx(slot_id));
		}
	}

	return result;
}
Beispiel #3
0
// Internal Method: Checks an inventory bucket for a particular item
sint16 Inventory::_HasItemByUse(map<sint16, ItemInst*>& bucket, uint8 use, 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 && inst->IsType(ItemClassCommon) && inst->GetItem()->ItemType == use) {
			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 && baginst->IsType(ItemClassCommon) && baginst->GetItem()->ItemType == use) {
					quantity_found += (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges();
					if (quantity_found >= quantity)
						return Inventory::CalcSlotId(it->first, itb->first);
				}
			}
		}
	}
	
	// Not found
	return SLOT_INVALID;
}
Beispiel #4
0
// Internal Method: Checks an inventory queue type bucket for a particular item
int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup)
{
	iter_queue it;
	iter_contents itb;

	// Read-only iteration of queue
	for (it = iqueue.begin(); it != iqueue.end(); ++it) {
		ItemInst* inst = *it;
		if (inst)
		{
			if (inst->GetItem()->LoreGroup == loregroup)
				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 && baginst->IsType(ItemClassCommon) && baginst->GetItem()->LoreGroup == loregroup)
					return Inventory::CalcSlotId(SLOT_CURSOR, itb->first);
			}
		}
	}

	// Not found
	return SLOT_INVALID;
}
Beispiel #5
0
int16 Inventory::_HasItemByLoreGroup(std::map<int16, ItemInst*>& bucket, uint32 loregroup)
{
	iter_inst it;
	iter_contents itb;
	ItemInst* inst = nullptr;

	// 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->GetItem()->LoreGroup == loregroup)
				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 && baginst->IsType(ItemClassCommon) && baginst->GetItem()->LoreGroup == loregroup)
					return Inventory::CalcSlotId(it->first, itb->first);

			}
		}
	}

	// Not found
	return SLOT_INVALID;
}
Beispiel #6
0
// Checks All items in a bag for No Drop
bool Inventory::CheckNoDrop(sint16 slot_id) {
    ItemInst* inst = GetItem(slot_id);
	if (!inst) return false;
	if (!inst->GetItem()->NoDrop) return true;
	if (inst->GetItem()->ItemClass == 1) {
		for (int16 i=0; i<10; i++) {
			ItemInst* bagitem = GetItem(Inventory::CalcSlotId(slot_id, i));
			if (bagitem && !bagitem->GetItem()->NoDrop) return true;
		}
	}
	return false;
}
Beispiel #7
0
// Remove all items from container
void ItemInst::ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent)
{
	// Destroy container contents
	iter_contents cur, end, del;
	cur = m_contents.begin();
	end = m_contents.end();
	for (; cur != end;) {
		ItemInst* inst = cur->second;
		const Item_Struct* item = inst->GetItem();
		del = cur;
		++cur;

		switch (is_nodrop) {
		case byFlagSet:
			if (item->NoDrop == 0) {
				safe_delete(inst);
				m_contents.erase(del->first);
				continue;
			}
		default:
			break;
		}

		switch (is_norent) {
		case byFlagSet:
			if (item->NoRent == 0) {
				safe_delete(inst);
				m_contents.erase(del->first);
				continue;
			}
		default:
			break;
		}
	}
}
Beispiel #8
0
void Inventory::dumpBagContents(ItemInst *inst, iter_inst *it) {
	iter_contents itb;

	if (!inst || !inst->IsType(ItemClassContainer))
		return;

	// Go through bag, if bag
	for (itb=inst->_begin(); itb!=inst->_end(); ++itb) {
		ItemInst* baginst = itb->second;
		if(!baginst || !baginst->GetItem())
			continue;

		std::string subSlot;
		StringFormat(subSlot,"	Slot %d: %s (%d)", Inventory::CalcSlotId((*it)->first, itb->first),
			baginst->GetItem()->Name, (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges());
		std::cout << subSlot << std::endl;
	}

}
Beispiel #9
0
// Internal Method: Checks an inventory queue type bucket for a particular item
sint16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup)
{
	iter_queue it;
	iter_contents itb;
	
	// Read-only iteration of queue
	for (it=iqueue.begin(); it!=iqueue.end(); it++) {
		ItemInst* inst = *it;
		if (inst)
		{
			if (inst->GetItem()->LoreGroup == loregroup) 
				return SLOT_CURSOR;
			
			ItemInst* Aug;
			for(int i = 0; i < MAX_AUGMENT_SLOTS; i++) {
				Aug = inst->GetAugment(i);
				if (Aug && Aug->GetItem()->LoreGroup == loregroup)
					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 && baginst->IsType(ItemClassCommon)&& baginst->GetItem()->LoreGroup == loregroup) 
					return Inventory::CalcSlotId(SLOT_CURSOR, itb->first);
				
				
				ItemInst* Aug2;
				for(int i = 0; i < MAX_AUGMENT_SLOTS; i++) {
					Aug2 = baginst->GetAugment(i);
					if (Aug2 && Aug2->GetItem()->LoreGroup == loregroup)
						return SLOT_AUGMENT; // Only one augment per slot.
				}

			}
		}
	}
	
	// Not found
	return SLOT_INVALID;
}
Beispiel #10
0
sint16 Inventory::_HasItemByLoreGroup(map<sint16, ItemInst*>& bucket, uint32 loregroup) 
{
	iter_inst it;
	iter_contents itb;
	ItemInst* inst = NULL;
		
	// 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->GetItem()->LoreGroup == loregroup) 
				return it->first;
				
			ItemInst* Aug;
			for(int i = 0; i < MAX_AUGMENT_SLOTS; i++) {
				Aug = inst->GetAugment(i);
				if (Aug && Aug->GetItem()->LoreGroup == loregroup)
					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 && baginst->IsType(ItemClassCommon)&& baginst->GetItem()->LoreGroup == loregroup) 
					return Inventory::CalcSlotId(it->first, itb->first);
				
				ItemInst* Aug2;
				for(int i = 0; i < MAX_AUGMENT_SLOTS; i++) {
					Aug2 = baginst->GetAugment(i);
					if (Aug2 && Aug2->GetItem()->LoreGroup == loregroup)
						return SLOT_AUGMENT; // Only one augment per slot.
				}
			}
		}
	}
	
	// Not found
	return SLOT_INVALID;
}
Beispiel #11
0
void Inventory::dumpItemCollection(const std::map<int16, ItemInst*> &collection) {
	iter_inst it;
	iter_contents itb;
	ItemInst* inst = nullptr;
	
	for (it=collection.begin(); it!=collection.end(); ++it) {
		inst = it->second;
		if(!inst || !inst->GetItem())
			continue;
		
		std::string slot;
		StringFormat(slot, "Slot %d: %s (%d)",it->first, it->second->GetItem()->Name, (inst->GetCharges()<=0) ? 1 : inst->GetCharges());
		std::cout << slot << std::endl;		

		dumpBagContents(inst, &it);
	}
}
Beispiel #12
0
void Inventory::dumpInventory() {
	iter_inst it;
	iter_contents itb;
	ItemInst* inst = NULL;
	
	// Check item: After failed checks, check bag contents (if bag)
	printf("Worn items:\n");
	for (it=m_worn.begin(); it!=m_worn.end(); it++) {
		inst = it->second;
		it->first;
		if(!inst || !inst->GetItem())
			continue;
		
		printf("Slot %d: %s (%d)\n", it->first, it->second->GetItem()->Name, (inst->GetCharges()<=0) ? 1 : inst->GetCharges());
		
		// Go through bag, if bag
		if (inst && inst->IsType(ItemClassContainer)) {
			for (itb=inst->_begin(); itb!=inst->_end(); itb++) {
				ItemInst* baginst = itb->second;
				if(!baginst || !baginst->GetItem())
					continue;
				printf("	Slot %d: %s (%d)\n", Inventory::CalcSlotId(it->first, itb->first),
						baginst->GetItem()->Name, (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges());
			}
		}
	}
	
	printf("Inventory items:\n");
	for (it=m_inv.begin(); it!=m_inv.end(); it++) {
		inst = it->second;
		it->first;
		if(!inst || !inst->GetItem())
			continue;
		
		printf("Slot %d: %s (%d)\n", it->first, it->second->GetItem()->Name, (inst->GetCharges()<=0) ? 1 : inst->GetCharges());
		
		// Go through bag, if bag
		if (inst && inst->IsType(ItemClassContainer)) {
			for (itb=inst->_begin(); itb!=inst->_end(); itb++) {
				ItemInst* baginst = itb->second;
				if(!baginst || !baginst->GetItem())
					continue;
				printf("	Slot %d: %s (%d)\n", Inventory::CalcSlotId(it->first, itb->first),
							baginst->GetItem()->Name, (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges());
				
			}
		}
	}
	
	printf("Bank items:\n");
	for (it=m_bank.begin(); it!=m_bank.end(); it++) {
		inst = it->second;
		it->first;
		if(!inst || !inst->GetItem())
			continue;
		
		printf("Slot %d: %s (%d)\n", it->first, it->second->GetItem()->Name, (inst->GetCharges()<=0) ? 1 : inst->GetCharges());
		
		// Go through bag, if bag
		if (inst && inst->IsType(ItemClassContainer)) {
			
			for (itb=inst->_begin(); itb!=inst->_end(); itb++) {
				ItemInst* baginst = itb->second;
				if(!baginst || !baginst->GetItem())
					continue;
				printf("	Slot %d: %s (%d)\n", Inventory::CalcSlotId(it->first, itb->first),
						baginst->GetItem()->Name, (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges());
				
			}
		}
	}
	
	printf("Shared Bank items:\n");
	for (it=m_shbank.begin(); it!=m_shbank.end(); it++) {
		inst = it->second;
		it->first;
		if(!inst || !inst->GetItem())
			continue;
		
		printf("Slot %d: %s (%d)\n", it->first, it->second->GetItem()->Name, (inst->GetCharges()<=0) ? 1 : inst->GetCharges());
		
		// Go through bag, if bag
		if (inst && inst->IsType(ItemClassContainer)) {
			
			for (itb=inst->_begin(); itb!=inst->_end(); itb++) {
				ItemInst* baginst = itb->second;
				if(!baginst || !baginst->GetItem())
					continue;
				printf("	Slot %d: %s (%d)\n", Inventory::CalcSlotId(it->first, itb->first),
						baginst->GetItem()->Name, (baginst->GetCharges()<=0) ? 1 : baginst->GetCharges());
				
			}
		}
	}
	
	printf("\n");
	fflush(stdout);
}
Beispiel #13
0
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;
}
Beispiel #14
0
void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
	/* This gets sent no matter what as a sort of ACK */
	client->QueuePacket(app);

	if (!loot_cooldown_timer.Check()) {
		SendEndLootErrorPacket(client);
		//unlock corpse for others
		if (this->being_looted_by = client->GetID()) {
			being_looted_by = 0xFFFFFFFF;
		}
		return;
	}

	/* To prevent item loss for a player using 'Loot All' who doesn't have inventory space for all their items. */
	if (RuleB(Character, CheckCursorEmptyWhenLooting) && !client->GetInv().CursorEmpty()) {
		client->Message(13, "You may not loot an item while you have an item on your cursor.");
		SendEndLootErrorPacket(client);
		/* Unlock corpse for others */
		if (this->being_looted_by = client->GetID()) {
			being_looted_by = 0xFFFFFFFF;
		}
		return;
	}

	LootingItem_Struct* lootitem = (LootingItem_Struct*)app->pBuffer;

	if (this->being_looted_by != client->GetID()) {
		client->Message(13, "Error: Corpse::LootItem: BeingLootedBy != client");
		SendEndLootErrorPacket(client);
		return;
	}
	if (IsPlayerCorpse() && !CanPlayerLoot(client->CharacterID()) && !become_npc && (char_id != client->CharacterID() && client->Admin() < 150)) {
		client->Message(13, "Error: This is a player corpse and you dont own it.");
		SendEndLootErrorPacket(client);
		return;
	}
	if (is_locked && client->Admin() < 100) {
		SendLootReqErrorPacket(client, 0);
		client->Message(13, "Error: Corpse locked by GM.");
		return;
	}
	if (IsPlayerCorpse() && (char_id != client->CharacterID()) && CanPlayerLoot(client->CharacterID()) && GetPlayerKillItem() == 0){
		client->Message(13, "Error: You cannot loot any more items from this corpse.");
		SendEndLootErrorPacket(client);
		being_looted_by = 0xFFFFFFFF;
		return;
	}
	const Item_Struct* item = 0;
	ItemInst *inst = 0;
	ServerLootItem_Struct* item_data = nullptr, *bag_item_data[10];

	memset(bag_item_data, 0, sizeof(bag_item_data));
	if (GetPlayerKillItem() > 1){
		item = database.GetItem(GetPlayerKillItem());
	}
	else if (GetPlayerKillItem() == -1 || GetPlayerKillItem() == 1){
		item_data = GetItem(lootitem->slot_id - EmuConstants::CORPSE_BEGIN); //dont allow them to loot entire bags of items as pvp reward
	}
	else{
		item_data = GetItem(lootitem->slot_id - EmuConstants::CORPSE_BEGIN, bag_item_data);
	}

	if (GetPlayerKillItem()<=1 && item_data != 0) {
		item = database.GetItem(item_data->item_id);
	}

	if (item != 0) {
		if (item_data){ 
			inst = database.CreateItem(item, item_data ? item_data->charges : 0, item_data->aug_1, item_data->aug_2, item_data->aug_3, item_data->aug_4, item_data->aug_5, item_data->aug_6, item_data->attuned);
		}
		else {
			inst = database.CreateItem(item);
		}
	}

	if (client && inst) {
		if (client->CheckLoreConflict(item)) {
			client->Message_StringID(0, LOOT_LORE_ERROR);
			SendEndLootErrorPacket(client);
			being_looted_by = 0;
			delete inst;
			return;
		}

		if (inst->IsAugmented()) {
			for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
				ItemInst *itm = inst->GetAugment(i);
				if (itm) {
					if (client->CheckLoreConflict(itm->GetItem())) {
						client->Message_StringID(0, LOOT_LORE_ERROR);
						SendEndLootErrorPacket(client);
						being_looted_by = 0;
						delete inst;
						return;
					}
				}
			}
		}

		char buf[88];
		char corpse_name[64];
		strcpy(corpse_name, corpse_name);
		snprintf(buf, 87, "%d %d %s", inst->GetItem()->ID, inst->GetCharges(), EntityList::RemoveNumbers(corpse_name));
		buf[87] = '\0';
		std::vector<EQEmu::Any> args;
		args.push_back(inst);
		args.push_back(this);
		parse->EventPlayer(EVENT_LOOT, client, buf, 0, &args);
		parse->EventItem(EVENT_LOOT, client, inst, this, buf, 0);

		if (!IsPlayerCorpse() && RuleB(Character, EnableDiscoveredItems)) {
			if (client && !client->GetGM() && !client->IsDiscovered(inst->GetItem()->ID))
				client->DiscoverItem(inst->GetItem()->ID);
		}

		if (zone->adv_data) {
			ServerZoneAdventureDataReply_Struct *ad = (ServerZoneAdventureDataReply_Struct*)zone->adv_data;
			if (ad->type == Adventure_Collect && !IsPlayerCorpse()) {
				if (ad->data_id == inst->GetItem()->ID) {
					zone->DoAdventureCountIncrease();
				}
			}
		}

		/* First add it to the looter - this will do the bag contents too */
		if (lootitem->auto_loot) {
			if (!client->AutoPutLootInInventory(*inst, true, true, bag_item_data))
				client->PutLootInInventory(MainCursor, *inst, bag_item_data);
		}
		else {
			client->PutLootInInventory(MainCursor, *inst, bag_item_data);
		}

		/* Update any tasks that have an activity to loot this item */
		if (RuleB(TaskSystem, EnableTaskSystem))
			client->UpdateTasksForItem(ActivityLoot, item->ID);

		/* Remove it from Corpse */
		if (item_data){
			/* Delete needs to be before RemoveItem because its deletes the pointer for item_data/bag_item_data */
			database.DeleteItemOffCharacterCorpse(this->corpse_db_id, item_data->equip_slot, item_data->item_id);
			/* Delete Item Instance */
			RemoveItem(item_data->lootslot);
		}

		/* Remove Bag Contents */
		if (item->ItemClass == ItemClassContainer && (GetPlayerKillItem() != -1 || GetPlayerKillItem() != 1)) {
			for (int i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) {
				if (bag_item_data[i]) {
					/* Delete needs to be before RemoveItem because its deletes the pointer for item_data/bag_item_data */
					database.DeleteItemOffCharacterCorpse(this->corpse_db_id, bag_item_data[i]->equip_slot, bag_item_data[i]->item_id);
					/* Delete Item Instance */
					RemoveItem(bag_item_data[i]);
				}
			}
		}

		if (GetPlayerKillItem() != -1) {
			SetPlayerKillItemID(0);
		}

	/* Send message with item link to groups and such */
	Client::TextLink linker;
	linker.SetLinkType(linker.linkItemInst);
	linker.SetItemInst(inst);

	auto item_link = linker.GenerateLink();

	client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str());

	if (!IsPlayerCorpse()) {
			Group *g = client->GetGroup();
			if(g != nullptr) {
				g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str());
			}
			else {
				Raid *r = client->GetRaid();
				if(r != nullptr) {
					r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str());
				}
			}
		}
	}
	else {
		SendEndLootErrorPacket(client);
		safe_delete(inst);
		return;
	}

	if (IsPlayerCorpse()){
		client->SendItemLink(inst);
	}
	else{
		client->SendItemLink(inst, true);
	}

	safe_delete(inst);
}
Beispiel #15
0
// Retrieve item at specified slot; returns false if item not found
ItemInst* Inventory::GetItem(sint16 slot_id) const
{
	_CP(Inventory_GetItem);
	ItemInst* result = NULL;
	
	// Cursor
	if (slot_id == SLOT_CURSOR) {
		// Cursor slot
		result = m_cursor.peek_front();
	}
	
	// Non bag slots
	else if (slot_id>=3000 && slot_id<=3007) {
		// Trade slots
		result = _GetItem(m_trade, slot_id);
	}
	else if (slot_id>=2500 && slot_id<=2501) {
		// Shared Bank slots
		result = _GetItem(m_shbank, slot_id);
	}
	else if (slot_id>=2000 && slot_id<=2023) {
		// Bank slots
		result = _GetItem(m_bank, slot_id);
	}
	else if ((slot_id>=22 && slot_id<=29)) {
		// Personal inventory slots
		result = _GetItem(m_inv, slot_id);
	}
	else if ((slot_id>=0 && slot_id<=21) || (slot_id >= 400 && slot_id<=404) || (slot_id == 9999)) {
		// Equippable slots (on body)
		result = _GetItem(m_worn, slot_id);
	}
	
	// Inner bag slots
	else if (slot_id>=3031 && slot_id<=3110) {
		// Trade bag slots
		ItemInst* inst = _GetItem(m_trade, Inventory::CalcSlotId(slot_id));
		if (inst && inst->IsType(ItemClassContainer)) {
			result = inst->GetItem(Inventory::CalcBagIdx(slot_id));
		}
	}
	else if (slot_id>=2531 && slot_id<=2550) {
		// Shared Bank bag slots
		ItemInst* inst = _GetItem(m_shbank, Inventory::CalcSlotId(slot_id));
		if (inst && inst->IsType(ItemClassContainer)) {
			result = inst->GetItem(Inventory::CalcBagIdx(slot_id));
		}
	}
	else if (slot_id>=2031 && slot_id<=2270) {
		// Bank bag slots
		ItemInst* inst = _GetItem(m_bank, Inventory::CalcSlotId(slot_id));
		if (inst && inst->IsType(ItemClassContainer)) {
			result = inst->GetItem(Inventory::CalcBagIdx(slot_id));
		}
	}
	else if (slot_id>=331 && slot_id<=340) {
		// Cursor bag slots
		ItemInst* inst = m_cursor.peek_front();
		if (inst && inst->IsType(ItemClassContainer)) {
			result = inst->GetItem(Inventory::CalcBagIdx(slot_id));
		}
	}
	else if (slot_id>=251 && slot_id<=330) {
		// Personal inventory bag slots
		ItemInst* inst = _GetItem(m_inv, Inventory::CalcSlotId(slot_id));
		if (inst && inst->IsType(ItemClassContainer)) {
			result = inst->GetItem(Inventory::CalcBagIdx(slot_id));
		}
	}
	
	return result;
}
Beispiel #16
0
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();
	}
}
Beispiel #17
0
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);

}
Beispiel #18
0
void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID event, uint32 objid, const char * data,
        NPC* npcmob, ItemInst* iteminst, Mob* mob, uint32 extradata, std::vector<EQEmu::Any> *extra_pointers)
{
    switch (event) {
    case EVENT_SAY: {
        if(npcmob && mob) {
            npcmob->DoQuestPause(mob);
        }

        ExportVar(package_name.c_str(), "data", objid);
        ExportVar(package_name.c_str(), "text", data);
        ExportVar(package_name.c_str(), "langid", extradata);
        break;
    }

    case EVENT_TRADE: {
        if(extra_pointers) {
            size_t sz = extra_pointers->size();
            for(size_t i = 0; i < sz; ++i) {
                ItemInst *inst = EQEmu::any_cast<ItemInst*>(extra_pointers->at(i));

                std::string var_name = "item";
                var_name += std::to_string(i + 1);

                if(inst) {
                    ExportVar(package_name.c_str(), var_name.c_str(), inst->GetItem()->ID);

                    std::string temp_var_name = var_name;
                    temp_var_name += "_charges";
                    ExportVar(package_name.c_str(), temp_var_name.c_str(), inst->GetCharges());

                    temp_var_name = var_name;
                    temp_var_name += "_attuned";
                    ExportVar(package_name.c_str(), temp_var_name.c_str(), inst->IsAttuned());
                } else {
                    ExportVar(package_name.c_str(), var_name.c_str(), 0);

                    std::string temp_var_name = var_name;
                    temp_var_name += "_charges";
                    ExportVar(package_name.c_str(), temp_var_name.c_str(), 0);

                    temp_var_name = var_name;
                    temp_var_name += "_attuned";
                    ExportVar(package_name.c_str(), temp_var_name.c_str(), 0);
                }
            }
        }

        ExportVar(package_name.c_str(), "copper", GetVar("copper." + std::string(itoa(objid))).c_str());
        ExportVar(package_name.c_str(), "silver", GetVar("silver." + std::string(itoa(objid))).c_str());
        ExportVar(package_name.c_str(), "gold", GetVar("gold." + std::string(itoa(objid))).c_str());
        ExportVar(package_name.c_str(), "platinum", GetVar("platinum." + std::string(itoa(objid))).c_str());
        std::string hashname = package_name + std::string("::itemcount");
        perl->eval(std::string("%").append(hashname).append(" = ();").c_str());
        perl->eval(std::string("++$").append(hashname).append("{$").append(package_name).append("::item1};").c_str());
        perl->eval(std::string("++$").append(hashname).append("{$").append(package_name).append("::item2};").c_str());
        perl->eval(std::string("++$").append(hashname).append("{$").append(package_name).append("::item3};").c_str());
        perl->eval(std::string("++$").append(hashname).append("{$").append(package_name).append("::item4};").c_str());
        break;
    }

    case EVENT_WAYPOINT_ARRIVE:
    case EVENT_WAYPOINT_DEPART: {
        ExportVar(package_name.c_str(), "wp", data);
        break;
    }

    case EVENT_HP: {
        if (extradata == 1) {
            ExportVar(package_name.c_str(), "hpevent", "-1");
            ExportVar(package_name.c_str(), "inchpevent", data);
        }
        else
        {
            ExportVar(package_name.c_str(), "hpevent", data);
            ExportVar(package_name.c_str(), "inchpevent", "-1");
        }
        break;
    }

    case EVENT_TIMER: {
        ExportVar(package_name.c_str(), "timer", data);
        break;
    }

    case EVENT_SIGNAL: {
        ExportVar(package_name.c_str(), "signal", data);
        break;
    }

    case EVENT_NPC_SLAY: {
        ExportVar(package_name.c_str(), "killed", mob->GetNPCTypeID());
        break;
    }

    case EVENT_COMBAT: {
        ExportVar(package_name.c_str(), "combat_state", data);
        break;
    }

    case EVENT_CLICK_DOOR: {
        ExportVar(package_name.c_str(), "doorid", data);
        ExportVar(package_name.c_str(), "version", zone->GetInstanceVersion());
        break;
    }

    case EVENT_LOOT: {
        Seperator sep(data);
        ExportVar(package_name.c_str(), "looted_id", sep.arg[0]);
        ExportVar(package_name.c_str(), "looted_charges", sep.arg[1]);
        ExportVar(package_name.c_str(), "corpse", sep.arg[2]);
        break;
    }

    case EVENT_ZONE: {
        ExportVar(package_name.c_str(), "target_zone_id", data);
        break;
    }

    case EVENT_CAST_ON:
    case EVENT_CAST:
    case EVENT_CAST_BEGIN: {
        ExportVar(package_name.c_str(), "spell_id", data);
        break;
    }

    case EVENT_TASK_ACCEPTED: {
        ExportVar(package_name.c_str(), "task_id", data);
        break;
    }

    case EVENT_TASK_STAGE_COMPLETE: {
        Seperator sep(data);
        ExportVar(package_name.c_str(), "task_id", sep.arg[0]);
        ExportVar(package_name.c_str(), "activity_id", sep.arg[1]);
        break;
    }

    case EVENT_TASK_FAIL: {
        Seperator sep(data);
        ExportVar(package_name.c_str(), "task_id", sep.arg[0]);
        break;
    }

    case EVENT_TASK_COMPLETE:
    case EVENT_TASK_UPDATE: {
        Seperator sep(data);
        ExportVar(package_name.c_str(), "donecount", sep.arg[0]);
        ExportVar(package_name.c_str(), "activity_id", sep.arg[1]);
        ExportVar(package_name.c_str(), "task_id", sep.arg[2]);
        break;
    }

    case EVENT_PLAYER_PICKUP: {
        ExportVar(package_name.c_str(), "picked_up_id", data);
        ExportVar(package_name.c_str(), "picked_up_entity_id", extradata);
        break;
    }

    case EVENT_AGGRO_SAY: {
        ExportVar(package_name.c_str(), "data", objid);
        ExportVar(package_name.c_str(), "text", data);
        ExportVar(package_name.c_str(), "langid", extradata);
        break;
    }

    case EVENT_POPUP_RESPONSE: {
        ExportVar(package_name.c_str(), "popupid", data);
        break;
    }
    case EVENT_ENVIRONMENTAL_DAMAGE: {
        Seperator sep(data);
        ExportVar(package_name.c_str(), "env_damage", sep.arg[0]);
        ExportVar(package_name.c_str(), "env_damage_type", sep.arg[1]);
        ExportVar(package_name.c_str(), "env_final_damage", sep.arg[2]);
        break;
    }

    case EVENT_PROXIMITY_SAY: {
        ExportVar(package_name.c_str(), "data", objid);
        ExportVar(package_name.c_str(), "text", data);
        ExportVar(package_name.c_str(), "langid", extradata);
        break;
    }

    case EVENT_SCALE_CALC:
    case EVENT_ITEM_ENTER_ZONE: {
        // need a valid ItemInst pointer check here..unsure how to cancel this process
        ExportVar(package_name.c_str(), "itemid", objid);
        ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
        break;
    }

    case EVENT_ITEM_CLICK_CAST:
    case EVENT_ITEM_CLICK: {
        // need a valid ItemInst pointer check here..unsure how to cancel this process
        ExportVar(package_name.c_str(), "itemid", objid);
        ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
        ExportVar(package_name.c_str(), "slotid", extradata);
        ExportVar(package_name.c_str(), "spell_id", iteminst->GetItem()->Click.Effect);
        break;
    }

    case EVENT_GROUP_CHANGE: {
        if(mob && mob->IsClient())
        {
            ExportVar(package_name.c_str(), "grouped", mob->IsGrouped());
            ExportVar(package_name.c_str(), "raided", mob->IsRaidGrouped());
        }
        break;
    }

    case EVENT_HATE_LIST: {
        ExportVar(package_name.c_str(), "hate_state", data);
        break;
    }

    case EVENT_SPELL_EFFECT_CLIENT:
    case EVENT_SPELL_EFFECT_NPC:
    case EVENT_SPELL_BUFF_TIC_CLIENT:
    case EVENT_SPELL_BUFF_TIC_NPC:
    {
        ExportVar(package_name.c_str(), "caster_id", extradata);
        break;
    }

    //tradeskill events
    case EVENT_COMBINE_SUCCESS:
    case EVENT_COMBINE_FAILURE:
    {
        ExportVar(package_name.c_str(), "recipe_id", extradata);
        ExportVar(package_name.c_str(), "recipe_name", data);
        break;
    }

    case EVENT_FORAGE_SUCCESS: {
        ExportVar(package_name.c_str(), "foraged_item", extradata);
        break;
    }

    case EVENT_FISH_SUCCESS: {
        ExportVar(package_name.c_str(), "fished_item", extradata);
        break;
    }

    case EVENT_CLICK_OBJECT: {
        ExportVar(package_name.c_str(), "objectid", data);
        ExportVar(package_name.c_str(), "clicker_id", extradata);
        break;
    }

    case EVENT_DISCOVER_ITEM: {
        ExportVar(package_name.c_str(), "itemid", extradata);
        break;
    }

    case EVENT_COMMAND: {
        ExportVar(package_name.c_str(), "text", data);
        ExportVar(package_name.c_str(), "data", "0");
        ExportVar(package_name.c_str(), "langid", "0");
        break;
    }

    case EVENT_RESPAWN: {
        ExportVar(package_name.c_str(), "option", data);
        ExportVar(package_name.c_str(), "resurrect", extradata);
        break;
    }

    case EVENT_DEATH:
    case EVENT_DEATH_COMPLETE: {
        Seperator sep(data);
        ExportVar(package_name.c_str(), "killer_id", sep.arg[0]);
        ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]);
        ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]);
        ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
        break;
    }
    case EVENT_DROP_ITEM: {
        ExportVar(package_name.c_str(), "quantity", iteminst->IsStackable() ? iteminst->GetCharges() : 1);
        ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
        ExportVar(package_name.c_str(), "itemid", iteminst->GetItem()->ID);
        ExportVar(package_name.c_str(), "spell_id", iteminst->GetItem()->Click.Effect);
        ExportVar(package_name.c_str(), "slotid", extradata);
        break;
    }
    case EVENT_SPAWN_ZONE: {
        Seperator sep(data);
        ExportVar(package_name.c_str(), "spawned_entity_id", sep.arg[0]);
        ExportVar(package_name.c_str(), "spawned_npc_id", sep.arg[1]);
        break;
    }
    case EVENT_DEATH_ZONE: {
        Seperator sep(data);
        ExportVar(package_name.c_str(), "killer_id", sep.arg[0]);
        ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]);
        ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]);
        ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
        ExportVar(package_name.c_str(), "killed_npc_id", sep.arg[4]);
        break;
    }

    default: {
        break;
    }
    }
}
Beispiel #19
0
bool Inventory::HasSpaceForItem(const Item_Struct *ItemToTry, sint16 Quantity) {

	if(ItemToTry->Stackable) {

		for(sint16 i = 22; i <= 29; i++) {
	
			ItemInst* InvItem = GetItem(i);

			if(InvItem && (InvItem->GetItem()->ID == ItemToTry->ID) && (InvItem->GetCharges() < InvItem->GetItem()->StackSize)) {

				int ChargeSlotsLeft = InvItem->GetItem()->StackSize - InvItem->GetCharges();
		
				if(Quantity <= ChargeSlotsLeft)
					return true;

				Quantity -= ChargeSlotsLeft;

			}
			if (InvItem && InvItem->IsType(ItemClassContainer)) {

				sint16 BaseSlotID = Inventory::CalcSlotId(i, 0);
				int8 BagSize=InvItem->GetItem()->BagSlots;
				for (uint8 BagSlot = 0; BagSlot < BagSize; BagSlot++) {

					InvItem = GetItem(BaseSlotID + BagSlot);

					if(InvItem && (InvItem->GetItem()->ID == ItemToTry->ID) &&
					   (InvItem->GetCharges() < InvItem->GetItem()->StackSize)) {

						int ChargeSlotsLeft = InvItem->GetItem()->StackSize - InvItem->GetCharges();
			
						if(Quantity <= ChargeSlotsLeft)
							return true;

						Quantity -= ChargeSlotsLeft;
					}
				}
			}
		}
	}

	for (sint16 i = 22; i <= 29; i++) {

		ItemInst* InvItem = GetItem(i);

		if (!InvItem) {

			if(!ItemToTry->Stackable) {

				if(Quantity == 1)
					return true;
				else
					Quantity--;
			}
			else {
				if(Quantity <= ItemToTry->StackSize)
					return true;
				else
					Quantity -= ItemToTry->StackSize;
			}

		}
		else if(InvItem->IsType(ItemClassContainer) && CanItemFitInContainer(ItemToTry, InvItem->GetItem())) {

			sint16 BaseSlotID = Inventory::CalcSlotId(i, 0);

			int8 BagSize=InvItem->GetItem()->BagSlots;

			for (uint8 BagSlot=0; BagSlot<BagSize; BagSlot++) {

				InvItem = GetItem(BaseSlotID + BagSlot);

				if(!InvItem) {
					if(!ItemToTry->Stackable) {

						if(Quantity == 1)
							return true;
						else
							Quantity--;
					}
					else {
						if(Quantity <= ItemToTry->StackSize)
							return true;
						else
							Quantity -= ItemToTry->StackSize;
					}
				}
			}
		}
	}

	return false;

}
Beispiel #20
0
// Perform tradeskill combine
void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Object *worldo)
{
	if (!user || !in_combine) {
		LogFile->write(EQEMuLog::Error, "Client or NewCombine_Struct not set in Object::HandleCombine");
		return;
	}
	
	Inventory& user_inv = user->GetInv();
	PlayerProfile_Struct& user_pp = user->GetPP();
	ItemInst* container = NULL;
	ItemInst* inst = NULL;
 	uint8 c_type = 0xE8;
 	uint32 some_id = 0;
	bool worldcontainer=false;
	
	if (in_combine->container_slot == SLOT_TRADESKILL) {
		if(!worldo) {
			user->Message(13, "Error: Server is not aware of the tradeskill container you are attempting to use");
			return;
		}
		c_type = worldo->m_type;
		inst = worldo->m_inst;
		worldcontainer=true;
	}
	else {
		inst = user_inv.GetItem(in_combine->container_slot);
		if (inst) {
			const Item_Struct* item = inst->GetItem();
			if (item && inst->IsType(ItemClassContainer)) {
 				c_type = item->BagType;
 				some_id = item->ID;
			}
		}
	}
	
	if (!inst || !inst->IsType(ItemClassContainer)) {
		user->Message(13, "Error: Server does not recognize specified tradeskill container");
		return;
	}
	
	container = inst;
	
 	DBTradeskillRecipe_Struct spec;
 	if (!database.GetTradeRecipe(container, c_type, some_id, user->CharacterID(), &spec)) {
 		user->Message_StringID(MT_Emote,TRADESKILL_NOCOMBINE);
 		EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
 		user->QueuePacket(outapp);
 		safe_delete(outapp);
 		return;
 	}
 	
 	// Character hasn't learnt the recipe yet.
 	// must_learn:
 	//  bit 1 (0x01): recipe can't be experimented
 	//  bit 2 (0x02): can try to experiment but not useable for auto-combine until learnt
 	//  bit 5 (0x10): no learn message, use unlisted flag to prevent it showing up on search
 	//  bit 6 (0x20): unlisted recipe flag
 	if ((spec.must_learn&0xF) == 1 && !spec.has_learnt) {
 		// Made up message for the client. Just giving a DNC is the other option.
 		user->Message(4, "You need to learn how to combine these first.");
 		EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
 		user->QueuePacket(outapp);
 		safe_delete(outapp);
 		return;
 	}
	// Character does not have the required skill.
	if(spec.skill_needed > 0 && user->GetSkill(spec.tradeskill) < spec.skill_needed ) {
		// Notify client.
		user->Message(4, "You are not skilled enough.");
		EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
		user->QueuePacket(outapp);
		safe_delete(outapp);
		return;
	}
 	
	//changing from a switch to string of if's since we don't need to iterate through all of the skills in the SkillType enum
	if (spec.tradeskill == ALCHEMY) {
 		if (user_pp.class_ != SHAMAN) {
			user->Message(13, "This tradeskill can only be performed by a shaman.");
			return;
		}
		else if (user_pp.level < MIN_LEVEL_ALCHEMY) {
			user->Message(13, "You cannot perform alchemy until you reach level %i.", MIN_LEVEL_ALCHEMY);
			return;
		}
	}
	else if (spec.tradeskill == TINKERING) {
 		if (user_pp.race != GNOME) {
			user->Message(13, "Only gnomes can tinker.");
			return;
		}
	}
	else if (spec.tradeskill == MAKE_POISON) {
 		if (user_pp.class_ != ROGUE) {
			user->Message(13, "Only rogues can mix poisons.");
			return;
		}
	}
	
	// Send acknowledgement packets to client
	EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
	user->QueuePacket(outapp);
	safe_delete(outapp);

	//now clean out the containers.
	if(worldcontainer){
		container->Clear();
		outapp = new EQApplicationPacket(OP_ClearObject, sizeof(ClearObject_Struct));
		ClearObject_Struct *cos = (ClearObject_Struct *)outapp->pBuffer;
		cos->Clear = 1;
		user->QueuePacket(outapp);
		safe_delete(outapp);
		database.DeleteWorldContainer(worldo->m_id, zone->GetZoneID());
	} else{
		for (uint8 i=0; i<10; i++){
			const ItemInst* inst = container->GetItem(i);
			if (inst) {
				user->DeleteItemInInventory(Inventory::CalcSlotId(in_combine->container_slot,i),0,true);
			}
		}
		container->Clear();
	}
	//do the check and send results...
	bool success = user->TradeskillExecute(&spec);

	// Learn new recipe message
	// Update Made count
	if (success) {
		if (!spec.has_learnt && ((spec.must_learn&0x10) != 0x10)) {
			user->Message_StringID(4, TRADESKILL_LEARN_RECIPE, spec.name.c_str());
		}
		database.UpdateRecipeMadecount(spec.recipe_id, user->CharacterID(), spec.madecount+1);
	}
	
	// Replace the container on success if required.
	//
	
	if(success && spec.replace_container) {
		if(worldcontainer){
			//should report this error, but we dont have the recipe ID, so its not very useful
			LogFile->write(EQEMuLog::Error, "Replace container combine executed in a world container.");
		}
		else
			user->DeleteItemInInventory(in_combine->container_slot, 0, true);
	}
	if (success) 
		parse->EventPlayer(EVENT_COMBINE_SUCCESS, user, spec.name.c_str(), spec.recipe_id);
	else
		parse->EventPlayer(EVENT_COMBINE_FAILURE, user, spec.name.c_str(), spec.recipe_id); 
}
Beispiel #21
0
uint32 Client::CalcCurrentWeight() {

	const Item_Struct* TempItem = 0;
	ItemInst* ins;
	uint32 Total = 0;
	int x;
	for(x = EmuConstants::EQUIPMENT_BEGIN; x <= MainCursor; x++) // include cursor or not?
	{
		TempItem = 0;
		ins = GetInv().GetItem(x);
		if (ins)
			TempItem = ins->GetItem();
		if (TempItem)
			Total += TempItem->Weight;
	}
	for (x = EmuConstants::GENERAL_BAGS_BEGIN; x <= EmuConstants::GENERAL_BAGS_END; x++) // include cursor bags or not?
	{
		int TmpWeight = 0;
		TempItem = 0;
		ins = GetInv().GetItem(x);
		if (ins)
			TempItem = ins->GetItem();
		if (TempItem)
			TmpWeight = TempItem->Weight;
		if (TmpWeight > 0)
		{
			// this code indicates that weight redux bags can only be in the first general inventory slot to be effective...
			// is this correct? or can we scan for the highest weight redux and use that? (need client verifications)
			int bagslot = MainGeneral1;
			int reduction = 0;
			for (int m = EmuConstants::GENERAL_BAGS_BEGIN + 10; m <= EmuConstants::GENERAL_BAGS_END; m += 10) // include cursor bags or not?
			{
				if (x >= m)
					bagslot += 1;
			}
			ItemInst* baginst = GetInv().GetItem(bagslot);
			if (baginst && baginst->GetItem() && baginst->IsType(ItemClassContainer))
				reduction = baginst->GetItem()->BagWR;
			if (reduction > 0)
				TmpWeight -= TmpWeight*reduction/100;
			Total += TmpWeight;
		}
	}

	//TODO: coin weight reduction (from purses, etc), since client already calculates it
	/*From the Wiki http://www.eqemulator.net/wiki/wikka.php?wakka=EQEmuDBSchemaitems under bagwr (thanks Trevius):
	Interestingly, you can also have bags that reduce coin weight. However, in order to set bags to reduce coin weight, you MUST set the Item ID somewhere between 17201 and 17230. This is hard coded into the client.
	The client is set to have certain coin weight reduction on a per Item ID basis within this range. The best way to create an new item to reduce coin weight is to examine existing bags in this range.
	Search for the words "coin purse" with the #finditem command in game and the Bag WR setting on those bags is the amount they will reduce coin weight. It is easiest to overwrite one of those bags if you wish to create one with the
	same weight reduction amount for coins. You can use other Item IDs in this range for setting coin weight reduction, but by using an existing item, at least you will know the amount the client will reduce it by before you create it.
	This is the ONLY instance I have seen where the client is hard coded to particular Item IDs to set a certain property for an item. It is very odd.
	*/

	// SoD+ client has no weight for coin
	if (EQLimits::CoinHasWeight(ClientVersion))
		Total += (m_pp.platinum + m_pp.gold + m_pp.silver + m_pp.copper) / 4;

	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;
}
Beispiel #22
0
void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augment, Object *worldo)
{
	if (!user || !in_augment)
	{
		LogFile->write(EQEMuLog::Error, "Client or AugmentItem_Struct not set in Object::HandleAugmentation");
		return;
	}

	ItemInst* container = NULL;

	if (worldo)
	{
		container = worldo->m_inst;
	} 
	else
	{
		// Check to see if they have an inventory container type 53 that is used for this.
		Inventory& user_inv = user->GetInv();
		ItemInst* inst = NULL;
		
		inst = user_inv.GetItem(in_augment->container_slot);
		if (inst)
		{
			const Item_Struct* item = inst->GetItem();
			if (item && inst->IsType(ItemClassContainer) && item->BagType == 53)
			{
				// We have found an appropriate inventory augmentation sealer
				container = inst;

				// Verify that no more than two items are in container to guarantee no inadvertant wipes.
				uint8 itemsFound = 0;
				for (uint8 i=0; i<10; i++)
				{
					const ItemInst* inst = container->GetItem(i);
					if (inst)
					{
						itemsFound++;
					}
				}

				if (itemsFound != 2)
				{
					user->Message(13, "Error:  Too many/few items in augmentation container.");
					return;
				}
			}
		}
	}

	if(!container)
	{
		LogFile->write(EQEMuLog::Error, "Player tried to augment an item without a container set.");
		user->Message(13, "Error: This item is not a container!");
		return;
	}
	
	ItemInst *tobe_auged, *auged_with = NULL;
	int8 slot=-1;

	// Verify 2 items in the augmentation device
	if (container->GetItem(0) && container->GetItem(1))
	{
		// Verify 1 item is augmentable and the other is not
		if (container->GetItem(0)->IsAugmentable() && !container->GetItem(1)->IsAugmentable())
		{
			tobe_auged = container->GetItem(0);
			auged_with = container->GetItem(1);
		}
		else if (!container->GetItem(0)->IsAugmentable() && container->GetItem(1)->IsAugmentable())
		{
			tobe_auged = container->GetItem(1);
			auged_with = container->GetItem(0);
		}
		else
		{
			// Either 2 augmentable items found or none found
			// This should never occur due to client restrictions, but prevent in case of a hack
			user->Message(13, "Error: Must be 1 augmentable item in the sealer");
			return;
		}
	}
	else
	{
		// This happens if the augment button is clicked more than once quickly while augmenting
		if (!container->GetItem(0))
		{
			user->Message(13, "Error: No item in slot 0 of sealer");
		}
		if (!container->GetItem(1))
		{
			user->Message(13, "Error: No item in slot 1 of sealer");
		}
		return;
	}

	bool deleteItems = false;

	ItemInst *itemOneToPush = NULL, *itemTwoToPush = NULL;

	// Adding augment
	if (in_augment->augment_slot == -1)
	{
		if (((slot=tobe_auged->AvailableAugmentSlot(auged_with->GetAugmentType()))!=-1) && (tobe_auged->AvailableWearSlot(auged_with->GetItem()->Slots)))
		{
			tobe_auged->PutAugment(slot,*auged_with);
			itemOneToPush = tobe_auged->Clone();
			deleteItems = true;
		}
		else
		{
			user->Message(13, "Error: No available slot for augment");
		}
	}
	else
	{
		ItemInst *old_aug=NULL;
		const uint32 id=auged_with->GetID();
		if (id==40408 || id==40409 || id==40410)
			tobe_auged->DeleteAugment(in_augment->augment_slot);
		else
			old_aug=tobe_auged->RemoveAugment(in_augment->augment_slot);

		itemOneToPush = tobe_auged->Clone();
		if (old_aug)
			itemTwoToPush = old_aug->Clone();

		deleteItems = true;
	}

	if (deleteItems)
	{
		if (worldo)
		{
			container->Clear();
			EQApplicationPacket* outapp = new EQApplicationPacket(OP_ClearObject, sizeof(ClearObject_Struct));
			ClearObject_Struct *cos = (ClearObject_Struct *)outapp->pBuffer;
			cos->Clear = 1;
			user->QueuePacket(outapp);
			safe_delete(outapp);
			database.DeleteWorldContainer(worldo->m_id, zone->GetZoneID());
		}
		else
		{
			// Delete items in our inventory container... 
			for (uint8 i=0; i<10; i++)
			{
				const ItemInst* inst = container->GetItem(i);
				if (inst)
				{
					user->DeleteItemInInventory(Inventory::CalcSlotId(in_augment->container_slot,i),0,true);
				}
			}
			// Explicitly mark container as cleared.
			container->Clear();
		}
	}

	// Must push items after the items in inventory are deleted - necessary due to lore items...
	if (itemOneToPush)
	{
		user->PushItemOnCursor(*itemOneToPush,true);
	}
	if (itemTwoToPush)
	{
		user->PushItemOnCursor(*itemTwoToPush,true);
	}

}
Beispiel #23
0
Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
	"Unnamed_Corpse",				  // const char*	in_name,
	"",								  // const char*	in_lastname,
	0,								  // int32		in_cur_hp,
	0,								  // int32		in_max_hp,
	client->GetGender(),			  // uint8		in_gender,
	client->GetRace(),				  // uint16		in_race,
	client->GetClass(),				  // uint8		in_class,
	BT_Humanoid,					  // bodyType	in_bodytype,
	client->GetDeity(),				  // uint8		in_deity,
	client->GetLevel(),				  // uint8		in_level,
	0,								  // uint32		in_npctype_id,
	client->GetSize(),				  // float		in_size,
	0,								  // float		in_runspeed,
	client->GetPosition(),
	client->GetInnateLightType(),	  // uint8		in_light, - verified for client innate_light value
	client->GetTexture(),			  // uint8		in_texture,
	client->GetHelmTexture(),		  // uint8		in_helmtexture,
	0,								  // uint16		in_ac,
	0,								  // uint16		in_atk,
	0,								  // uint16		in_str,
	0,								  // uint16		in_sta,
	0,								  // uint16		in_dex,
	0,								  // uint16		in_agi,
	0,								  // uint16		in_int,
	0,								  // uint16		in_wis,
	0,								  // uint16		in_cha,
	client->GetPP().haircolor,		  // uint8		in_haircolor,
	client->GetPP().beardcolor,		  // uint8		in_beardcolor,
	client->GetPP().eyecolor1,		  // uint8		in_eyecolor1, // the eyecolors always seem to be the same, maybe left and right eye?
	client->GetPP().eyecolor2,		  // uint8		in_eyecolor2,
	client->GetPP().hairstyle,		  // uint8		in_hairstyle,
	client->GetPP().face,			  // uint8		in_luclinface,
	client->GetPP().beard,			  // uint8		in_beard,
	client->GetPP().drakkin_heritage, // uint32		in_drakkin_heritage,
	client->GetPP().drakkin_tattoo,	  // uint32		in_drakkin_tattoo,
	client->GetPP().drakkin_details,  // uint32		in_drakkin_details,
	0,								  // uint32		in_armor_tint[_MaterialCount],
	0xff,							  // uint8		in_aa_title,
	0,								  // uint8		in_see_invis, // see through invis
	0,								  // uint8		in_see_invis_undead, // see through invis vs. undead
	0,								  // uint8		in_see_hide,
	0,								  // uint8		in_see_improved_hide,
	0,								  // int32		in_hp_regen,
	0,								  // int32		in_mana_regen,
	0,								  // uint8		in_qglobal,
	0,								  // uint8		in_maxlevel,
	0,								  // uint32		in_scalerate
	0,								  // uint8		in_armtexture,
	0,								  // uint8		in_bracertexture,
	0,								  // uint8		in_handtexture,
	0,								  // uint8		in_legtexture,
	0								  // uint8		in_feettexture,
	),
	corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)),
	corpse_rez_timer(RuleI(Character, CorpseResTimeMS)),
	corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)),
	corpse_graveyard_timer(RuleI(Zone, GraveyardTimeMS)),
	loot_cooldown_timer(10)
{
	int i;

	PlayerProfile_Struct *pp = &client->GetPP();
	ItemInst *item;

	/* Check if Zone has Graveyard First */
	if(!zone->HasGraveyard()) {
		corpse_graveyard_timer.Disable();
	}

	memset(item_tint, 0, sizeof(item_tint));

	for (i = 0; i < MAX_LOOTERS; i++){
		allowed_looters[i] = 0;
	}

	is_corpse_changed		= true;
	rez_experience			= in_rezexp;
	can_corpse_be_rezzed			= true;
	is_player_corpse	= true;
	is_locked			= false;
	being_looted_by	= 0xFFFFFFFF;
	char_id			= client->CharacterID();
	corpse_db_id	= 0;
	player_corpse_depop			= false;
	copper			= 0;
	silver			= 0;
	gold			= 0;
	platinum		= 0;

	strcpy(corpse_name, pp->name);
	strcpy(name, pp->name);

	/* become_npc was not being initialized which led to some pretty funky things with newly created corpses */
	become_npc = false;

	SetPlayerKillItemID(0);

	/* Check Rule to see if we can leave corpses */
	if(!RuleB(Character, LeaveNakedCorpses) ||
		RuleB(Character, LeaveCorpses) &&
		GetLevel() >= RuleI(Character, DeathItemLossLevel)) {
		// cash
		// Let's not move the cash when 'RespawnFromHover = true' && 'client->GetClientVersion() < EQClientSoF' since the client doesn't.
		// (change to first client that supports 'death hover' mode, if not SoF.)
		if (!RuleB(Character, RespawnFromHover) || client->GetClientVersion() < ClientVersion::SoF) {
			SetCash(pp->copper, pp->silver, pp->gold, pp->platinum);
			pp->copper = 0;
			pp->silver = 0;
			pp->gold = 0;
			pp->platinum = 0;
		}

		// get their tints
		memcpy(item_tint, &client->GetPP().item_tint, sizeof(item_tint));

		// TODO soulbound items need not be added to corpse, but they need
		// to go into the regular slots on the player, out of bags
		std::list<uint32> removed_list;
		
		for(i = MAIN_BEGIN; i < EmuConstants::MAP_POSSESSIONS_SIZE; ++i) {
			if(i == MainAmmo && client->GetClientVersion() >= ClientVersion::SoF) {
				item = client->GetInv().GetItem(MainPowerSource);
				if (item != nullptr) {
					if (!client->IsBecomeNPC() || (client->IsBecomeNPC() && !item->GetItem()->NoRent))
						MoveItemToCorpse(client, item, MainPowerSource, removed_list);
				}
			}

			item = client->GetInv().GetItem(i);
			if (item == nullptr) { continue; }

			if(!client->IsBecomeNPC() || (client->IsBecomeNPC() && !item->GetItem()->NoRent))
				MoveItemToCorpse(client, item, i, removed_list);
		}

		database.TransactionBegin();

		// I have an untested process that avoids this snarl up when all possessions inventory is removed..but this isn't broke
		if (!removed_list.empty()) {
			std::stringstream ss("");
			ss << "DELETE FROM inventory WHERE charid=" << client->CharacterID();
			ss << " AND (";
			std::list<uint32>::const_iterator iter = removed_list.begin();
			bool first = true;
			while (iter != removed_list.end()) {
				if (first) {
					first = false;
				}
				else {
					ss << " OR ";
				}
				ss << "slotid=" << (*iter);
				++iter;
			}
			ss << ")";
			database.QueryDatabase(ss.str().c_str());
		}

		auto start = client->GetInv().cursor_cbegin();
		auto finish = client->GetInv().cursor_cend();
		database.SaveCursor(client->CharacterID(), start, finish);

		client->CalcBonuses();
		client->Save();

		IsRezzed(false);
		Save();

		database.TransactionCommit();

		UpdateEquipmentLight();
		UpdateActiveLight();

		return;
	} //end "not leaving naked corpses"

	UpdateEquipmentLight();
	UpdateActiveLight();

	IsRezzed(false);
	Save();
}
Beispiel #24
0
// solar: the current stuff is at the bottom of this function
void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* cs) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char* query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	Inventory *inv;

	for (int i=0; i<10; i++) {
		strcpy(cs->name[i], "<none>");
		cs->zone[i] = 0;
		cs->level[i] = 0;
			cs->tutorial[i] = 0;
		cs->gohome[i] = 0;
	}

	int char_num = 0;
	unsigned long* lengths;

	// Populate character info
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT name,profile,zonename,class,level FROM character_ WHERE account_id=%i order by name limit 10", account_id), errbuf, &result)) {
		safe_delete_array(query);
		while ((row = mysql_fetch_row(result))) {
			lengths = mysql_fetch_lengths(result);
			////////////
			////////////	This is the current one, the other are for converting
			////////////
			if ((lengths[1] == sizeof(PlayerProfile_Struct))) {
				strcpy(cs->name[char_num], row[0]);
				PlayerProfile_Struct* pp = (PlayerProfile_Struct*)row[1];
				uint8 clas = atoi(row[3]);
				uint8 lvl = atoi(row[4]);

				// Character information
				if(lvl == 0)
					cs->level[char_num]		= pp->level;	//no level in DB, trust PP
				else
					cs->level[char_num]		= lvl;
				if(clas == 0)
					cs->class_[char_num]	= pp->class_;	//no class in DB, trust PP
				else
					cs->class_[char_num]	= clas;
				cs->race[char_num]			= pp->race;
				cs->gender[char_num]		= pp->gender;
				cs->deity[char_num]			= pp->deity;
				cs->zone[char_num]			= GetZoneID(row[2]);
				cs->face[char_num]			= pp->face;
				cs->haircolor[char_num]		= pp->haircolor;
				cs->beardcolor[char_num]	= pp->beardcolor;
				cs->eyecolor2[char_num]		= pp->eyecolor2;
				cs->eyecolor1[char_num]		= pp->eyecolor1;
				cs->hairstyle[char_num]		= pp->hairstyle;
				cs->beard[char_num]			= pp->beard;
				cs->drakkin_heritage[char_num]	= pp->drakkin_heritage;
				cs->drakkin_tattoo[char_num]	= pp->drakkin_tattoo;
				cs->drakkin_details[char_num]	= pp->drakkin_details;

				if(RuleB(World, EnableTutorialButton) && (lvl <= RuleI(World, MaxLevelForTutorial)))
					cs->tutorial[char_num] = 1;

				if(RuleB(World, EnableReturnHomeButton)) {
					int now = time(nullptr);
					if((now - pp->lastlogin) >= RuleI(World, MinOfflineTimeToReturnHome))
						cs->gohome[char_num] = 1;
				}


				// This part creates home city entries for characters created before the home bind point was tracked.
				// Do it here because the player profile is already loaded and it's as good a spot as any. This whole block should
				// probably be removed at some point, when most accounts are safely converted.
				if(pp->binds[4].zoneId == 0) {
					bool altered = false;
					MYSQL_RES *result2;
					MYSQL_ROW row2;
					char startzone[50] = {0};

					// check for start zone variable (I didn't even know any variables were still being used...)
					if(database.GetVariable("startzone", startzone, 50)) {
						uint32 zoneid = database.GetZoneID(startzone);
						if(zoneid) {
							pp->binds[4].zoneId = zoneid;
							GetSafePoints(zoneid, 0, &pp->binds[4].x, &pp->binds[4].y, &pp->binds[4].z);
							altered = true;
						}
					}
					else {
						RunQuery(query,
							MakeAnyLenString(&query,
							"SELECT zone_id,bind_id,x,y,z FROM start_zones "
							"WHERE player_class=%i AND player_deity=%i AND player_race=%i",
							pp->class_,
							pp->deity,
							pp->race
							),
							errbuf,
							&result2
						);
						safe_delete_array(query);

						// if there is only one possible start city, set it
						if(mysql_num_rows(result2) == 1) {
							row2 = mysql_fetch_row(result2);
							if(atoi(row2[1]) != 0) {		// if a bind_id is specified, make them start there
								pp->binds[4].zoneId = (uint32)atoi(row2[1]);
								GetSafePoints(pp->binds[4].zoneId, 0, &pp->binds[4].x, &pp->binds[4].y, &pp->binds[4].z);
							}
							else {	// otherwise, use the zone and coordinates given
								pp->binds[4].zoneId = (uint32)atoi(row2[0]);
								float x = atof(row2[2]);
								float y = atof(row2[3]);
								float z = atof(row2[4]);
								if(x == 0 && y == 0 && z == 0)
									GetSafePoints(pp->binds[4].zoneId, 0, &x, &y, &z);

								pp->binds[4].x = x;
								pp->binds[4].y = y;
								pp->binds[4].z = z;
							}
							altered = true;
						}

						mysql_free_result(result2);
					}

					// update the player profile
					if(altered) {
						uint32 char_id = GetCharacterID(cs->name[char_num]);
						RunQuery(query,MakeAnyLenString(&query,"SELECT extprofile FROM character_ WHERE id=%i",char_id), errbuf, &result2);
						safe_delete_array(query);
						if(result2) {
							row2 = mysql_fetch_row(result2);
							ExtendedProfile_Struct* ext = (ExtendedProfile_Struct*)row2[0];
							SetPlayerProfile(account_id,char_id,pp,inv,ext, 0, 0, 5);
						}
						mysql_free_result(result2);
					}
				}	// end of "set start zone" block


				// Character's equipped items
				// @merth: Haven't done bracer01/bracer02 yet.
				// Also: this needs a second look after items are a little more solid
				// NOTE: items don't have a color, players MAY have a tint, if the
				// use_tint part is set. otherwise use the regular color
				inv = new Inventory;
				if(GetInventory(account_id, cs->name[char_num], inv))
				{
					for (uint8 material = 0; material <= 8; material++)
					{
						uint32 color;
						ItemInst *item = inv->GetItem(Inventory::CalcSlotFromMaterial(material));
						if(item == 0)
							continue;

						cs->equip[char_num][material] = item->GetItem()->Material;

						if(pp->item_tint[material].rgb.use_tint)	// they have a tint (LoY dye)
							color = pp->item_tint[material].color;
						else	// no tint, use regular item color
							color = item->GetItem()->Color;

						cs->cs_colors[char_num][material].color = color;

						// the weapons are kept elsewhere
						if ((material==MaterialPrimary) || (material==MaterialSecondary))
						{
							if(strlen(item->GetItem()->IDFile) > 2) {
								uint32 idfile=atoi(&item->GetItem()->IDFile[2]);
								if (material==MaterialPrimary)
									cs->primary[char_num]=idfile;
								else
									cs->secondary[char_num]=idfile;
							}
						}
					}
				}
				else
				{
					printf("Error loading inventory for %s\n", cs->name[char_num]);
				}
				safe_delete(inv);
				if (++char_num > 10)
					break;
			}
			else
			{
				std::cout << "Got a bogus character (" << row[0] << ") Ignoring!!!" << std::endl;
				std::cout << "PP length ="<<lengths[1]<<" but PP should be "<<sizeof(PlayerProfile_Struct) << std::endl;
				//DeleteCharacter(row[0]);
			}
		}
		mysql_free_result(result);
	}
	else
	{
		std::cerr << "Error in GetCharSelectInfo query '" << query << "' " << errbuf << std::endl;
		safe_delete_array(query);
		return;
	}

	return;
}