Is it possible to give a mob access to more than one Weapon abiltiy using public override WeaponAbility GetWeaponAbility() ?

public override WeaponAbility GetWeaponAbility()
{
return WeaponAbility.ConcussionBlow;
return WeaponAbility.CrushingBlow;
}

This obviously doesn't work, can't return twice loll, but anyway, is that possible?

If not, how would I go about doing this? I understand Xmlspawner2 might have this functionality, but I'm clueless on that.
 
You could use a switch-case statement with a random value;

Code:
public override WeaponAbility GetWeaponAbility()
{
	switch( Utility.Random( 2 ) )
	{
		case 0: return WeaponAbility.ConcussionBlow;
		case 1: return WeaponAbility.CrushingBlow;
	}

	return null; // or perhaps a non-null default ability?
}

Or perhaps a static-context list:
Code:
private static WeaponAbility[] _Abilities = 
{
	WeaponAbility.ConcussionBlow,
	WeaponAbility.CrushingBlow
};

public override WeaponAbility GetWeaponAbility()
{
	return _Abilities[Utility.Random(_Abilities.Length)];
}
 
Would this not mean that when the creature spawns its randomly given one of those two abilities and it never changes?

If thats the case, I was more looking for the capability for a creature to be given two options of special abilities to use, and it randomly chooses one.
 
GetWeaponAbility is called constantly while a creature's AI is active (when it's ready to attempt an ability), so the code I provided does exactly what you want :)
 
PERFECT! Thank you.
[doublepost=1483683920][/doublepost]
GetWeaponAbility is called constantly while a creature's AI is active (when it's ready to attempt an ability), so the code I provided does exactly what you want :)

I have confirmed that it does indeed work perfectly as expected :D Out of curiosity, the first set of code you provided, at what point would it trickle to the return null option? Never right? Its just required to compile I imagine.
 
Out of curiosity, the first set of code you provided, at what point would it trickle to the return null option? Never right? Its just required to compile I imagine.

That is entirely correct.
The compiler cannot guarantee that the value returned by the random method will always fall within the bounds of the cases defined to handle them, at least not without a 'default' case:

Code:
public override WeaponAbility GetWeaponAbility()
{
    switch( Utility.Random( 2 ) )
    {
        case 0: return WeaponAbility.ConcussionBlow;
        default: return WeaponAbility.CrushingBlow;
    }
}

In this example, the random number could be rolled out of 20 (instead of just 2) and if it lands on 1 to 19, it will 'fall through' to the 'default' case, since there are no explicit cases defined to handle numbers in that range.

This essentially means that case 0 has a 1 in 20 (5%) chance of landing and the default case has a 19 in 20 (95%) chance of landing.

Utility.Random always returns a number in the range of 0 to value-1
 
That is entirely correct.
The compiler cannot guarantee that the value returned by the random method will always fall within the bounds of the cases defined to handle them, at least not without a 'default' case:

Code:
public override WeaponAbility GetWeaponAbility()
{
    switch( Utility.Random( 2 ) )
    {
        case 0: return WeaponAbility.ConcussionBlow;
        default: return WeaponAbility.CrushingBlow;
    }
}

In this example, the random number could be rolled out of 20 (instead of just 2) and if it lands on 1 to 19, it will 'fall through' to the 'default' case, since there are no explicit cases defined to handle numbers in that range.

This essentially means that case 0 has a 1 in 20 (5%) chance of landing and the default case has a 19 in 20 (95%) chance of landing.

Utility.Random always returns a number in the range of 0 to value-1

Which leads me to another thing I was starting to consider, the capability to "weight" one skill to happen more often than the other - although I'm sure this is a much sloppier way of doing that than necessary.

I assume you meant to have switch( Utility.Random( 20 ) ) there, not 2.. Unless I'm missing out how it would roll 1-19 somewhere else.
 
I left the 2 in on purpose for the sake of continuity in the example, but yes, change tht 2 to 20 and it will line up with what you're expecting :)

Code:
public override WeaponAbility GetWeaponAbility()
{
    switch( Utility.Random( 20 ) )
    {
		case 0: // fall through to case 1
		case 1: // fall through to case 2
		case 2: return WeaponAbility.ConcussionBlow;

		default: return WeaponAbility.CrushingBlow;
    }
}

