Jump to content
Maintenance : Final step ×

Legendary items effect


Recommended Posts

  • Active+ Member

hi, long story short

i've seen some global servers adding a certain effects to some items to make them LEGENDARY

and i think it looks cool

so i've decided to code it and make it public

and this is a gif to show u what i mean

spacer.png

spacer.png

 

 

Downsides

- The alpha is a miss for some unknown reason

- the effect won't apply on items that dosen't use SLOT

 

 

other than that it's great,

and you can choose a certain set of items and apply a certain color on each set too

 

for example

	0: ((19, 40101, 41117, 45053), (1.0, 1.0, 1.0, 1.0)),
	1: ((18, 40102, 41118, 45054), (0.5, 1.0, 1.0, 1.0)),

 

link:

Spoiler

This is the hidden content, please

This is the hidden content, please

 

  • Metin2 Dev 66
  • Good 15
  • muscle 1
  • Love 2
  • Love 33
Link to comment
Share on other sites

  • Active+ Member
56 minutes ago, Hekate said:

Hi, im working on (martysama) files but u can try to adjust your source whatever it's like this

PythonWindow.cpp

Spoiler
#if defined(ENABLE_LEGENDARY_SLOT_EFFECT)
	void CAniImageBox::AppendImage(const char * c_szFileName, float r, float g, float b, float a)
#else
	void CAniImageBox::AppendImage(const char * c_szFileName)
#endif
	{
		CResource * pResource = CResourceManager::Instance().GetResourcePointer(c_szFileName);
		if (!pResource->IsType(CGraphicImage::Type()))
			return;

		CGraphicExpandedImageInstance * pImageInstance = CGraphicExpandedImageInstance::New();
		pImageInstance->SetImagePointer(static_cast<CGraphicImage*>(pResource));
#if defined(ENABLE_LEGENDARY_SLOT_EFFECT)
		pImageInstance->SetDiffuseColor(r, g, b, a);
#endif

		if (pImageInstance->IsEmpty())
		{
			CGraphicExpandedImageInstance::Delete(pImageInstance);
			return;
		}

		m_ImageVector.push_back(pImageInstance);
		m_bycurIndex = rand() % m_ImageVector.size();
	}

 

PythonWindow.h

Spoiler
#if defined(ENABLE_LEGENDARY_SLOT_EFFECT)
			void	AppendImage(const char * c_szFileName, float r = 1.0, float g = 1.0, float b = 1.0, float a = 1.0);
#else
			void	AppendImage(const char * c_szFileName);
#endif

 

 

 

Edited by CONTROL
  • Love 1
Link to comment
Share on other sites

  • Honorable Member

Nice idea.

Yesterday I  wanted to mention that the guide might be wrong for some people whom have no clue about the things, in this case the custom AppendImage from the Sash system by LeNnT or whoever.

Alpha channel is a thing, not that hard to deal with it, but you forgot to refresh the links after you managed to fix them ?.
Also white image might be better to recolor with diffuse.

Spoiler

spacer.png

 

  • Lmao 1
  • Love 1
Link to comment
Share on other sites

  • Active+ Member
7 hours ago, xP3NG3Rx said:

Nice idea.

Yesterday I  wanted to mention that the guide might be wrong for some people whom have no clue about the things, in this case the custom AppendImage from the Sash system by LeNnT or whoever.

Alpha channel is a thing, not that hard to deal with it, but you forgot to refresh the links after you managed to fix them ?.
Also white image might be better to recolor with diffuse.

  Hide contents

spacer.png

 

- the problem wasn't the alpha channel tho it was something with the RenderingMode XD

- sry, im not really active in here and i didn't know how to edit the topic so i just report it to the mod with the new link

- i didn't really make the pics my self, a friend just sent them to me with the idea 

Edited by CONTROL
Link to comment
Share on other sites

  • 3 weeks later...
  • Active+ Member
6 hours ago, boloca said:

I'm having trouble giving different colors. Can you give a few more examples?

just use Google 

search for (color picker) and you'll find a tool that can show you the rgp etc..

this is like the ABC of programing, i won't give you anymore help about it.

Edited by CONTROL
Link to comment
Share on other sites

On 04/06/2024 at 12:09, CONTROL said:

basta usar o Google 

procure por (seletor de cores) e você encontrará uma ferramenta que pode mostrar o rgp etc.

isso é como o ABC da programação,  não vou mais te ajudar sobre isso.

I know this, however, no matter how much I change the colors, nothing changes within the game.

