Passing class type?

  • (2 Pages)
  • +
  • 1
  • 2

20 Replies - 1601 Views - Last Post: 15 April 2013 - 08:29 AM Rate Topic: -----

#16 kiasta  Icon User is offline

  • D.I.C Regular

Reputation: 22
  • View blog
  • Posts: 260
  • Joined: 18-November 07

Re: Passing class type?

Posted 09 April 2013 - 12:56 PM

That's true, but the problem is my base types are just child classes of parent classes: BaseArmor, BaseWeapon, etc. I just made base types so I can use the deeds only on these items and not all of them. It would be a lot of work to make a base type for all pieces of armor since each type has different types and are child classes of Item and several others. I really can't think of a better way to figure out the type without the if/else statements. Though it's a good idea to make a base type for all the item types. If I could do something like this:

public class BaseDragonkin : BaseArmor, BaseClothing, BaseJewel, BaseShield, BaseWeapon



The problem is I get errors when trying to add constructors, for instance BaseArmor takes this constructor:

public BaseDragonkinArmor(int itemID) : base(itemID)



While BaseClothing takes this constructor:

public BaseClothing( int itemID, Layer layer, int hue ) : base( itemID )



The problem I'm having is when I add different constructors it keeps giving me an ambiguous error but the error is for BaseArmor, which I'm guessing checks BaseArmor if that constructor exists, which is doesn't. I'm sure there's a way to get it done and I'm still working on it.

This post has been edited by kiasta: 09 April 2013 - 01:08 PM

Was This Post Helpful? 0
  • +
  • -

#17 lordofduct  Icon User is offline

  • I'm a cheeseburger
  • member icon


Reputation: 2538
  • View blog
  • Posts: 4,639
  • Joined: 24-September 10

Re: Passing class type?

Posted 09 April 2013 - 01:21 PM

Quote

public class BaseDragonkin : BaseArmor, BaseClothing, BaseJewel, BaseShield, BaseWeapon


This is why games often use what is called the 'component pattern' or 'composite pattern'.

You have a generic type, say 'Entity' or 'GameObject' or something. These take in component types that add functionality to the object. If you want you object to act like multiple different things, you add the needed components. The compositing of these components creates a unique type.



This is not the only solution, especially since I don't know exactly what you're trying to pull off.



If you're looking to create instances of objects whose constructors / initial values vary. Look into a Factory Pattern of some sort to create instances... the Factory will know what the constructors need.


I will say that if you have an overt need to constantly be checking specific type, your design is probably bad.

Let's say you have a function like so:

void Foo(Item obj)
{
    if (obj is Sword)
	{
		//do something with a sword
	}
	else if (obj is Potion)
	{
		//do something with a potion
	}
}



Why not let the Item define what it does?

abstract class Item
{
	abstract void DoFooWithPlayer(Player player);
}

void Foo(Item obj)
{
	obj.DoFooWithPlayer(player);
}


This post has been edited by lordofduct: 09 April 2013 - 01:23 PM

Was This Post Helpful? 1
  • +
  • -

#18 kiasta  Icon User is offline

  • D.I.C Regular

Reputation: 22
  • View blog
  • Posts: 260
  • Joined: 18-November 07

Re: Passing class type?

Posted 13 April 2013 - 08:54 PM

Quote

This is why games often use what is called the 'component pattern' or 'composite pattern'.

You have a generic type, say 'Entity' or 'GameObject' or something. These take in component types that add functionality to the object. If you want you object to act like multiple different things, you add the needed components. The compositing of these components creates a unique type.


I understand what you are saying, I was actually contemplating on doing just that, since all the BaseXXX items are derived from the parent: Item.



Quote

This is not the only solution, especially since I don't know exactly what you're trying to pull off.

Yeah, there's a lot of code to work with, that's why I've been trying to explain using only my code, otherwise I'd be posting thousands more lines of code and several files just to explain exactly what I need.



Quote

If you're looking to create instances of objects whose constructors / initial values vary. Look into a Factory Pattern of some sort to create instances... the Factory will know what the constructors need.

I'll look into that. I'm still pretty noobish at C# and since I've never had formal schooling I just rely on tutorials online.


Quote

I will say that if you have an overt need to constantly be checking specific type, your design is probably bad.

Let's say you have a function like so:

