Ce Jayce

Member
I've become a tad stuck with the latest idea i'm working on so am hoping some of you out there can help me!

The end goal I want to achieve is to have a quest giver randomly select a number 1-6 and then select that number of items (different types not amounts) so long as that item is part of "BaseClassSpecialItem" - Selecting the items randomly is where i've come stuck.

For example I have 26 items ItemA to ItemZ that are all part of BaseClassSpecialItem I then want to randomly select an item or several items from that list.

I've tried a variety of methods but nothing has seemed to work, I eventually gave in and decided to create a List and add each item a-z into that list and then use that list to randomly select from.

I declared my list and added the Items
Code:
List<BaseClassSpecialItem> itemlist = new List<BaseClassSpecialItem>();

itemlist.Add(ItemA);
itemlist.Add(ItemB);

However it doesn't take ItemA or ItemB as "Class name is not valid at this point" my guess is because although the list is BaseClassSpecialItem and ItemA & ItemB are both BaseClassSpecialItem they are a subclass of it rather than the parent class itself.
Surely though, there is a way?!

All help is greatly appreciated,
Thanks in advance!
 
Many ways you can do this. One simple way is you can use a switch statement on a random number range to return the type you want.
Code:
public static BaseClassSepcialItem GetItem(int random)
{
	switch (random)
	{
		case 0:
			return new ItemA();
		case 1:
			return new ItemB();
	}

	return null;
}
 
Thanks Kalamus!
I was hoping to avoid having to list each item out as they were already part of the same base class but it seems not! I'll get to work on it :p

Cheers again
 
You can still do what you want without having to type out each known item in code by using some Reflection. Was just trying to keep it simple ;). Try this sample I just whipped up.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Commands;
using Server.Items;

public class RandomRewardItem
{
	private static List<Type> rewardTypes;

	public static void Initialize()
	{
		foreach (var assembly in ScriptCompiler.Assemblies)
		{
			rewardTypes = new List<Type>(assembly.GetTypes().Where(type => type.IsSubclassOf(typeof(BaseWeapon))));
		}

		CommandSystem.Register("GetReward", AccessLevel.Counselor, OnCommand);
	}

	private static void OnCommand(CommandEventArgs e)
	{
		e.Mobile.AddToBackpack(GetReward());
	}

	public static BaseWeapon GetReward()
	{
		int random = Utility.Random(rewardTypes.Count);

		return (BaseWeapon)Activator.CreateInstance(rewardTypes[random]);
	}
}

With this class you can do RandomRewardItem.GetReward() and it will return a random BaseWeapon from a list of Subclass types it creates on server startup from all BaseWeapons it finds in the assemblies. I added a [GetRewards command as an example that allows you to type the command in game and get a random BaseWeapon in your backpack. Just replace BaseWeapon with your base class and remove the command :).

Edit: Forgot to include the using statements
 
Last edited:
IsSubclassOf <- You have no idea how long I hunted for something...anything like that. I'm sure I even types those words!

Thanks once again! You have saved me a lot of time.

If i'm picking say 6 random items and wan't to make sure that they're not the same item. Would the best way be to create a secondary list of picked items and then compare the result of RandomRewardItem.GetReward() with item in PickedList ?
 
Would the best way be to create a secondary list of picked items and then compare the result of RandomRewardItem.GetReward() with item in PickedList ?
I would add another method to the RandomRewardItem class to return a list of items because GetReward() actually creates instances of the item each time it's called so you would want to build the list internally to avoid that. You could add a second method like so to return an amount of rewards.
Code:
public static List<BaseWeapon> GetRewards(int amount)
{
	var rewardList = new List<BaseWeapon>();

	while (rewardList.Count < amount)
	{
		int random = Utility.Random(rewardTypes.Count);

		if (rewardList.Count == 0 || rewardList.All(reward => reward.GetType() != rewardTypes[random]))
		{
			rewardList.Add((BaseWeapon)Activator.CreateInstance(rewardTypes[random]));
		}
	}

	return rewardList;
}
You can then use that list something like this
Code:
foreach (var reward in RandomRewardItem.GetRewards(6)) // get 6 rewards
{
	e.Mobile.AddToBackpack(reward);
}

Should note these are examples and don't have much error check built in. Like requesting more rewards than there are types would cause this sample to freeze your server in loop. Up to you to supply those :).

Edit: Fixed linq expression. Had Any where I should of put All.
 
One more note about my above code. Was doing this as an example but if you are using this code I suggest adding the following checks because if you do use it on BaseWeapon or something else you might not have control over, you'll run into errors with the types found being abstract or not public. Adding some extra checks to line 15 in my RandomRewardItem class like so can resolve them.
Code:
rewardTypes = new List<Type>(assembly.GetTypes().Where(type => !type.IsAbstract && type.IsPublic && type.IsSubclassOf(typeof(BaseWeapon))));

I only did minor checks with the code posted above and it was creating weapons just fine but played around with it some more and found those errors. Also randomly found a bugged weapon that was coded wrong from this :).
 
rewardTypes = new List<Type>(assembly.GetTypes().Where(type => !type.IsAbstract && type.IsPublic && type.IsSubclassOf(typeof(BaseWeapon))));
Was jut going to post querying if this code or not was going to include abstract types etc. - You're now reading my mind and answering questions before I post them.

I'm going to wear out these 7 keys but once again.. Thanks!
 

Active Shards

Donations

Total amount
$0.00
Goal
$1,000.00
Back