Link to comment
Share on other sites

  • 2 months later...
  • Active+ Member
On 5/17/2024 at 10:57 PM, KingzZ said:

It´s lagy if start switchbot

my apologies,

you were right the effect will reset each time the inventory updates

to solve this issue you have to 

Spoiler
change

		if (pActiveEff)
		{
			delete pActiveEff;
			pActiveEff = nullptr;
		}

to

		if (pActiveEff)
			return;

 

same thing goes for all the functions that uses this method like the ActivateEffect or whatever 

this should fix the updating issue

 

BUT THAT DOSEN'T CHANGE THE FACT THAT YOU SHOULD NEVER SPAM THE SHIT OUT OF YOUR INVENTORY !! 

 

and to give you a little hint about how you can avoid that,

you can make a separate slots for your special enchants inside the switchbot itself so you wouldn't have to update your inventory so frequently

Spoiler
enum SwitchbotValues
{
#if defined(__SWITCHBOT_PENDANT_CHANGER__) && defined(__SWITCHBOT_ADVANCE_CHANGER__)
	SWITCHBOT_SLOT_COUNT = 8,
#else
	SWITCHBOT_SLOT_COUNT = 6,
#endif
	SWITCHBOT_SLOT_COUNT_REAL = 5,
	SWITCHBOT_ALTERNATIVE_COUNT = 2,

	SWITCHBOT_PRICE_TYPE = 1,
	SWITCHBOT_PRICE_AMOUNT = 1,
#ifdef ENABLE_SWITCHBOT_YANG
	SWITCHBOT_LOW_YANG_PRICE = 100,
	SWITCHBOT_HIGH_YANG_PRICE = 200,
#endif
};

 

 

this will allow you to take the enchants from a known slot instead of looping over your entire inventory every 0.5s or whatever

Spoiler
	if (switchItem && HaveTheGold)
	{
		const WORD itemCount = switchItem->GetCount();
		if (itemCount <= SWITCHBOT_PRICE_AMOUNT) {
			m_table.items[EnchantSlot] = 0;
			switchItem->SetUpdateStatus(false);
		}
		switchItem->SetCount(itemCount - SWITCHBOT_PRICE_AMOUNT);
		pkOwner->PointChange(POINT_GOLD, - SWITCHBOT_HIGH_YANG_PRICE);
	}
	else {
		return;
	}

 

 

Link to comment
Share on other sites

I think it is tiring to put all the weapon and armor codes.
I modified the code to make it easier to get the weapon or armor level.

in ui.py 
Find: def SetItemSlot(self, renderingSlotNumber, ItemIndex, ItemCount = 0, diffuseColor = (1.0, 1.0, 1.0, 1.0)):
replace with:

def SetItemSlot(self, renderingSlotNumber, ItemIndex, ItemCount = 0, diffuseColor = (1.0, 1.0, 1.0, 1.0)):
		if 0 == ItemIndex or None == ItemIndex:
			wndMgr.ClearSlot(self.hWnd, renderingSlotNumber)
			return

		item.SelectItem(ItemIndex)
		itemIcon = item.GetIconImage()

		item.SelectItem(ItemIndex)
		(width, height) = item.GetItemSize()

		wndMgr.SetSlot(self.hWnd, renderingSlotNumber, ItemIndex, width, height, itemIcon, diffuseColor)
		wndMgr.SetSlotCount(self.hWnd, renderingSlotNumber, ItemCount)

		if app.ENABLE_LEGENDARY_SLOT_EFFECT:
			if ItemIndex > 0:
				wndMgr.ActivateLegendaryEffect(self.hWnd, renderingSlotNumber, *legendaryitems.GetEffectColor(ItemIndex))
			else:
				wndMgr.DeactivateLegendaryEffect(self.hWnd, renderingSlotNumber)


in legendaryitems.py
replace all with:

import item

EFFECTS = {
    "WEAPON": {
        30: (0.3, 0.3, 0.3, 0.4),  # Common
        65: (0.0, 1.0, 0.0, 0.7),  # Uncommon
        75: (0.0, 0.5, 1.0, 0.7),  # Rare
        90: (1.0, 0.0, 1.0, 0.7),  # Epic
        105: (1.0, 0.8, 0.0, 0.8), # Legendary
    },
    "ARMOR": {  # Armor
        30: (1.0, 1.0, 1.0, 0.4),  # Common
    }
}