void Foo(Item obj)
{
    if (obj is Sword)
	{
		//do something with a sword
	}
	else if (obj is Potion)
	{
		//do something with a potion
	}
}


Why not let the Item define what it does?

abstract class Item
{
	abstract void DoFooWithPlayer(Player player);
}

void Foo(Item obj)
{
	obj.DoFooWithPlayer(player);
}


Let me explain a bit in more detail what the item itself does. The items I am referring to are just deeds (basically pieces of paper) that increase a stat of a piece of equipment. When I double click the deed I get a Target instance which when I click on the item it's returned as an object type. I don't know what type it is and the item is not a deed. In order for me to modify the value I have to do something like this:

m_Attributes = ((BaseDragonkinShoes)item).Attributes;
m_Attributes[m_Attribute] += m_Modifier;



If there was a way around casting the enumerator I wouldn't need to worry about the item's type I am modifying. There are different attributes for different types of items, for instance the enumerator used for AttackChance is AosAttributes, it can be applied to any wearable item. If I have something like the SelfRepair attribute I can only apply it to BaseArmor and BaseWeapon types and I have to cast their respective enumerators AosArmorAttributes and AosWeaponAttributes both of which are not even a part of Item or BaseArmor/Shield/Weapon/etc but in a separate file: AOS.cs, they are just instantiated within BaseArmor/Weapon/etc. (BaseShield is actually just a child class of BaseArmor)

Take, for instance, the SelfRepair attribute. It can only be applied to items which have durability: BaseArmor/BaseShield/BaseWeapon. The SelfRepair attribute is only in the AosArmorAttribute and AosWeaponAttribute enums and not in AosAttribute enum so I have to know, first, the item's type, if in fact it is armor, shield or weapon. Let me show you the way they have implemented BaseArmor's attributes, bear in mind that this is not my work.

BaseArmor.cs

private AosAttributes m_AosAttributes;
private AosArmorAttributes m_AosArmorAttributes;

[CommandProperty( AccessLevel.GameMaster )]
public AosAttributes Attributes
{
	get{ return m_AosAttributes; }
	set{}
}

[CommandProperty( AccessLevel.GameMaster )]
public AosArmorAttributes ArmorAttributes
{
	get{ return m_AosArmorAttributes; }
	set{}
}



AOS.cs

AosAttribute

[Flags]
public enum AosAttribute
{
	RegenHits=0x00000001,
	RegenStam=0x00000002,
	RegenMana=0x00000004,
	DefendChance=0x00000008,
	AttackChance=0x00000010,
	BonusStr=0x00000020,
	BonusDex=0x00000040,
	BonusInt=0x00000080,
	BonusHits=0x00000100,
	BonusStam=0x00000200,
	BonusMana=0x00000400,
	WeaponDamage=0x00000800,
	WeaponSpeed=0x00001000,
	SpellDamage=0x00002000,
	CastRecovery=0x00004000,
	CastSpeed=0x00008000,
	LowerManaCost=0x00010000,
	LowerRegCost=0x00020000,
	ReflectPhysical=0x00040000,
	EnhancePotions=0x00080000,
	Luck=0x00100000,
	SpellChanneling=0x00200000,
	NightSight=0x00400000,
	IncreasedKarmaLoss=0x00800000
}

public sealed class AosAttributes : BaseAttributes
{
	public AosAttributes( Item owner )
		: base( owner )
	{
	}

	public AosAttributes( Item owner, AosAttributes other )
		: base( owner, other )
	{
	}

	public AosAttributes( Item owner, GenericReader reader )
		: base( owner, reader )
	{
	}

