Whenever I was playing on any server that had far too many drop items from monsters — I wondered — how am I going to find myself in this pile of scrap? You click on one item and pick up a completely different one, thus littering your inventory.
With my solution, your players don't have to worry about it anymore.
Pros:
- You don't have to worry about items gained by other players;
- The alphabetical list will allow you to easily find the acquired item;
- The dynamic list cleans and completes itself on a regular basis;
- You can still pick up items directly from the floor;
- You can show and hide the window whenever you want to use it;
- If the item isn't yours then your player name in ownership color will be red instead of yellow;
- You do not have to worry that your list will be flooded with items that have been lying on the ground for a long time — only the items you have acquired will go to the list;
- You can double-click on the name of the item and the character will automatically move towards it with the intention of picking up;
- You can refresh the list by yourself;
- You can select an item from the list and pick it up from the ground with one button.
Min:
- You still need to be close to the item to pick it up — but it's probably fair;
- Sometime you must click twice on item name because of too far distance (by default).
YouTube video explanation (click on image):
- Python uidroplist.py
- Python constInfo.py
- Python game.py
- Python droplistwindow
- locale_game.txt and locale_interface.txt
- C++ locale_inc.h
- C++ PythonPlayer
- C++ PythonTextTail
Go back to installation list ⬆️
- Place uidroplist.py inside root directory.
Go back to installation list ⬆️
- Open constInfo.py inside root directory:
PVPMODE_PROTECTED_LEVEL = 15
DROPLIST_VID_AND_ITEM_NAME = {}
OWN_ITEM_VID = []
DROP_LIST_REFRESH = 0
DROP_LIST_LAST = ""
DROP_LIST_DOUBLE = 0
DROP_LIST_SLIDER = 0
def SET_TWO_HANDED_WEAPON_ATT_SPEED_DECREASE_VALUE():
global TWO_HANDED_WEAPON_ATT_SPEED_DECREASE_VALUE
app.SetTwoHandedWeaponAttSpeedDecreaseValue(TWO_HANDED_WEAPON_ATT_SPEED_DECREASE_VALUE)
def DropListAppend(vid, item_name):
global DROPLIST_VID_AND_ITEM_NAME
append = {vid : item_name}
DROPLIST_VID_AND_ITEM_NAME.update(append)
def DropListMyItem(vid):
global OWN_ITEM_VID
global DROP_LIST_REFRESH
OWN_ITEM_VID.append(vid)
DROP_LIST_REFRESH = 1
def RemoveFromDropList(vid):
global DROPLIST_VID_AND_ITEM_NAME
global OWN_ITEM_VID
global DROP_LIST_REFRESH
if DROPLIST_VID_AND_ITEM_NAME and OWN_ITEM_VID:
if vid in DROPLIST_VID_AND_ITEM_NAME:
del DROPLIST_VID_AND_ITEM_NAME[vid]
OWN_ITEM_VID.remove(vid)
DROP_LIST_REFRESH = 1
Go back to installation list ⬆️
- Open game.py inside root directory:
import interfaceModule
import uidroplist
self.quickSlotPageIndex = 0
self.dropListDlg = 0
def __BuildKeyDict(self):
onPressKeyDict[app.DIK_F4] = lambda : self.__PressQuickSlot(7)
onPressKeyDict[app.DIK_F5] = lambda : self.ScanDropList()
You can change Key DIK if you want to
def StopRight(self):
player.SetSingleDIKKeyState(app.DIK_RIGHT, False)
def ScanDropList(self):
if not self.dropListDlg:
self.dropListDlg=uidroplist.FileListDialog()
self.dropListDlg.Open()
def DropListUpdate(self, vid, name):
constInfo.DropListAppend(int(vid), str(name))
def DropListOwn(self, vid):
constInfo.DropListMyItem(int(vid))
def RemoveVidFromList(self, vid):
constInfo.RemoveFromDropList(int(vid))
Go back to installation list ⬆️
- Place droplistwindow.py inside uiscript directory.
Go back to installation list ⬆️
- Paste the relevant entries in locale_interface.txt and locale_game.txt inside locale directory.
Go back to installation list ⬆️
- Open locale_inc.h inside UserInterface directory:
#define ENABLE_DROPLIST_WINDOW
Go back to installation list ⬆️
- Open PythonPlayer.h inside UserInterface directory:
void SendClickItemPacket(DWORD dwIID);
#ifdef ENABLE_DROPLIST_WINDOW
void SendClickItemPacketDropList(DWORD dwIID);
#endif
void ClearSkillDict();
#ifdef ENABLE_DROPLIST_WINDOW
void DropListAppend(DWORD VID, string Item_Name);
void DropListOwn(DWORD VID);
void RemoveFromOwnList(DWORD VID);
#endif
- Open PythonPlayer.cpp inside UserInterface directory:
void CPythonPlayer::ClearSkillDict()
{
...
}
#ifdef ENABLE_DROPLIST_WINDOW
void CPythonPlayer::DropListAppend(DWORD VID, string Item_Name)
{
PyCallClassMemberFunc(m_ppyGameWindow, "DropListUpdate", Py_BuildValue("(is)", VID, Item_Name.c_str()));
}
void CPythonPlayer::DropListOwn(DWORD VID)
{
PyCallClassMemberFunc(m_ppyGameWindow, "DropListOwn", Py_BuildValue("(i)", VID));
}
void CPythonPlayer::RemoveFromOwnList(DWORD VID)
{
PyCallClassMemberFunc(m_ppyGameWindow, "RemoveVidFromList", Py_BuildValue("(i)", VID));
}
#endif
DWORD CPythonPlayer::GetPlayTime()
{
return m_dwPlayTime;
}
#ifdef ENABLE_DROPLIST_WINDOW
void CPythonPlayer::SendClickItemPacketDropList(DWORD dwIID)
{
CInstanceBase* pkInstMain = NEW_GetMainActorPtr();
if (!pkInstMain)
return;
if (IsObserverMode())
return;
if (pkInstMain->IsStun())
return;
if (pkInstMain->IsDead())
return;
CPythonItem& rkIT = CPythonItem::Instance();
TPixelPosition kPPosPickedItem;
if (rkIT.GetGroundItemPosition(dwIID, &kPPosPickedItem))
{
float distance = 120.0f;
if (pkInstMain->IsMountingHorse() || pkInstMain->IsNewMount())
distance = 150.0f;
if (pkInstMain->NEW_GetDistanceFromDestPixelPosition(kPPosPickedItem) < distance)
{
CPythonNetworkStream& rkNetStream = CPythonNetworkStream::Instance();
TPixelPosition kPPosCur;
pkInstMain->NEW_GetPixelPosition(&kPPosCur);
float fCurRot = pkInstMain->GetRotation();
rkNetStream.SendCharacterStatePacket(kPPosCur, fCurRot, CInstanceBase::FUNC_WAIT, 0);
pkInstMain->NEW_Stop();
__ClearReservedAction();
SendClickItemPacket(dwIID);
}
else
{
pkInstMain->NEW_MoveToDestPixelPositionDirection(kPPosPickedItem);
SendClickItemPacket(dwIID);
}
}
else
{
__ClearReservedAction();
SendClickItemPacket(dwIID);
}
}
#endif
Go back to installation list ⬆️
- Open PythonTextTail.cpp inside UserInterface directory:
void CPythonTextTail::RegisterItemTextTail(DWORD VirtualID, const char * c_szText, CGraphicObjectInstance * pOwner
In xP3NG3Rx [C++] ItemName reneval on the ground RegisterItemTextTail ends with bool bHasAttr
TTextTail * pTextTail = RegisterTextTail(VirtualID, c_szText, pOwner, c_TextTail_Name_Position,
In xP3NG3Rx [C++] ItemName reneval on the ground pTextTail = RegisterTextTail ends with c_d3dColor
#ifdef ENABLE_DROPLIST_WINDOW
CPythonPlayer::Instance().DropListAppend(VirtualID, c_szText);
#endif
void CPythonTextTail::DeleteItemTextTail(DWORD VirtualID)
DeleteTextTail(itor->second);
#ifdef ENABLE_DROPLIST_WINDOW
CPythonPlayer::Instance().RemoveFromOwnList(VirtualID);
#endif
❗ Important ❗
If you're using xP3NG3Rx [C++] ItemName reneval on the ground from metin2dev - then use this part.
If not use part below:
void CPythonTextTail::SetItemTextTailOwner(DWORD dwVID, const char * c_szName)
{
...
}
it's extended item text tail color version but without item attr coloring
void CPythonTextTail::SetItemTextTailOwner(DWORD dwVID, const char * c_szName)
{
TTextTailMap::iterator itor = m_ItemTextTailMap.find(dwVID);
if (m_ItemTextTailMap.end() == itor)
return;
TTextTail * pTextTail = itor->second;
if (strlen(c_szName) > 0)
{
if (!pTextTail->pOwnerTextInstance)
pTextTail->pOwnerTextInstance = CGraphicTextInstance::New();
pTextTail->pOwnerTextInstance->SetTextPointer(ms_pFont);
pTextTail->pOwnerTextInstance->SetHorizonalAlign(CGraphicTextInstance::HORIZONTAL_ALIGN_CENTER);
pTextTail->pOwnerTextInstance->SetValue(c_szName);
CInstanceBase * pInstance = CPythonCharacterManager::Instance().GetMainInstancePtr();
if (pInstance)
{
if (!strcmp(pInstance->GetNameString(), c_szName))
{
pTextTail->pOwnerTextInstance->SetColor(1.0f, 1.0f, 0.0f);
#ifdef ENABLE_DROPLIST_WINDOW
CPythonPlayer::Instance().DropListOwn(pTextTail->dwVirtualID);
#endif
}
else
pTextTail->pOwnerTextInstance->SetColor(1.0f, 0.0f, 0.0f);
}
pTextTail->pOwnerTextInstance->Update();
int xOwnerSize, yOwnerSize;
pTextTail->pOwnerTextInstance->GetTextSize(&xOwnerSize, &yOwnerSize);
pTextTail->yStart = -2.0f;
pTextTail->yEnd += float(yOwnerSize + 4);
pTextTail->xStart = fMIN(pTextTail->xStart, float(-xOwnerSize / 2 - 1));
pTextTail->xEnd = fMAX(pTextTail->xEnd, float(xOwnerSize / 2 + 1));
}
else
{
if (pTextTail->pOwnerTextInstance)
{
CGraphicTextInstance::Delete(pTextTail->pOwnerTextInstance);
pTextTail->pOwnerTextInstance = NULL;
}
int xSize, ySize;
pTextTail->pTextInstance->GetTextSize(&xSize, &ySize);
pTextTail->xStart = (float) (-xSize / 2 - 2);
pTextTail->yStart = -2.0f;
pTextTail->xEnd = (float) (xSize / 2 + 2);
pTextTail->yEnd = (float) ySize;
}
}
❗ Use only with xP3NG3Rx [C++] ItemName reneval on the ground ❗ if not - use RegisterItemTextTail from above.
void CPythonTextTail::RegisterItemTextTail(DWORD VirtualID, const char * c_szText, CGraphicObjectInstance * pOwner, bool bHasAttr)
{
...
#ifdef ENABLE_EXTENDED_ITEMNAME_ON_GROUND
CInstanceBase * pInstance = CPythonCharacterManager::Instance().GetMainInstancePtr();
if (pInstance)
{
if (!strcmp(pInstance->GetNameString(), c_szName))
pTextTail->pOwnerTextInstance->SetColor(1.0f, 1.0f, 0.0f);
else
pTextTail->pOwnerTextInstance->SetColor(1.0f, 0.0f, 0.0f);
}
#else
#ifdef ENABLE_EXTENDED_ITEMNAME_ON_GROUND
CInstanceBase * pInstance = CPythonCharacterManager::Instance().GetMainInstancePtr();
if (pInstance)
{
if (!strcmp(pInstance->GetNameString(), c_szName))
{
pTextTail->pOwnerTextInstance->SetColor(1.0f, 1.0f, 0.0f);
#ifdef ENABLE_DROPLIST_WINDOW
CPythonPlayer::Instance().DropListOwn(pTextTail->dwVirtualID);
#endif
}
else
pTextTail->pOwnerTextInstance->SetColor(1.0f, 0.0f, 0.0f);
}
#else