def GetEffectColor(ItemIndex):
    # select the item based on the ItemIndex
    item.SelectItem(ItemIndex)
    itemType = item.GetItemType()  # return itemType of the item

    # select the effect_type based on the itemType
    if itemType == item.ITEM_TYPE_WEAPON:
        effect_type = "WEAPON"
    elif itemType == item.ITEM_TYPE_ARMOR:
        effect_type = "ARMOR"
    else:
        return (0.0, 0.0, 0.0, 0.0)  # default color

    # search for the limitValue in the EFFECTS dictionary
    for i in range(item.LIMIT_MAX_NUM):
        limitValue = item.GetLimit(i)[1]  # return limitValue of the item
        
        # if limitValue is in the EFFECTS dictionary, return the color
        if limitValue in EFFECTS[effect_type]:
            return EFFECTS[effect_type][limitValue]

    # default color
    return (0.0, 0.0, 0.0, 0.0)

 

Edited by xRooT
Link to comment
Share on other sites

  • 1 month later...

@xRooT Thx for idea 😛

Spoiler
import item

MYTHOS_COLOR = (1.0, 1.0, 0.0, 1.0)

EFFECTS = {
	"WEAPON": {
		30: {"+%d" % i: MYTHOS_COLOR for i in xrange(10)},
		75: {"+%d" % i: MYTHOS_COLOR for i in xrange(10)},
	},

	"ARMOR": {},
}

def GetEffectColor(ItemIndex):
	item.SelectItem(ItemIndex)

	itemType = item.GetItemType()
	itemName = item.GetItemName()

	if itemType == item.ITEM_TYPE_WEAPON:
		effect_type = "WEAPON"
	elif itemType == item.ITEM_TYPE_ARMOR:
		effect_type = "ARMOR"
	else:
		return (0.0, 0.0, 0.0, 0.0)

	for i in xrange(item.LIMIT_MAX_NUM):
		limit_value = item.GetLimit(i)[1]
		if limit_value in EFFECTS.get(effect_type, {}):
			for upgrade_level in ["+%d" % i for i in xrange(10)]:
				if upgrade_level in itemName:
					return EFFECTS[effect_type][limit_value][upgrade_level]

	return (0.0, 0.0, 0.0, 0.0)

 

Now you can use more things like flag "+7" antiflags, flags, level, colors, etc..

 

@ CONTROL

On 9/10/2024 at 9:29 AM, CONTROL said:

my apologies,

you were right the effect will reset each time the inventory updates

to solve this issue you have to 

  Reveal hidden contents
change

		if (pActiveEff)
		{
			delete pActiveEff;
			pActiveEff = nullptr;
		}

to

		if (pActiveEff)
			return;

 

same thing goes for all the functions that uses this method like the ActivateEffect or whatever 

this should fix the updating issue

 

BUT THAT DOSEN'T CHANGE THE FACT THAT YOU SHOULD NEVER SPAM THE SHIT OUT OF YOUR INVENTORY !! 

 

and to give you a little hint about how you can avoid that,

you can make a separate slots for your special enchants inside the switchbot itself so you wouldn't have to update your inventory so frequently

  Reveal hidden contents
enum SwitchbotValues
{
#if defined(__SWITCHBOT_PENDANT_CHANGER__) && defined(__SWITCHBOT_ADVANCE_CHANGER__)
	SWITCHBOT_SLOT_COUNT = 8,
#else
	SWITCHBOT_SLOT_COUNT = 6,
#endif
	SWITCHBOT_SLOT_COUNT_REAL = 5,
	SWITCHBOT_ALTERNATIVE_COUNT = 2,

	SWITCHBOT_PRICE_TYPE = 1,
	SWITCHBOT_PRICE_AMOUNT = 1,
#ifdef ENABLE_SWITCHBOT_YANG
	SWITCHBOT_LOW_YANG_PRICE = 100,
	SWITCHBOT_HIGH_YANG_PRICE = 200,
#endif
};

 

 

this will allow you to take the enchants from a known slot instead of looping over your entire inventory every 0.5s or whatever

  Reveal hidden contents
	if (switchItem && HaveTheGold)
	{
		const WORD itemCount = switchItem->GetCount();
		if (itemCount <= SWITCHBOT_PRICE_AMOUNT) {
			m_table.items[EnchantSlot] = 0;
			switchItem->SetUpdateStatus(false);
		}
		switchItem->SetCount(itemCount - SWITCHBOT_PRICE_AMOUNT);
		pkOwner->PointChange(POINT_GOLD, - SWITCHBOT_HIGH_YANG_PRICE);
	}
	else {
		return;
	}

 

 

