Below is a script for a Bow that on creation will be assigned 3x Random Combat Properties from the Predetermined list. Occasionally when the item is created it will only have 2 properties on it instead of 3. I suspect this is related to the line " while (property1 == property2) " which is to prevent property 1 and 2 from being the same. I think its likely that its only comming out with 2 instead of 3 properties because the random chance has generated the same property multiple times.


im stumped on how i can include the 3rd property to not duplicate. ive tried using multiple loop statements like

" while (property1 == property2) "
" while (property2 == property3) "
" while (property1 == property3) "


this method did not work ive also tried adding property into the loop " while (property1 == property2 ==Property3) "
For obvious reasons this did not work either.
Looking for some guidance as ive spent way to much time on this and i think my brain is just broken at this point.

How can i fix the loop to include Property3?



namespace Items
{
[Flipable(0x13B2, 0x13B1)]
public class RareBowOfRandom : BaseRanged
{
[Constructable]
public RareBowOfRandom()
: base(0x13B2)
{
Name = "Rare Bow Of Random";
Weight = 6.0;
Layer = Layer.TwoHanded;
Hue = 0x4f2;

// Assign 2 random combat properties with a value of 75
int property1 = Utility.Random(1, 17);
int property2 = Utility.Random(1, 17);
int property3 = Utility.Random(1, 17);
while (property1 == property2)
{
property2 = Utility.Random(1, 17);
}
SetRandomProperty(property1, 75);
SetRandomProperty(property2, 75);
SetRandomProperty(property3, 75);
}

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

public override int EffectID => 0xF42;
public override Type AmmoType => typeof(Arrow);
public override Item Ammo => new Arrow();
public override WeaponAbility PrimaryAbility => WeaponAbility.ParalyzingBlow;
public override WeaponAbility SecondaryAbility => WeaponAbility.MortalStrike;
public override int StrengthReq => 30;
public override int MinDamage => 17;
public override int MaxDamage => 21;
public override float Speed => 4;
public override int DefMaxRange => 10;
public override int InitMinHits => 31;
public override int InitMaxHits => 60;
public override WeaponAnimation DefAnimation => WeaponAnimation.ShootBow;

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

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

private void SetRandomProperty(int index, int value)
{
switch (index)
{
case 1:
WeaponAttributes.HitLeechHits = value;
break;
case 2:
WeaponAttributes.HitLeechStam = value;
break;
case 3:
WeaponAttributes.HitLeechMana = value;
break;
case 4:
WeaponAttributes.HitLowerAttack = value;
break;
case 5:
WeaponAttributes.HitLowerDefend = value;
break;
case 6:
WeaponAttributes.HitMagicArrow = value;
break;
case 7:
WeaponAttributes.HitHarm = value;
break;
case 8:
WeaponAttributes.HitFireball = value;
break;
case 9:
WeaponAttributes.HitLightning = value;
break;
case 10:
WeaponAttributes.HitDispel = value;
break;
case 11:
WeaponAttributes.HitColdArea = value;
break;
case 12:
WeaponAttributes.HitFireArea = value;
break;
case 13:
WeaponAttributes.HitPoisonArea = value;
break;
case 14:
WeaponAttributes.HitEnergyArea = value;
break;
case 15:
WeaponAttributes.HitPhysicalArea = value;
break;
case 16:
WeaponAttributes.UseBestSkill = value;
break;
case 17:
WeaponAttributes.MageWeapon = value;
break;
}
}
}

}
}
 
Last edited:

zerodowned

Moderator
I'm thinking an easy way to go about it is to have a List intialized with all the weaponattributes, then copy that list and remove properties from the new list as it's added to the weapon. this way you don't need to constantly check if property 2 = 1, and if property 3 = 2 or 1
 
OP

OfficerLawless

Citizen
I Shamelessly Turned to AI lol this worked.

int property1 = Utility.Random(1, 17);
int property2 = Utility.Random(1, 17);
int property3 = Utility.Random(1, 17);
while (property1 == property2 || property1 == property3 || property2 == property3)
{
if(property1 == property2) property2 = Utility.Random(1, 17);
if(property1 == property3) property3 = Utility.Random(1, 17);
if(property2 == property3) property3 = Utility.Random(1, 17);
}
SetRandomProperty(property1, 75);
SetRandomProperty(property2, 75);
SetRandomProperty(property3, 75);
}
 

PyrO

Moderator
Well that AI kinda made it weird :D
C#:
List<int> indices = new List<int>();

while(indices.Count < 3)
{
    int temp = Utility.Random(1, 17);
    if (!indices.Contains(temp))
        indices.Add(temp);
}

foreach(int index in indices)
{
    SetRandomProperty(index, 75);
}

I guess I would rather go this route
 

Voxpire

Vita-Nex
Administrator
This is slightly more complicated and dangerous, but I figured I'd throw it out there as it doesn't require a collection allocation and could benefit as a learning example for bit-shift operations.

The 'state' represents bit flags, one bit for each available index in the range 1..17 (it can support 1..32).
These bit flags are used to mark an index as "used", so it will attempt to roll a new index.

Code:
int state = 0, count = 0, index, flag;

while ( count < 3 )
{
    do
    {
        index = Utility.RandomMinMax( 1, 17 );
        flag = 1 << ( index - 1 );
    }
    while ( ( state & flag ) != 0 );

    SetRandomProperty( index, 75 );

    ++count;
}

The dangerous part: if 'count' is ever equal to, or greater than the number of property indices available, then it will enter a stack overflow situation where it will never be able to break out of the do-while loop.
The higher the 'count' gets, the higher the potential gets for collisions, which can slow things down if it keeps rolling used indices.
Another drawback is that you're limited to 32 indices unless you declare 'state' as a 64-bit ulong, in which case you can provide up to 64 unique properties.