Ejemplo n.º 1
0
bool CustomJewels::Apply(LPOBJ lpObj, int source, int target)
{
	char sbuf[1024]={0};
	int TIndex = lpObj->pInventory[target].m_Type;
	int SIndex = lpObj->pInventory[source].m_Type;

	if(source < 0 || source > ReadConfig.MAIN_INVENTORY_SIZE(lpObj->m_Index,false)-1 )
	{
		return false;
	}

	if(target < 0 || target > ReadConfig.MAIN_INVENTORY_SIZE(lpObj->m_Index,false)-1 )
	{
		return false;
	}

	if(lpObj->pInventory[source].IsItem() == 0)
	{
		return false;
	}

	if(lpObj->pInventory[target].IsItem() == 0)
	{
		return false;
	}

	if (lpObj->pInventory[target].m_Type >= ITEMGET(12,0))
	{
		GCServerMsgStringSend("Can not aply this jewel to this item!",lpObj->m_Index, 0x01);
		return false;
	}

	if (!gObjJewelUpHackCheck(lpObj,target))
	{
		GCServerMsgStringSend("[Anti-Hack] Shadow Bug Attempt!",lpObj->m_Index, 0x01);
		if(ReadConfig.AHLog == TRUE)
		{
			ANTI_HACK_LOG.Output("[Anti-Hack][Custom Jewel][%s][%s] Shadow Bug Attempt, Item: %d",
				lpObj->AccountID,lpObj->Name,lpObj->pInventory[target].m_Type);
		}
		return false;
	}

	BYTE jPos = IsJewel(SIndex);
	BYTE jSuccess = GetSuccessPosition(SIndex);
	BYTE jFail = GetFailPosition(SIndex);

	if(jPos == -1)
	{
		LogAddTD("[CJewel] Could not find jewel property with id: %d", SIndex);
		GCServerMsgStringSend("JEWEL ERROR, contact GM!",lpObj->m_Index, 0x01);
		return false;
	}
	if(jSuccess == -1)
	{
		LogAddTD("[CJewel] Could not find jewel success with id: %d", SIndex);
		GCServerMsgStringSend("JEWEL ERROR, contact GM!",lpObj->m_Index, 0x01);
		return false;
	}
	if(jFail == -1)
	{
		LogAddTD("[CJewel] Could not find jewel fail with id: %d", SIndex);
		GCServerMsgStringSend("JEWEL ERROR, contact GM!",lpObj->m_Index, 0x01);
		return false;
	}

	if(lpObj->pInventory[target].m_Level < this->Property[jPos].MinLevel)
	{
		wsprintf(sbuf,"Item level must be higher than %d!",this->Property[jPos].MinLevel);
		GCServerMsgStringSend(sbuf,lpObj->m_Index, 0x01);
		return false;
	}

	if(lpObj->pInventory[target].m_Level > this->Property[jPos].MaxLevel)
	{
		wsprintf(sbuf,"Item level must be lower than %d!",this->Property[jPos].MaxLevel);
		GCServerMsgStringSend(sbuf,lpObj->m_Index, 0x01);
		return false;
	}

	if(lpObj->pInventory[target].m_Z28Option < this->Property[jPos].MinZ28Option)
	{
		wsprintf(sbuf,"Item JOL option minimum is +%d",(this->Property[jPos].MinZ28Option*4));
		GCServerMsgStringSend(sbuf,lpObj->m_Index, 0x01);
		return false;
	}

	if(this->Property[jPos].hasToHaveLuck == -1)
	{
		if (lpObj->pInventory[target].m_LuckOption != 0)
		{
			GCServerMsgStringSend("Item can not have Luck!",lpObj->m_Index, 0x01);
			return false;
		}
	}
	if(this->Property[jPos].hasToHaveLuck > 0)
	{
		if (lpObj->pInventory[target].m_LuckOption == 0)
		{
			GCServerMsgStringSend("Item has to have Luck!",lpObj->m_Index, 0x01);
			return false;
		}
	}

	if(this->Property[jPos].hasToHaveSkill == -1)
	{
		if (lpObj->pInventory[target].m_SkillOption != 0)
		{
			GCServerMsgStringSend("Item can not have Skill!",lpObj->m_Index, 0x01);
			return false;
		}
	}
	if(this->Property[jPos].hasToHaveSkill > 0)
	{
		if (lpObj->pInventory[target].m_SkillOption == 0)
		{
			GCServerMsgStringSend("Item has to have Skill!",lpObj->m_Index, 0x01);
			return false;
		}
	}

	if(this->Property[jPos].hasToBeAncient == -1)
	{
		if (lpObj->pInventory[target].m_SetOption != 0)
		{
			GCServerMsgStringSend("Item can not be Ancient!",lpObj->m_Index, 0x01);
			return false;
		}
	}
	if(this->Property[jPos].hasToBeAncient > 0)
	{
		if (lpObj->pInventory[target].m_SetOption == 0)
		{
			GCServerMsgStringSend("Item must be Ancient!",lpObj->m_Index, 0x01);
			return false;
		}
	}

	if(this->Property[jPos].hasToBeExcellent == -1)
	{
		if (lpObj->pInventory[target].m_NewOption != 0)
		{
			GCServerMsgStringSend("Item can not be Excellent!",lpObj->m_Index, 0x01);
			return false;
		}
	}
	if(this->Property[jPos].hasToBeExcellent > 0)
	{
		if (lpObj->pInventory[target].m_NewOption == 0)
		{
			GCServerMsgStringSend("Item must be Excellent!",lpObj->m_Index, 0x01);
			return false;
		}
	}

	if(this->Property[jPos].MaxExc != 0)
	{
		if(NumOfExcOptions(lpObj->pInventory[target].m_NewOption) >= this->Property[jPos].MaxExc)
		{
			wsprintf(sbuf,"Cant add jewel, you have a lot of excellent options, max opt are %d!",this->Property[jPos].MaxExc);
			GCServerMsgStringSend(sbuf,lpObj->m_Index, 0x01);
			return false;
		}
	}

	if(this->Property[jPos].hasToBeSoketItem == -1)
	{
		if(IsSlotItem(lpObj->pInventory[target].m_Type)==1)
		{
			GCServerMsgStringSend("Item can not be socket item!",lpObj->m_Index, 0x01);
			return false;
		}
	}
	if(this->Property[jPos].hasToBeSoketItem == 1)
	{
		if(IsSlotItem(lpObj->pInventory[target].m_Type)==0)
		{
			GCServerMsgStringSend("This item has to be socket item!",lpObj->m_Index, 0x01);
			return false;
		} else {
			if(this->Property[jPos].MinNumberSokets > 0)
			{
				BYTE counter = 0;

				if (lpObj->pInventory[target].m_ItemSlot1 > 0)
					counter += 1;
				if (lpObj->pInventory[target].m_ItemSlot2 > 0)
					counter += 1;
				if (lpObj->pInventory[target].m_ItemSlot3 > 0)
					counter += 1;
				if (lpObj->pInventory[target].m_ItemSlot4 > 0)
					counter += 1;
				if (lpObj->pInventory[target].m_ItemSlot5 > 0)
					counter += 1;

				if (this->Property[jPos].MinNumberSokets > counter)
				{
					wsprintf(sbuf,"Item minimum socket count is %d",this->Property[jPos].MinNumberSokets);
					GCServerMsgStringSend(sbuf,lpObj->m_Index, 0x01);
					return false;
				}
			}
		}
	}

	if(this->Property[jPos].MaxNumberSokets != 0)
	{
		BYTE counter = 0;

		if (lpObj->pInventory[target].m_ItemSlot1 > 0)
			counter += 1;
		if (lpObj->pInventory[target].m_ItemSlot2 > 0)
			counter += 1;
		if (lpObj->pInventory[target].m_ItemSlot3 > 0)
			counter += 1;
		if (lpObj->pInventory[target].m_ItemSlot4 > 0)
			counter += 1;
		if (lpObj->pInventory[target].m_ItemSlot5 > 0)
			counter += 1;

		if(counter >= this->Property[jPos].MaxNumberSokets)
		{
			wsprintf(sbuf,"Cant add jewel, you have a lot of socket slots, max slot are %d!",this->Property[jPos].MaxNumberSokets);
			GCServerMsgStringSend(sbuf,lpObj->m_Index, 0x01);
			return false;
		}
	}

	//if(MuItemShop.IsCShopItem(aIndex,target) == true)
	//{
	//	GCServerMsgStringSend("You can not use the jewel in this item!",lpObj->m_Index, 0x01);
	//	return true;
	//}

	LogAddTD("[CJewel][%s][%s] Use %s on item %s (%d)",
		lpObj->AccountID,lpObj->Name,lpObj->pInventory[source].GetName(),lpObj->pInventory[target].GetName(),
		lpObj->pInventory[target].m_Number);

	int _r = rand()%100;
	if(_r < this->Property[jPos].Rate )
	{
		//Success
		GCServerMsgStringSend("Jewel Succeded!",lpObj->m_Index, 0x01);
				
		LogAddTD("[CJewel][%s][%s] Success %s on item %s (%d) [%d][%d,%d]",
			lpObj->AccountID,lpObj->Name,lpObj->pInventory[source].GetName(),lpObj->pInventory[target].GetName(),
			lpObj->pInventory[target].m_Number,
			TIndex,_r,this->Property[jPos].Rate);

		if(this->Success[jSuccess].Luck == 1)
		{
			lpObj->pInventory[target].m_LuckOption = 1;
		}
		if(this->Success[jSuccess].Skill == 1)
		{
			lpObj->pInventory[target].m_SkillOption = 1;
		}
		if(this->Success[jSuccess].SetItem == 1)
		{
			lpObj->pInventory[target].m_SetOption = gSetItemOption.GenSetOption(lpObj->pInventory[target].m_Type);
		}
		if(this->Success[jSuccess].Excellent != 63)
		{
			if(this->Success[jSuccess].Excellent > 0) 
			{
				lpObj->pInventory[target].m_NewOption |= this->Success[jSuccess].Excellent;
			}
		}else
		{
			lpObj->pInventory[target].m_NewOption = 63;
		}
		if(this->Success[jSuccess].Level > 0)
		{
			if((lpObj->pInventory[target].m_Level + this->Success[jSuccess].Level) > MAX_ITEM_LEVEL)
			{
				lpObj->pInventory[target].m_Level = MAX_ITEM_LEVEL;
			}else
			{
				lpObj->pInventory[target].m_Level += this->Success[jSuccess].Level;
			}
		}

		if(this->Success[jSuccess].Sokets > 0)
		{
			if ( IsSlotItem(lpObj->pInventory[target].m_Type) )
			{
				for(int k=0;k<this->Success[jSuccess].Sokets;k++)
				{
					if (lpObj->pInventory[target].m_ItemSlot1 == 0)
						lpObj->pInventory[target].m_ItemSlot1 = 0xFF;
					else if (lpObj->pInventory[target].m_ItemSlot2 == 0)
						lpObj->pInventory[target].m_ItemSlot2 = 0xFF;
					else if (lpObj->pInventory[target].m_ItemSlot3 == 0)
						lpObj->pInventory[target].m_ItemSlot3 = 0xFF;
					else if (lpObj->pInventory[target].m_ItemSlot4 == 0)
						lpObj->pInventory[target].m_ItemSlot4 = 0xFF;
					else if (lpObj->pInventory[target].m_ItemSlot5 == 0)
						lpObj->pInventory[target].m_ItemSlot5 = 0xFF;
				}
			}
		}

		if(this->Success[jSuccess].Option > 0)
		{
			if((lpObj->pInventory[target].m_Z28Option + this->Success[jSuccess].Option) > 7)
			{
				lpObj->pInventory[target].m_Z28Option = 7;
			}else
			{
				lpObj->pInventory[target].m_Z28Option += this->Success[jSuccess].Option;
			}
		}
	}
	else
	{
		//Fail
		GCServerMsgStringSend("Jewel Failed!",lpObj->m_Index, 0x01);
		
		LogAddTD("[CJewel][%s][%s] Fail %s on item %s (%d) [%d][%d,%d]",
			lpObj->AccountID,lpObj->Name,lpObj->pInventory[source].GetName(),lpObj->pInventory[target].GetName(),
			lpObj->pInventory[target].m_Number,
			TIndex,_r,this->Property[jPos].Rate);

		if(this->Fail[jFail].Destroy == 1)
		{			
			gObjInventoryItemSet(lpObj->m_Index, target, -1);
			lpObj->pInventory[target].Clear();
			GCInventoryItemDeleteSend(lpObj->m_Index, target, 1);
			return true;
		}
		
		if(this->Fail[jFail].Luck == -1)
		{
			lpObj->pInventory[target].m_LuckOption = 0;
		}
		if(this->Fail[jFail].Skill == -1)
		{
			lpObj->pInventory[target].m_SkillOption = 0;
		}
		if(this->Fail[jFail].SetItem == -1)
		{
			lpObj->pInventory[target].m_SetOption = 0;
		}
		if(this->Fail[jFail].Excellent < 0)
		{
			if(this->Fail[jFail].Excellent == -63)
				lpObj->pInventory[target].m_NewOption = 0;
			else if( (lpObj->pInventory[target].m_NewOption&(this->Fail[jFail].Excellent)) )
				lpObj->pInventory[target].m_NewOption += (this->Fail[jFail].Excellent);

			if(lpObj->pInventory[target].m_NewOption < 0)
				lpObj->pInventory[target].m_NewOption = 0;
		}
		if(this->Fail[jFail].Level < 0)
		{
			if((lpObj->pInventory[target].m_Level + (this->Fail[jFail].Level)) < 0)
			{
				lpObj->pInventory[target].m_Level = 0;
			}else
			{
				lpObj->pInventory[target].m_Level += (this->Fail[jFail].Level);
			}
		}
		if(this->Fail[jFail].Sokets < 0)
		{
			if ( IsSlotItem(lpObj->pInventory[target].m_Type) )
			{
				for(int k=0;k<(this->Fail[jFail].Sokets);k++)
				{
					if (lpObj->pInventory[target].m_ItemSlot5 > 0)
						lpObj->pInventory[target].m_ItemSlot5 = 0x00;
					else if (lpObj->pInventory[target].m_ItemSlot4 > 0)
						lpObj->pInventory[target].m_ItemSlot4 = 0x00;
					else if (lpObj->pInventory[target].m_ItemSlot3 > 0)
						lpObj->pInventory[target].m_ItemSlot3 = 0x00;
					else if (lpObj->pInventory[target].m_ItemSlot2 > 0)
						lpObj->pInventory[target].m_ItemSlot2 = 0x00;
					else if (lpObj->pInventory[target].m_ItemSlot1 > 0)
						lpObj->pInventory[target].m_ItemSlot1 = 0x00;
				}
			}
		}
		if(this->Fail[jFail].Option < 0)
		{
			if((lpObj->pInventory[target].m_Z28Option + (this->Fail[jFail].Option)) < 0)
			{
				lpObj->pInventory[target].m_Z28Option = 0;
			}else
			{
				lpObj->pInventory[target].m_Z28Option += (this->Fail[jFail].Option);
			}
		}
	}

	float levelitemdur = ItemGetDurability(lpObj->pInventory[target].m_Type,lpObj->pInventory[target].m_Level,lpObj->pInventory[target].IsExtItem(),lpObj->pInventory[target].IsSetItem());

	lpObj->pInventory[target].m_Durability = levelitemdur * lpObj->pInventory[target].m_Durability / lpObj->pInventory[target].m_BaseDurability;

	lpObj->pInventory[target].Convert(
			lpObj->pInventory[target].m_Type,
			lpObj->pInventory[target].m_SkillOption,
			lpObj->pInventory[target].m_LuckOption,
			lpObj->pInventory[target].m_Z28Option,
			lpObj->pInventory[target].m_NewOption,
			lpObj->pInventory[target].m_SetOption,
			lpObj->pInventory[target].m_ItemOptionEx,
			CURRENT_DB_VERSION);

	if(g_kJewelOfHarmonySystem.IsStrengthenByJewelOfHarmony(&lpObj->pInventory[target])== 1)
	{
		if(g_kJewelOfHarmonySystem.IsActive(&lpObj->pInventory[target]) == 0)
		{
			GCServerMsgStringSend(lMsg.Get(3370),lpObj->m_Index,1);
		}
	}

	return true;
}
Ejemplo n.º 2
0
IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder order)
{
	IBaseMenu *menu = md.menu;

	if (!menu)
	{
		return NULL;
	}

	struct
	{
		unsigned int position;
		ItemDrawInfo draw;
	} drawItems[10];

	/* Figure out how many items to draw */
	IMenuStyle *style = menu->GetDrawStyle();
	unsigned int pgn = menu->GetPagination();
	unsigned int maxItems = style->GetMaxPageItems();
	bool exitButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT;
	bool novoteButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_NOVOTE) == MENUFLAG_BUTTON_NOVOTE;

	if (pgn != MENU_NO_PAGINATION)
	{
		maxItems = pgn;
	}
	else if (exitButton)
	{
		maxItems--;
	}

	if (novoteButton)
	{
		maxItems--;
	}

	/* This is very not allowed! */
	if (maxItems < 2)
	{
		return NULL;
	}

	unsigned int totalItems = menu->GetItemCount();
	unsigned int startItem = 0;

	/* For pagination, find the starting point. */
	if (pgn != MENU_NO_PAGINATION)
	{
		if (order == ItemOrder_Ascending)
		{
			startItem = md.lastItem;
			/* This shouldn't happen with well-coded menus.
			 * If the item is out of bounds, switch the order to
			 * Items_Descending and make us start from the top.
			 */
			if (startItem >= totalItems)
			{
				startItem = totalItems - 1;
				order = ItemOrder_Descending;
			}
		}
		else if (order == ItemOrder_Descending)
		{
			startItem = md.firstItem;
			/* This shouldn't happen with well-coded menus.
			 * If searching backwards doesn't give us enough room,
			 * start from the beginning and change to ascending.
			 */
			if (startItem <= maxItems)
			{
				startItem = 0;
				order = ItemOrder_Ascending;
			}
		}
	}

	/* Get our Display pointer and initialize some crap */
	IMenuPanel *panel = menu->CreatePanel();
	IMenuHandler *mh = md.mh;
	bool foundExtra = false;
	unsigned int extraItem = 0;

	if (panel == NULL)
	{
		return NULL;
	}

	/**
	 * We keep searching until:
	 * 1) There are no more items
	 * 2) We reach one OVER the maximum number of slot items
	 * 3) We have reached maxItems and pagination is MENU_NO_PAGINATION
	 */
	unsigned int i = startItem;
	unsigned int foundItems = 0;
	while (totalItems)
	{
		ItemDrawInfo &dr = drawItems[foundItems].draw;
		/* Is the item valid? */
		if (menu->GetItemInfo(i, &dr) != NULL)
		{
			/* Ask the user to change the style, if necessary */
			mh->OnMenuDrawItem(menu, client, i, dr.style);
			/* Check if it's renderable */
			if (IsSlotItem(panel, dr.style))
			{
				/* If we've already found the max number of items,
				 * This means we should just cancel out and log our
				 * "last item."
				 */
				if (foundItems >= maxItems)
				{
					foundExtra = true;
					extraItem = i;
					break;
				}
				drawItems[foundItems++].position = i;
			}
		}
		/* If there's no pagination, stop once the menu is full. */
		if (pgn == MENU_NO_PAGINATION)
		{
			/* If we've filled up, then stop */
			if (foundItems >= maxItems)
			{
				break;
			}
		}
		/* If we're descending and this is the first item, stop */
		if (order == ItemOrder_Descending)
		{
			if (i == 0)
			{
				break;
			}
			i--;
		} 
		/* If we're ascending and this is the last item, stop */
		else if (order == ItemOrder_Ascending)
		{
			if (i >= totalItems - 1)
			{
				break;
			}
			i++;
		}
	}

	/* There were no items to draw! */
	if (!foundItems)
	{
		panel->DeleteThis();
		return NULL;
	}

	bool displayPrev = false;
	bool displayNext = false;

	/* This is an annoying process.
	 * Skip it for non-paginated menus, which get special treatment.
	 */
	if (pgn != MENU_NO_PAGINATION)
	{
		if (foundExtra)
		{
			if (order == ItemOrder_Descending)
			{
				displayPrev = true;
				md.firstItem = extraItem;
			}
			else if (order == ItemOrder_Ascending)
			{
				displayNext = true;
				md.lastItem = extraItem;
			}
		}

		unsigned int lastItem = 0;
		ItemDrawInfo dr;
		/* Find the last feasible item to search from. */
		if (order == ItemOrder_Descending)
		{
			lastItem = drawItems[0].position;
			if (lastItem >= totalItems - 1)
			{
				goto skip_search;
			}
			while (++lastItem < totalItems)
			{
				if (menu->GetItemInfo(lastItem, &dr) != NULL)
				{
					mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
					if (IsSlotItem(panel, dr.style))
					{
						displayNext = true;
						md.lastItem = lastItem;
						break;
					}
				}
			}
		}
		else if (order == ItemOrder_Ascending)
		{
			lastItem = drawItems[0].position;
			if (lastItem == 0)
			{
				goto skip_search;
			}
			lastItem--;
			while (lastItem != 0)
			{
				if (menu->GetItemInfo(lastItem, &dr) != NULL)
				{
					mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
					if (IsSlotItem(panel, dr.style))
					{
						displayPrev = true;
						md.firstItem = lastItem;
						break;
					}
				}
				lastItem--;
			}
		}
	}