This is rlly BAD idea.. Did you tried this? Meaning this:

change

		if (pActiveEff)
		{
			delete pActiveEff;
			pActiveEff = nullptr;
		}

to

		if (pActiveEff)
			return;

 

  • Love 1
Link to comment
Share on other sites

  • Active+ Member
9 hours ago, Filachilla said:

@xRooT Thx for idea 😛

  Reveal hidden contents
import item

MYTHOS_COLOR = (1.0, 1.0, 0.0, 1.0)

EFFECTS = {
	"WEAPON": {
		30: {"+%d" % i: MYTHOS_COLOR for i in xrange(10)},
		75: {"+%d" % i: MYTHOS_COLOR for i in xrange(10)},
	},

	"ARMOR": {},
}

def GetEffectColor(ItemIndex):
	item.SelectItem(ItemIndex)

	itemType = item.GetItemType()
	itemName = item.GetItemName()

	if itemType == item.ITEM_TYPE_WEAPON:
		effect_type = "WEAPON"
	elif itemType == item.ITEM_TYPE_ARMOR:
		effect_type = "ARMOR"
	else:
		return (0.0, 0.0, 0.0, 0.0)

	for i in xrange(item.LIMIT_MAX_NUM):
		limit_value = item.GetLimit(i)[1]
		if limit_value in EFFECTS.get(effect_type, {}):
			for upgrade_level in ["+%d" % i for i in xrange(10)]:
				if upgrade_level in itemName:
					return EFFECTS[effect_type][limit_value][upgrade_level]

	return (0.0, 0.0, 0.0, 0.0)

 

Now you can use more things like flag "+7" antiflags, flags, level, colors, etc..

 

@ CONTROL

This is rlly BAD idea.. Did you tried this? Meaning this:

change

		if (pActiveEff)
		{
			delete pActiveEff;
			pActiveEff = nullptr;
		}

to

		if (pActiveEff)
			return;

 

Yes, works perfectly for me.

  • Love 1
Link to comment
Share on other sites

  • Active+ Member
23 hours ago, Filachilla said:

You never refresh slot again, so when you move item, slot stayed with effect.. 😄 Why? Because you place effect on slot and when you move item, slot is not restarted

giphy.gif

 

as i said works fine for me

+ i didn't really gave it that much attention cuz i don't like how the PythonSlotWindow works im gonna rewrite the entier thing anyway so..

Edited by Metin2 Dev International
Core X - External 2 Internal
Link to comment
Share on other sites

On 11/1/2024 at 4:49 PM, CONTROL said:

giphy.gif

 

as i said works fine for me

+ i didn't really gave it that much attention cuz i don't like how the PythonSlotWindow works im gonna rewrite the entier thing anyway so..

Did you have original slot functions? Because in original marty 5.8 with last updates, I never refresh slot again when I put only return in function.. My effect is placed on slot and not on item, so when I move item, effect still stayed on slot

Edit: Can you share some pieces of code for some debug? Would be fine see PythonSlot

Edited by Filachilla
Link to comment
Share on other sites

  • Active+ Member
13 hours ago, Filachilla said:

Did you have original slot functions? Because in original marty 5.8 with last updates, I never refresh slot again when I put only return in function.. My effect is placed on slot and not on item, so when I move item, effect still stayed on slot

Edit: Can you share some pieces of code for some debug? Would be fine see PythonSlot

i used the LeNnT way which was my bad from the beginning it's bad and it cause stutter i deleted the previous code and this is how i recoded the system

PythonSlotWindow.cpp