Essentially this modifies the probability of the roll, ConcussionBlow now has a 3/20 (15%) chance to land.

If you have a lot of potentially different ways to pick an ability, you can use some other method, but the end result is the same - whatever ability you decide to return, is the one that will be used at the time GetWeaponAbility is called by the AI.

The above code can also be written like this:
Code:
public override WeaponAbility GetWeaponAbility()
{
	if(Utility.RandomDouble() <= 0.15)
	{
		return WeaponAbility.ConcussionBlow;
	}

	return WeaponAbility.CrushingBlow;
}
 
Yep, as I figured that's a much more efficient (probably?) and more legible way to code logic for weighting skill use.
[doublepost=1483690121][/doublepost]To expand on this, I've modified Crushing Blow to also "taunt" the target if they aren't currently attacking the person hitting them with crushing blow by settings defender.Combatant = attacker;

That part works great, the only problem is the emulator has a funky way of "target switching" depending on what tile the combatant is on relative to them..

For example, the monster will first prefer enemies DIRECTLY on top of it, then on tiles DIRECTLY next to it (N, E, S, W), THEN if no aggresors are found on those tiles it swaps to checking (NE, SE, SW, NW) diagonal tiles. This means that if the mob using crushing blow is diagonal to its combatant, it will taunt, but only for about 1 second before the target switches back over to something on the directly adjacent tiles or directly on top of itself.

Theres probably a way to create a timer that forces the enemy to remain "taunted" for a determined amount of time, but thats a bit outside my experience level.

Alternatively, is there a way to just modify the code somewhere so it prefers all tiles equally? I poked around in basecreature for this logic but couldn't find it. I'm guessing it goes a little deeper in the code than that.
 
Just to throw in my two cents here:
Using Xmlspawner and the Custom Attacks package, you're able to give a mob multiple Custom Attacks, and get some nice properties to play with for the Attachment. Offhand, I don't think you can get as specific as certain tiles/direction, etc in regards to taunts, crushing blows, and such. You are still bound UO reality, unless you rewrite Core scripts of course lol
 
Yep, as I figured that's a much more efficient (probably?) and more legible way to code logic for weighting skill use.
[doublepost=1483690121][/doublepost]
Alternatively, is there a way to just modify the code somewhere so it prefers all tiles equally? I poked around in basecreature for this logic but couldn't find it. I'm guessing it goes a little deeper in the code than that.

You'll need to edit the algorithm used to compute threat, which is based on Fight Mode.
BaseCreature.GetFightModeRanking() should be a good place to start.
The actual algorithm used for target selection is AcquireFocusMob in BaseAI.
 
You'll need to edit the algorithm used to compute threat, which is based on Fight Mode.
BaseCreature.GetFightModeRanking() should be a good place to start.
The actual algorithm used for target selection is AcquireFocusMob in BaseAI.

I took a look and didn't see anything that jumped out at me regarding relative x y z location - only "range".

Thats okay though, I've decided to go a slightly different route. I want to make crushing blow "provoke" the mob onto the user for a few seconds. Unfortunately when I tried to add that logic to crushing blow, it said it couldn't find methods for BardTarget, BardProvoked, ect. I took the code from basecreature essentially, but couldn't quite get it to function.

Heres the error I got, roughly, to be clear:
Code:
    CS1061: Line 44: 'Server.Mobile' does not contain a definition for 'BardProvoked' and no extension method 'BardProvoked' accepting a first argument of type 'Server.Mobile' could be found (are you missing a using directive or an assembly reference?)
    CS1061: Line 45: 'Server.Mobile' does not contain a definition for 'BardTarget' and no extension method 'BardTarget' accepting a first argument of type 'Server.Mobile' could be found (are you missing a using directive or an assembly reference?)
    CS1061: Line 46: 'Server.Mobile' does not contain a definition for 'BardMaster' and no extension method 'BardMaster' accepting a first argument of type 'Server.Mobile' could be found (are you missing a using directive or an assembly reference?)
 
Last edited:
Back