c++检查枚举标志

C++ checking enum flags

本文关键字:标志 枚举 检查 c++      更新时间:2023-10-16

在我的一个类中,我有一个整数,它存储了一组枚举标志,如下所示:

enum AttackFlags
{
    Contact = 1,                        //Move connects with target
    Projectile = 2,                         //Attack is projectile based
    Unblockable = 4,                        //Attack can not be blocked
    UncounterableLv1 = 8,                   //Attack can't be countered except by extreme counter attack skills/status effects
    UncounterableLv2 = 16,                  //Attack can not be countered
    Flinches = 32,                          //Has a chance to stun the enemy, pushing back their next turn
    Unreflectable = 64,                     //Attack penetrates reflect. Only checked for Magic attacks
    IgnoreDefenderStatusEffects = 128,      //Ignores active status effects on the defender
    IgnoreAttackerStatusEffects = 256,      //Ignores active status effects on the attacker
    IgnoreDefenderAbilities = 512,          //Ignore the defenders abilities
    IgnoreAttackerAbilities = 1024,         //Ignore the attackers abilities
    IgnoreArmorRating = 2048,               //Ignore the defensive boosts of armor
    IgnoreWeaponRating = 4096,              //Ignore the attack boost from weapons
    HighCritical = 8192,                    //The move has an increased chance to crit
    CausesStatus = 16384,                   //Can the move cause status effects?
    Elemental = 32768,                      //Is the move elemental based?
    Unimplemented = 65536,                  //has the move been implemented yet?
    ModsTimer = 131072,                     //Does it have an effect on the target or users timer?
    Heals = 262144,                         //Does the move heal?
    SecondaryEffects = 524288,              //Attack has additional effects besides basic attack
    PhysicalAttackFlag = 1048576,           //Is the Class Physically based? I.E. blocked by Protect and Shield
    MagicAttackFlag = 2097152,              //Is the move Magically Based? I.E. is it affected by things like Shell
    MultiHit = 4194304,                     //Does it enxcapsulate more then 1 hit
    SingleUse = 8388608,                    //Attack can only be used once per battle
    DoesNotCauseDamage = 16777216
};
class Attack
{
   int AtkFlags; //Stores AttackFlags |'d together
}

我想添加一个方法到我的攻击类与以下签名

bool HasAttackFlags(int flags);

标志将是多个AttackFlags |'d组合在一起。如果我只想核对一面旗帜,我只要&AtkFlags和flag在一起,但因为我必须检查多个可能的标志,这将不起作用。我怎样才能正确地检查多个标志?我想避免传递一个矢量/一组标志来检查,因为简单地将一组标志放在一起比构造一个矢量/集合

更简单。

Thanks in advance

编辑:

为了澄清我的意思,我可能会有下面的

Attack atk;
atk.AtkFlags = Contact | Projectile | Heals | MagicAttackFlag;

然后,我想检查攻击时的标志,像这样:

bool res = atk.HasAttackFlags(Contact | Projectile);

res应为真,反之

bool res = atk.HasAttackFlags(Contact | Unreflectable);

应该为false,因为AtkFlags不同时包含Contact和Unreflectable

我不确定我是否明白你的问题,因为你似乎提到了显而易见的解决方案。那么,这个解决方案有什么问题呢,显然可以添加任何您想要的额外标志:

bool HasAttackFlags(int flags) {
    return (flags&(contact|projectile))!=0;
}

编辑:哦……我想我刚刚算出来了,你想要检查是否有2个或更多的旗子作为一个集合?在这种情况下,您可以简单地将方法修改为:

bool HasAttackFlags(int flags) {
    return (flags&(contact|projectile))==(contact|projectile);
}

这是我的建议:

注意使用枚举定义来启用机器

enum AttackFlags
{
    Contact                     = 1ul <<  0,  // Move connects with target
    Projectile                  = 1ul <<  1,  // Attack is projectile based
    Unblockable                 = 1ul <<  2,  // Attack can not be blocked
    UncounterableLv1            = 1ul <<  3,  // Attack can't be countered except by extreme counter attack skills/status effects
    UncounterableLv2            = 1ul <<  4,  // Attack can not be countered
    Flinches                    = 1ul <<  5,  // Has a chance to stun the enemy, pushing back their next turn
    Unreflectable               = 1ul <<  6,  // Attack penetrates reflect. Only checked for Magic attacks
    IgnoreDefenderStatusEffects = 1ul <<  7,  // Ignores active status effects on the defender
    IgnoreAttackerStatusEffects = 1ul <<  8,  // Ignores active status effects on the attacker
    IgnoreDefenderAbilities     = 1ul <<  9,  // Ignore the defenders abilities
    IgnoreAttackerAbilities     = 1ul << 10,  // Ignore the attackers abilities
    IgnoreArmorRating           = 1ul << 11,  // Ignore the defensive boosts of armor
    IgnoreWeaponRating          = 1ul << 12,  // Ignore the attack boost from weapons
    HighCritical                = 1ul << 13,  // The move has an increased chance to crit
    CausesStatus                = 1ul << 14,  // Can the move cause status effects?
    Elemental                   = 1ul << 15,  // Is the move elemental based?
    Unimplemented               = 1ul << 16,  // has the move been implemented yet?
    ModsTimer                   = 1ul << 17,  // Does it have an effect on the target or users timer?
    Heals                       = 1ul << 18,  // Does the move heal?
    SecondaryEffects            = 1ul << 19,  // Attack has additional effects besides basic attack
    PhysicalAttackFlag          = 1ul << 20,  // Is the Class Physically based? I.E. blocked by Protect and Shield
    MagicAttackFlag             = 1ul << 21,  // Is the move Magically Based? I.E. is it affected by things like Shell
    MultiHit                    = 1ul << 22,  // Does it enxcapsulate more then 1 hit
    SingleUse                   = 1ul << 23,  // Attack can only be used once per battle
    DoesNotCauseDamage          = 1ul << 24, 
    MaskAttack      = MagicAttackFlag | PhysicalAttackFlag,
    MaskIgnore      = IgnoreWeaponRating | IgnoreArmorRating | IgnoreAttackerAbilities | IgnoreDefenderAbilities | IgnoreAttackerStatusEffects,
    // etc
};
static bool HasAttackFlag(AttackFlags flags)
{
    return flags & MaskAttack;
}
static bool HasIgnoreFlag(AttackFlags flags)
{
    return flags & MaskIgnore;
}

作为一个额外的好处,考虑一种方法,只返回"杂项"(也就是说,非掩码)标志:

static AttackFlags MiscFlags(AttackFlags flags)
{
    return (AttackFlags) (flags & ~(MaskAttack | MaskIgnore));
}

作为一个例子,您可以这样做:

int v = Unblockable | UncounterableLv1| UncounterableLv;
if ((flags & v ) == v)
{
  //flags has all three: Unblockable, UncounterableLv1 and UncounterableLv
}
else if ( (flags & v ) ==  (Unblockable | UncounterableLv1))
{
  //flags has Unblockable and UncounterableLv1
}
else if ( (flags & v ) ==  Unblockable )
{
  //flags has Unblockable only
}
//and so on