Spoiler
void CSlotWindow::ClearSlot(TSlot * pSlot)
{
#ifdef ENABLE_LEGENDARY_SLOT_EFFECT
	pSlot->bLegendaryActive = false;
#endif

 

void CSlotWindow::OnUpdate()
{

	[...]
	m_ReserveDestroyEffectDeque.clear();

#ifdef ENABLE_LEGENDARY_SLOT_EFFECT
	for (auto* effect : pActiveLegendarySlotEffect) {
		if (effect)
			effect->Update();
	}
#endif

 

void CSlotWindow::OnRender()
{
		[...]
		if (rSlot.pFinishCoolTimeEffect)
		{
			rSlot.pFinishCoolTimeEffect->SetPosition(rSlot.ixPosition, rSlot.iyPosition);
			rSlot.pFinishCoolTimeEffect->Update();
			rSlot.pFinishCoolTimeEffect->Render();
		}

#ifdef ENABLE_LEGENDARY_SLOT_EFFECT
		if (rSlot.bLegendaryActive)
		{
			if (pActiveLegendarySlotEffect[0] || pActiveLegendarySlotEffect[1] || pActiveLegendarySlotEffect[2])
			{
				int ix = m_rect.left + rSlot.ixPosition;
				int iy = m_rect.top + rSlot.iyPosition;
				int highlight = rSlot.byyPlacedItemSize - 1;
				pActiveLegendarySlotEffect[highlight]->Show();
				pActiveLegendarySlotEffect[highlight]->SetPosition(ix, iy);
				pActiveLegendarySlotEffect[highlight]->Render();
			}
		}
#endif
void CSlotWindow::__Initialize()
{
	[...]
	m_pToggleSlotImage = NULL;
#ifdef ENABLE_LEGENDARY_SLOT_EFFECT
	for (uint8_t i = 0; i < 3; ++i)
		pActiveLegendarySlotEffect[i] = nullptr;
#endif

 

void CSlotWindow::Destroy()
{
	[...]
	__DestroyBaseImage();
#ifdef ENABLE_LEGENDARY_SLOT_EFFECT
	__DestroySlotLegendaryEffect();
#endif

 

// Add wherever the hell u want

#ifdef ENABLE_LEGENDARY_SLOT_EFFECT
void CSlotWindow::ActivateLegendaryEffect(DWORD dwSlotIndex, float r, float g, float b, float a)
{
	TSlot * pSlot;
	if (!GetSlotPointer(dwSlotIndex, &pSlot))
		return;

	pSlot->bLegendaryActive = true;
	
	for (uint8_t i = 0; i < 3; i++) 
	{
		if (!pActiveLegendarySlotEffect[i])
			__CreateSlotLegendaryEffect(r, g, b, a);
	}
}

void CSlotWindow::__CreateSlotLegendaryEffect(float r, float g, float b, float a)
{
	__DestroySlotLegendaryEffect();

	for (uint8_t i = 0; i < 3; ++i)
	{
		CAniImageBox* pEff = new CAniImageBox(nullptr);
		const int ciImageCount = 60;
		for (uint8_t j = 0; j <= ciImageCount ; ++j)
		{
			char cBuf[72];
			snprintf(cBuf, sizeof(cBuf), "d:/ymir work/ui/public/rarityeffect/slot%d/diamond_%dslot_%03d.png", (i + 1), (i + 1), j);
			pEff->AppendImage(cBuf, r, g, b, a);
		}

		pEff->SetRenderingMode(CGraphicExpandedImageInstance::RENDERING_MODE_NORMAL);
		pActiveLegendarySlotEffect[i] = pEff;
	}
}

void CSlotWindow::DeactivateLegendaryEffect(DWORD dwSlotIndex)
{
	TSlot * pSlot;
	if (!GetSlotPointer(dwSlotIndex, &pSlot))
		return;

	pSlot->bLegendaryActive = false;
}

void CSlotWindow::__DestroySlotLegendaryEffect()
{
	for (uint8_t i = 0; i < 3; ++i)
	{
		if (pActiveLegendarySlotEffect[i]) {
			delete pActiveLegendarySlotEffect[i];
			pActiveLegendarySlotEffect[i] = nullptr;
		}
	}
}
#endif

 

 

PythonSlotWindow.h

Spoiler
				BOOL	bActive;
#ifdef ENABLE_LEGENDARY_SLOT_EFFECT
				bool	bLegendaryActive;
#endif

 

			// CallBack
			void ReserveDestroyCoolTimeFinishEffect(DWORD dwSlotIndex);

#ifdef ENABLE_LEGENDARY_SLOT_EFFECT
			void ActivateLegendaryEffect(DWORD dwSlotIndex, float r, float g, float b, float a);
			void DeactivateLegendaryEffect(DWORD dwSlotIndex);
			
			void __CreateSlotLegendaryEffect(float r, float g, float b, float a);
			void __DestroySlotLegendaryEffect();
#endif

 


			CImageBox * m_pToggleSlotImage;
#ifdef ENABLE_LEGENDARY_SLOT_EFFECT
			CAniImageBox*	pActiveLegendarySlotEffect[3];
#endif

 

 

  • Love 1
Link to comment
Share on other sites

  • 4 weeks later...
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.