	public static int GetValue( Mobile m, AosAttribute attribute )
	{
		if( !Core.AOS )
			return 0;

		List<Item> items = m.Items;
		int value = 0;

		for( int i = 0; i < items.Count; ++i )
		{
			Item obj = items[i];

			if( obj is BaseWeapon )
			{
				AosAttributes attrs = ((BaseWeapon)obj).Attributes;

				if( attrs != null )
					value += attrs[attribute];

				if( attribute == AosAttribute.Luck )
					value += ((BaseWeapon)obj).GetLuckBonus();
			}
			else if( obj is BaseArmor )
			{
				AosAttributes attrs = ((BaseArmor)obj).Attributes;

				if( attrs != null )
					value += attrs[attribute];

				if( attribute == AosAttribute.Luck )
					value += ((BaseArmor)obj).GetLuckBonus();
			}
			else if( obj is BaseJewel )
			{
				AosAttributes attrs = ((BaseJewel)obj).Attributes;

				if( attrs != null )
					value += attrs[attribute];
			}
			else if( obj is BaseClothing )
			{
				AosAttributes attrs = ((BaseClothing)obj).Attributes;

				if( attrs != null )
					value += attrs[attribute];
			}
			else if( obj is Spellbook )
			{
				AosAttributes attrs = ((Spellbook)obj).Attributes;

				if( attrs != null )
					value += attrs[attribute];
			}
			else if( obj is BaseQuiver )
			{
				AosAttributes attrs = ((BaseQuiver)obj).Attributes;

				if( attrs != null )
					value += attrs[attribute];
			}
			else if ( obj is BaseTalisman )
			{
				AosAttributes attrs = ((BaseTalisman)obj).Attributes;

				if (attrs != null)
					value += attrs[attribute];
			}
		}

		return value;
	}

	public int this[AosAttribute attribute]
	{
		get { return GetValue( (int)attribute ); }
		set { SetValue( (int)attribute, value ); }
	}

	public override string ToString()
	{
		return "...";
	}

	public void AddStatBonuses( Mobile to )
	{
		int strBonus = BonusStr;
		int dexBonus = BonusDex;
		int intBonus = BonusInt;

		if ( strBonus != 0 || dexBonus != 0 || intBonus != 0 )
		{
			string modName = Owner.Serial.ToString();

			if ( strBonus != 0 )
				to.AddStatMod( new StatMod( StatType.Str, modName + "Str", strBonus, TimeSpan.Zero ) );

			if ( dexBonus != 0 )
				to.AddStatMod( new StatMod( StatType.Dex, modName + "Dex", dexBonus, TimeSpan.Zero ) );

			if ( intBonus != 0 )
				to.AddStatMod( new StatMod( StatType.Int, modName + "Int", intBonus, TimeSpan.Zero ) );
		}

		to.CheckStatTimers();
	}

	public void RemoveStatBonuses( Mobile from )
	{
		string modName = Owner.Serial.ToString();

		from.RemoveStatMod( modName + "Str" );
		from.RemoveStatMod( modName + "Dex" );
		from.RemoveStatMod( modName + "Int" );

		from.CheckStatTimers();
	}