skip_search:

	/* Draw the item according to the order */
	menu_slots_t *slots = md.slots;
	unsigned int position = 0;			/* Keep track of the last position */

	if (novoteButton)
	{
		char text[50];
		if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "No Vote", &client))
		{
			UTIL_Format(text, sizeof(text), "No Vote");
		}
		ItemDrawInfo dr(text, 0);
		position = panel->DrawItem(dr);
		slots[position].type = ItemSel_Exit;
		position++;
	}

	if (order == ItemOrder_Ascending)
	{
		md.item_on_page = drawItems[0].position;
		for (unsigned int i = 0; i < foundItems; i++)
		{
			ItemDrawInfo &dr = drawItems[i].draw;
			if ((position = mh->OnMenuDisplayItem(menu, client, panel, drawItems[i].position, dr)) == 0)
			{
				position = panel->DrawItem(dr);
			}
			if (position != 0)
			{
				slots[position].item = drawItems[i].position;
				if ((dr.style & ITEMDRAW_DISABLED) == ITEMDRAW_DISABLED)
				{
					slots[position].type = ItemSel_None;
				}
				else
				{
					slots[position].type = ItemSel_Item;
				}
			}
		}
	}
	else if (order == ItemOrder_Descending)
	{
		unsigned int i = foundItems;
		/* NOTE: There will always be at least one item because
		 * of the check earlier.
		 */
		md.item_on_page = drawItems[foundItems - 1].position;
		while (i--)
		{
			ItemDrawInfo &dr = drawItems[i].draw;
			if ((position = mh->OnMenuDisplayItem(menu, client, panel, drawItems[i].position, dr)) == 0)
			{
				position = panel->DrawItem(dr);
			}
			if (position != 0)
			{
				slots[position].item = drawItems[i].position;
				if ((dr.style & ITEMDRAW_DISABLED) == ITEMDRAW_DISABLED)
				{
					slots[position].type = ItemSel_None;
				}
				else
				{
					slots[position].type = ItemSel_Item;
				}
			}
		}
	}

	/* Now, we need to check if we need to add anything extra */
	if (pgn != MENU_NO_PAGINATION || exitButton)
	{
		bool canDrawDisabled = panel->CanDrawItem(ITEMDRAW_DISABLED|ITEMDRAW_CONTROL);
		bool exitBackButton = false;
		char text[50];

		if (pgn != MENU_NO_PAGINATION
			&& (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXITBACK)
		{
			exitBackButton = true;
		}

		/* Calculate how many items we are allowed for control stuff */
		unsigned int padding = style->GetMaxPageItems() - maxItems;
		
		/* Add the number of available slots */
		padding += (maxItems - foundItems);

		/* Someday, if we are able to re-enable this, we will be very lucky men. */
#if 0
		if (!style->FeatureExists(MenuStyleFeature_ImplicitExit))
		{
#endif
		/* Even if we don't draw an exit button, we invalidate the slot. */
		padding--;
#if 0
		} else {
			/* Otherwise, we don't draw anything and leave the slot available */
			exitButton = false;
		}
#endif

		if (pgn != MENU_NO_PAGINATION)
		{
			/* Subtract two slots for the displayNext/displayPrev padding */
			padding -= 2;
		}

		/* If we have an "Exit Back" button and the space to draw it, do so. */
		if (exitBackButton)
		{
			if (!displayPrev)
			{
				displayPrev = true;
			}
			else
			{
				exitBackButton = false;
			}
		}

		/**
		 * We allow next/prev to be undrawn if neither exists.
		 * Thus, we only need padding if one of them will be drawn,
		 * or the exit button will be drawn.
		 */
		ItemDrawInfo padItem(NULL, ITEMDRAW_SPACER);
		if (exitButton || (displayNext || displayPrev))
		{
			/* If there are no control options,
			 * Instead just pad with invisible slots.
			 */
			if (!displayPrev && !displayPrev)
			{
				padItem.style = ITEMDRAW_NOTEXT;
			}
			/* Add spacers so we can pad to the end */
			for (unsigned int i=0; i<padding; i++)
			{
				position = panel->DrawItem(padItem);
				slots[position].type = ItemSel_None;
			}
		}

		/* Put a fake spacer before control stuff, if possible */
		if ((displayPrev || displayNext) || exitButton)
		{
			ItemDrawInfo draw("", ITEMDRAW_RAWLINE|ITEMDRAW_SPACER);
			panel->DrawItem(draw);
		}

		ItemDrawInfo dr(text, 0);

		/**
		 * If we have one or the other, we need to have spacers for both.
		 */
		if (pgn != MENU_NO_PAGINATION)
		{
			if (displayPrev || displayNext)
			{
				/* PREVIOUS */
				ItemDrawInfo padCtrlItem(NULL, ITEMDRAW_SPACER|ITEMDRAW_CONTROL);
				if (displayPrev || canDrawDisabled)
				{
					if (exitBackButton)
					{
						if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Back", &client))
						{
							UTIL_Format(text, sizeof(text), "Back");
						}
						dr.style = ITEMDRAW_CONTROL;
						position = panel->DrawItem(dr);
						slots[position].type = ItemSel_ExitBack;
					}
					else
					{
						if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Previous", &client))
						{
							UTIL_Format(text, sizeof(text), "Previous");
						}
						dr.style = (displayPrev ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL;
						position = panel->DrawItem(dr);
						slots[position].type = ItemSel_Back;
					}
				}
				else if (displayNext || exitButton)
				{
					/* If we can't display this, and there is an exit button,
					 * we need to pad!
					 */
					position = panel->DrawItem(padCtrlItem);
					slots[position].type = ItemSel_None;
				}

				/* NEXT */
				if (displayNext || canDrawDisabled)
				{
					if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Next", &client))
					{
						UTIL_Format(text, sizeof(text), "Next");
					}
					dr.style = (displayNext ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL;
					position = panel->DrawItem(dr);
					slots[position].type = ItemSel_Next;
				}
				else if (exitButton)
				{
					/* If we can't display this,
					 * but there is an "exit" button, we need to pad!
					 */
					position = panel->DrawItem(padCtrlItem);
					slots[position].type = ItemSel_None;
				}
			}
			else
			{
				/* Otherwise, bump to two slots! */
				ItemDrawInfo numBump(NULL, ITEMDRAW_NOTEXT);
				position = panel->DrawItem(numBump);
				slots[position].type = ItemSel_None;
				position = panel->DrawItem(numBump);
				slots[position].type = ItemSel_None;
			}
		}

		/* EXIT */
		if (exitButton)
		{
			if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Exit", &client))
			{
				UTIL_Format(text, sizeof(text), "Exit");
			}
			dr.style = ITEMDRAW_CONTROL;
			position = panel->DrawItem(dr);
			slots[position].type = ItemSel_Exit;
		}
	}

	/* Lastly, fill in any slots we could have missed */
	for (unsigned int i = position + 1; i < 10; i++)
	{
		slots[i].type = ItemSel_None;
	}

	/* Do title stuff */
	mh->OnMenuDisplay(menu, client, panel);
	panel->DrawTitle(menu->GetDefaultTitle(), true);

	return panel;
}