	[CommandProperty( AccessLevel.GameMaster )]
	public int RegenHits { get { return this[AosAttribute.RegenHits]; } set { this[AosAttribute.RegenHits] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int RegenStam { get { return this[AosAttribute.RegenStam]; } set { this[AosAttribute.RegenStam] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int RegenMana { get { return this[AosAttribute.RegenMana]; } set { this[AosAttribute.RegenMana] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int DefendChance { get { return this[AosAttribute.DefendChance]; } set { this[AosAttribute.DefendChance] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int AttackChance { get { return this[AosAttribute.AttackChance]; } set { this[AosAttribute.AttackChance] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int BonusStr { get { return this[AosAttribute.BonusStr]; } set { this[AosAttribute.BonusStr] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int BonusDex { get { return this[AosAttribute.BonusDex]; } set { this[AosAttribute.BonusDex] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int BonusInt { get { return this[AosAttribute.BonusInt]; } set { this[AosAttribute.BonusInt] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int BonusHits { get { return this[AosAttribute.BonusHits]; } set { this[AosAttribute.BonusHits] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int BonusStam { get { return this[AosAttribute.BonusStam]; } set { this[AosAttribute.BonusStam] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int BonusMana { get { return this[AosAttribute.BonusMana]; } set { this[AosAttribute.BonusMana] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int WeaponDamage { get { return this[AosAttribute.WeaponDamage]; } set { this[AosAttribute.WeaponDamage] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int WeaponSpeed { get { return this[AosAttribute.WeaponSpeed]; } set { this[AosAttribute.WeaponSpeed] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int SpellDamage { get { return this[AosAttribute.SpellDamage]; } set { this[AosAttribute.SpellDamage] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int CastRecovery { get { return this[AosAttribute.CastRecovery]; } set { this[AosAttribute.CastRecovery] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int CastSpeed { get { return this[AosAttribute.CastSpeed]; } set { this[AosAttribute.CastSpeed] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int LowerManaCost { get { return this[AosAttribute.LowerManaCost]; } set { this[AosAttribute.LowerManaCost] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int LowerRegCost { get { return this[AosAttribute.LowerRegCost]; } set { this[AosAttribute.LowerRegCost] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int ReflectPhysical { get { return this[AosAttribute.ReflectPhysical]; } set { this[AosAttribute.ReflectPhysical] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int EnhancePotions { get { return this[AosAttribute.EnhancePotions]; } set { this[AosAttribute.EnhancePotions] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int Luck { get { return this[AosAttribute.Luck]; } set { this[AosAttribute.Luck] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int SpellChanneling { get { return this[AosAttribute.SpellChanneling]; } set { this[AosAttribute.SpellChanneling] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int NightSight { get { return this[AosAttribute.NightSight]; } set { this[AosAttribute.NightSight] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int IncreasedKarmaLoss { get { return this[AosAttribute.IncreasedKarmaLoss]; } set { this[AosAttribute.IncreasedKarmaLoss] = value; } }
}



AosWeaponAttribute

[Flags]
public enum AosWeaponAttribute
{
	LowerStatReq=0x00000001,
	SelfRepair=0x00000002,
	HitLeechHits=0x00000004,
	HitLeechStam=0x00000008,
	HitLeechMana=0x00000010,
	HitLowerAttack=0x00000020,
	HitLowerDefend=0x00000040,
	HitMagicArrow=0x00000080,
	HitHarm=0x00000100,
	HitFireball=0x00000200,
	HitLightning=0x00000400,
	HitDispel=0x00000800,
	HitColdArea=0x00001000,
	HitFireArea=0x00002000,
	HitPoisonArea=0x00004000,
	HitEnergyArea=0x00008000,
	HitPhysicalArea=0x00010000,
	ResistPhysicalBonus=0x00020000,
	ResistFireBonus=0x00040000,
	ResistColdBonus=0x00080000,
	ResistPoisonBonus=0x00100000,
	ResistEnergyBonus=0x00200000,
	UseBestSkill=0x00400000,
	MageWeapon=0x00800000,
	DurabilityBonus=0x01000000
}

public sealed class AosWeaponAttributes : BaseAttributes
{
	public AosWeaponAttributes( Item owner )
		: base( owner )
	{
	}

	public AosWeaponAttributes( Item owner, AosWeaponAttributes other )
		: base( owner, other )
	{
	}

	public AosWeaponAttributes( Item owner, GenericReader reader )
		: base( owner, reader )
	{
	}

	public static int GetValue( Mobile m, AosWeaponAttribute attribute )
	{
		if( !Core.AOS )
			return 0;

		List<Item> items = m.Items;
		int value = 0;

		for( int i = 0; i < items.Count; ++i )
		{
			Item obj = items[i];

			if( obj is BaseWeapon )
			{
				AosWeaponAttributes attrs = ((BaseWeapon)obj).WeaponAttributes;

				if( attrs != null )
					value += attrs[attribute];
			}
			else if ( obj is ElvenGlasses )
			{
				AosWeaponAttributes attrs = ((ElvenGlasses)obj).WeaponAttributes;

				if( attrs != null )
					value += attrs[attribute];
			}
		}

		return value;
	}

	public int this[AosWeaponAttribute attribute]
	{
		get { return GetValue( (int)attribute ); }
		set { SetValue( (int)attribute, value ); }
	}

	public override string ToString()
	{
		return "...";
	}

	[CommandProperty( AccessLevel.GameMaster )]
	public int LowerStatReq { get { return this[AosWeaponAttribute.LowerStatReq]; } set { this[AosWeaponAttribute.LowerStatReq] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int SelfRepair { get { return this[AosWeaponAttribute.SelfRepair]; } set { this[AosWeaponAttribute.SelfRepair] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitLeechHits { get { return this[AosWeaponAttribute.HitLeechHits]; } set { this[AosWeaponAttribute.HitLeechHits] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitLeechStam { get { return this[AosWeaponAttribute.HitLeechStam]; } set { this[AosWeaponAttribute.HitLeechStam] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitLeechMana { get { return this[AosWeaponAttribute.HitLeechMana]; } set { this[AosWeaponAttribute.HitLeechMana] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitLowerAttack { get { return this[AosWeaponAttribute.HitLowerAttack]; } set { this[AosWeaponAttribute.HitLowerAttack] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitLowerDefend { get { return this[AosWeaponAttribute.HitLowerDefend]; } set { this[AosWeaponAttribute.HitLowerDefend] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitMagicArrow { get { return this[AosWeaponAttribute.HitMagicArrow]; } set { this[AosWeaponAttribute.HitMagicArrow] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitHarm { get { return this[AosWeaponAttribute.HitHarm]; } set { this[AosWeaponAttribute.HitHarm] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitFireball { get { return this[AosWeaponAttribute.HitFireball]; } set { this[AosWeaponAttribute.HitFireball] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitLightning { get { return this[AosWeaponAttribute.HitLightning]; } set { this[AosWeaponAttribute.HitLightning] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitDispel { get { return this[AosWeaponAttribute.HitDispel]; } set { this[AosWeaponAttribute.HitDispel] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitColdArea { get { return this[AosWeaponAttribute.HitColdArea]; } set { this[AosWeaponAttribute.HitColdArea] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitFireArea { get { return this[AosWeaponAttribute.HitFireArea]; } set { this[AosWeaponAttribute.HitFireArea] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitPoisonArea { get { return this[AosWeaponAttribute.HitPoisonArea]; } set { this[AosWeaponAttribute.HitPoisonArea] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitEnergyArea { get { return this[AosWeaponAttribute.HitEnergyArea]; } set { this[AosWeaponAttribute.HitEnergyArea] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int HitPhysicalArea { get { return this[AosWeaponAttribute.HitPhysicalArea]; } set { this[AosWeaponAttribute.HitPhysicalArea] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int ResistPhysicalBonus { get { return this[AosWeaponAttribute.ResistPhysicalBonus]; } set { this[AosWeaponAttribute.ResistPhysicalBonus] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int ResistFireBonus { get { return this[AosWeaponAttribute.ResistFireBonus]; } set { this[AosWeaponAttribute.ResistFireBonus] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int ResistColdBonus { get { return this[AosWeaponAttribute.ResistColdBonus]; } set { this[AosWeaponAttribute.ResistColdBonus] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int ResistPoisonBonus { get { return this[AosWeaponAttribute.ResistPoisonBonus]; } set { this[AosWeaponAttribute.ResistPoisonBonus] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int ResistEnergyBonus { get { return this[AosWeaponAttribute.ResistEnergyBonus]; } set { this[AosWeaponAttribute.ResistEnergyBonus] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int UseBestSkill { get { return this[AosWeaponAttribute.UseBestSkill]; } set { this[AosWeaponAttribute.UseBestSkill] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int MageWeapon { get { return this[AosWeaponAttribute.MageWeapon]; } set { this[AosWeaponAttribute.MageWeapon] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int DurabilityBonus { get { return this[AosWeaponAttribute.DurabilityBonus]; } set { this[AosWeaponAttribute.DurabilityBonus] = value; } }
}



AosArmorAttribute

[Flags]
public enum AosArmorAttribute
{
	LowerStatReq=0x00000001,
	SelfRepair=0x00000002,
	MageArmor=0x00000004,
	DurabilityBonus=0x00000008
}

public sealed class AosArmorAttributes : BaseAttributes
{
	public AosArmorAttributes( Item owner )
		: base( owner )
	{
	}

	public AosArmorAttributes( Item owner, GenericReader reader )
		: base( owner, reader )
	{
	}

	public AosArmorAttributes( Item owner, AosArmorAttributes other )
		: base( owner, other )
	{
	}

	public static int GetValue( Mobile m, AosArmorAttribute attribute )
	{
		if( !Core.AOS )
			return 0;

		List<Item> items = m.Items;
		int value = 0;

		for( int i = 0; i < items.Count; ++i )
		{
			Item obj = items[i];

			if( obj is BaseArmor )
			{
				AosArmorAttributes attrs = ((BaseArmor)obj).ArmorAttributes;

				if( attrs != null )
					value += attrs[attribute];
			}
			else if( obj is BaseClothing )
			{
				AosArmorAttributes attrs = ((BaseClothing)obj).ClothingAttributes;

				if( attrs != null )
					value += attrs[attribute];
			}
		}

		return value;
	}

	public int this[AosArmorAttribute attribute]
	{
		get { return GetValue( (int)attribute ); }
		set { SetValue( (int)attribute, value ); }
	}

	public override string ToString()
	{
		return "...";
	}

	[CommandProperty( AccessLevel.GameMaster )]
	public int LowerStatReq { get { return this[AosArmorAttribute.LowerStatReq]; } set { this[AosArmorAttribute.LowerStatReq] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int SelfRepair { get { return this[AosArmorAttribute.SelfRepair]; } set { this[AosArmorAttribute.SelfRepair] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int MageArmor { get { return this[AosArmorAttribute.MageArmor]; } set { this[AosArmorAttribute.MageArmor] = value; } }

	[CommandProperty( AccessLevel.GameMaster )]
	public int DurabilityBonus { get { return this[AosArmorAttribute.DurabilityBonus]; } set { this[AosArmorAttribute.DurabilityBonus] = value; } }
}



I know it's a lot of code, but I'm just trying to give an example of what I'm trying to work with. I've been trying to implement some kind of Reflection system. I am putting all of the types allowed to be modified into a class itslef like this:

public class EquipmentTypes
{
    public BaseDragonkinArmor m_Armor;
    public BaseDragonkinClothing m_Clothing;
    public BaseDragonkinJewel m_Jewel;
    public BaseDragonkinShield m_Shield;
    public BaseDragonkinWeapon m_Weapon;

    public EquipmentTypes()
    {
        m_Armor = new BaseDragonkinArmor();
        m_Clothing = new BaseDragonkinClothing();
        m_Jewel = new BaseDragonkinJewel();
        m_Shield = new BaseDragonkinShield();
        m_Weapon = new BaseDragonkinWeapon();
    }
}



Going through a foreach like so:

EquipmentTypes itemType = new EquipmentTypes();
MemberInfo[] members = itemType.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
foreach (MemberInfo member in members)
{
    if (item.GetType().BaseType.Equals(member.MemberType))
    {
        m_From.SendMessage("Refelction works!");
    }
    else
    {
        m_From.SendMessage("Reflection is not working. MemberInfo: {0}", member.MemberType.ToString());
    }
}



The problem with this is that it prints out 5x "member" and 5x "field". I'm not sure how to compare the member type of a class. I've tried to find something on google but I just cannot find anything, I've found info on properties but they are not properties. I was thinking on making the class static with static members but I'm not sure how to iterate through a static class nor do I know if it can be done, something like:

public static class EquipmentTypes
{
    public static BaseDragonkinArmor m_Armor = new BaseDragonkinArmor();
    public static BaseDragonkinClothing m_Clothing = new BaseDragonkinClothing();
    public static BaseDragonkinJewel m_Jewel = new BaseDragonkinJewel();
    public static BaseDragonkinShield m_Shield = new BaseDragonkinShield();
    public static BaseDragonkinWeapon m_Weapon = new BaseDragonkinWeapon();
}



Though, I don't know if I even have to instantiate a new class to get the member type, I just don't know enouhg about reflection. Any ideas on this, or is this just a sloppy way of doing things? If I could compare types like this than I won't have to bother with all those if/else statements.

This post has been edited by kiasta: 13 April 2013 - 08:56 PM

Was This Post Helpful? 0
  • +
  • -

#19 Momerath  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1012
  • View blog
  • Posts: 2,444
  • Joined: 04-October 09

Re: Passing class type?

Posted 14 April 2013 - 03:57 AM

In EverQuest (as an example) every item has every attribute. Yes it makes for a big structure, but then you don't have to worry about the type until they try to equip it (only goes in certain slots) or use it (can only be used in certain ways). Special abilities are done with something like a delegate. Each item also has a ItemType parameter to indicate what it is (an enumerated value). This lets them use a case statement instead of all the if (xx is SomeType) code you have.

Another way to do this is with the decorator pattern. Instead of altering items, you 'add' a decorator to it. As a small example, let's create some classes
public abstract Item {
    public abstract int MinHit {get; }
    public abstract int MaxHit {get; }
}

public ShortSword : Item {
    public override int MinHit { get { return 1; } }
    public override int MaxHit { get { return 6; } }
}

public EnchantPlusOne : Item {   // this is the decorator
    private Item nextItem;

    public EnchantPlusOne(Item itemToEnchant) {
        nextItem = itemToEnchant;
    }

    public override int MinHit { get { return 1 + nextItem.MinHit; } }
    public override int MaxHit { get { return 1 + nextItem.MinHit; } }
}

(Note: Just writing this as I sit here, I'm sure I'm leaving out some constructors and other stuff :))

Now we can create a weapon, and enchant it as many times as we wont, without having to alter the base item at all (which means we don't have different ShortSwords stored in our database).

You'd use it like this, assuming that playerWeapon is of type Item and is currently referencing a ShortSword object:
playerWeapon = new EnchantPlusOne(playerWeapon); // now a short sword + 1
playerWeapon = new EnchantPlusOne(playerWeapon);  // now a short sword + 2


You can also add things like specific target modifiers without having to have an attribute in the base object:
public class OrcSlaying : Item {
    private Item nextItem;

    public OrcSlaying(Item itemToEnchant) {
        nextItem = itemToEnchant;
    }

    public override int MinHit { get { 
        if (player.CurrentTarget.Race == Races.Orc) {
            return 6 + nextItem.MinHit;
        } else {
            return nextItem.MinHit; 
        }
    }

    public override int MaxHit {
        if (player.CurrentTarget.Race == Races.Orc) {
            return 6 + nextItem.MaxHit;
        } else {
            return nextItem.MaxHit; 
        }
    }
}


Now all the functionality of what a weapon does can be contained inside the weapon itself (with its decorators) rather than having code that checks all the various possibilities in your combat code. The combat code just asks for min and max hit and figures out what to do with those numbers. We can even combine different decorators since they all derive from the same base type:
playerWeapon = new EnchantPlusOne(playerWeapon);
playerWeapon = new OrcSlaying(playerWeapon);


This gives us an ShortSword + 1 of Orc Slaying without having to write complicated combat code or ever really altering the base weapon types and enchantments.

You can also use this type of thing to determine how 'buff' type spells affect players, as you wouldn't want to really change their attributes, you just want to know what they currently (with whatever spells are affecting them) are.
Was This Post Helpful? 1
  • +
  • -

#20 kiasta  Icon User is offline

  • D.I.C Regular

Reputation: 22
  • View blog
  • Posts: 260
  • Joined: 18-November 07

Re: Passing class type?

Posted 14 April 2013 - 09:00 AM

Actually Momerath, the items look very similar with what I've made. I'm trying what both you and Lordofduct suggested, but I'm having a little problem...

DragonkinBlade.cs:

using System;
using Server;
using Server.Items;
using Server.Targets;

namespace Server.Dragonkin
{
	[FlipableAttribute( 0x13FF, 0x13FE )]
    public class DragonkinBlade : BaseDragonkinWeapon
	{
        public override SkillName DefSkill { get { return SkillName.Swords; } }
        public override WeaponType DefType { get { return WeaponType.Slashing; } }
        public override WeaponAnimation DefAnimation { get { return WeaponAnimation.Slash1H; } }
		public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DoubleStrike; } }
		public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ArmorIgnore; } }

        public override int AosStrengthReq { get { return 25; } }
        public override int AosMinDamage { get { return 11; } }
        public override int AosMaxDamage { get { return 13; } }
        public override int AosSpeed { get { return 46; } }
        public override float MlSpeed { get { return 2.50f; } }

        public override int OldStrengthReq { get { return 10; } }
        public override int OldMinDamage { get { return 5; } }
        public override int OldMaxDamage { get { return 26; } }
        public override int OldSpeed { get { return 58; } }

        public override int DefHitSound { get { return 0x23B; } }
        public override int DefMissSound { get { return 0x23A; } }

        public override int InitMinHits { get { return 31; } }
        public override int InitMaxHits { get { return 90; } }

		[Constructable]
		public DragonkinBlade() : base( 0x13FF )
		{
            	Name = "Blade of the Dragonkin";
			    Weight = 6.0;
		}

        public void ModifyItem(AosAttribute attribute, int modifier)
        {
            Attributes[attribute] += modifier;
        }

        public void ModifyItem(AosWeaponAttribute attribute, int modifier)
        {
            WeaponAttributes[attribute] += modifier;
        }

		public DragonkinBlade( Serial serial ) : base( serial )
		{
		}

		public override void Serialize( GenericWriter writer )
		{
			base.Serialize( writer );
			writer.Write( (int) 0 );
		}

		public override void Deserialize( GenericReader reader )
		{
			base.Deserialize( reader );
			int version = reader.ReadInt();
		}
	}
}



As you can tell I created a method to handle the attribute and change according to the modifier, however when I target the item I still need to know what it's type is so I can call the method so I am trying to use reflection, like so:

MethodInfo[] methods = target.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance);
string methodName = "ModifyItem";
foreach (MethodInfo method in methods)
{
    if (method.Name == methodName)
    {
        object result = null;
        ParameterInfo[] parameters = method.GetParameters();
        object[] parametersArray = new object[] { Attribute, Modifier };
        result = method.Invoke(target, parametersArray);
    }
    else
    {
        from.SendMessage("There are no methods with the name of {0}", methodName);
    }
}



Which works, kind of. The problem is the code invokes BOTH overloaded methods, so while I do get an increase to AttackChance I also get an increase to HitLeechMana (which should not happen), I'm guessing from invoking the second overloaded method.

public void ModifyItem(AosWeaponAttribute attribute, int modifier)
{
        WeaponAttributes[attribute] += modifier;
}



*Edit* I did a test and commented out the second overloaded method:

public void ModifyItem(AosWeaponAttribute attribute, int modifier)
{
        WeaponAttributes[attribute] += modifier;
}



And the deed worked as it should. So it is definitely invoking both overloaded methods. I would think that both AosAttributes and AosWeaponAttributes methods, being different types, would not be invoked. It's strange to me that it would not throw an overloaded exception.

How do I account for overloaded methods in this case?

This post has been edited by kiasta: 14 April 2013 - 10:17 AM

Was This Post Helpful? 0
  • +
  • -

#21 kiasta  Icon User is offline

  • D.I.C Regular

Reputation: 22
  • View blog
  • Posts: 260
  • Joined: 18-November 07

Re: Passing class type?

Posted 15 April 2013 - 08:29 AM

Well I seem to have found the solution:

AttackChance.cs

try
{
    for (int i = 0; i < Settings.EquipmentTypes.Length; i++)
    {
        if (o_Target.GetType().BaseType == m_EquipmentTypesAllowed.GetValue(i))
	{
	    if (Settings.Misc.Debug) { m_From.SendMessage(m_EquipmentTypesAllowed.GetValue(i).ToString()); }
	    object MethodExists = o_Target.GetType().GetMethod(m_ModifyAttributeMethodName, new Type[] { m_Attribute.GetType(), typeof(int) });
	    if (MethodExists != null)
	    {
	        o_Target.GetType().GetMethod(m_ModifyAttributeMethodName, new Type[] { m_ArmorAttribute.GetType(), typeof(int) }).Invoke(o_Target, new object[] { m_ArmorAttribute, m_Modifier });
		if (!Settings.Misc.Debug) { IsApplied = true; }
	    }
    	}
    }
}
catch (NullReferenceException e)
{
    if (Settings.Misc.Debug) { m_From.SendMessage("NullReferenceException: {0}", e.ToString()); }
    else { m_From.SendMessage("You cannot add {0} to that.", m_AttributeName); }
}
catch (AmbiguousMatchException e)
{
    if (Settings.Misc.Debug) { m_From.SendMessage("AmbiguousMatchException: {0}", e.ToString()); }
    //Do something here
}
catch (ArgumentNullException e)
{
    if (Settings.Misc.Debug) { m_From.SendMessage("ArgumentNullException: {0}", e.ToString()); }
    //Do something here
}
catch (ArgumentException e)
{
    if (Settings.Misc.Debug) { m_From.SendMessage("ArgumentException: {0}", e.ToString()); }
    //Do something here
}
catch (Exception e)
{
    if (Settings.Misc.Debug) { m_From.SendMessage("Exception: {0}", e.ToString()); }
    //Do something here
}



BaseDragonkWeapon.cs

public void ModifyAttribute(AosAttribute attribute, int modifier)
{
    Attributes[attribute] += modifier;
}

public void ModifyAttribute(AosWeaponAttribute attribute, int modifier)
{
    WeaponAttributes[attribute] += modifier;
}



I actually have the code in another file that handles all the deeds functionality and a settings file for all the global values, this just gives an example of how it works :)

Thanks for all the help gals/guys, I appreciate it.
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2