Exemple #1
0
static bitboard getPieceBitboard(const position * const pos, const int piece)
{
    bitboard b = 0;
    int colour = COLOUR(piece);
    if(IS_KING(piece)) {
        b = pos->king[colour];
    }
    else if(IS_PAWN(piece)) {
        b = pos->pawns[colour];
    }
    else if(IS_KNIGHT(piece)) {
        b = pos->knights[colour];
    }
    else if(IS_BISHOP(piece)) {
        b = pos->bishops[colour];
    }
    else if(IS_ROOK(piece)) {
        b = pos->rooks[colour];
    }
    else if(IS_QUEEN(piece)) {
        b = pos->queens[colour];
    }
    else {
        /* Something is wrong, I don't know which piece this is.
         * This must NEVER happen; move generation is screwed.
         */
        assert(0);
    }
    return b;
}
Exemple #2
0
static int movePiece(position *pos, const move * const m, const int player)
{
    int piece;
    int castleBits;
    piece = m->thisPiece;
    /* move piece to new location */
    pos->board[m->to] = pos->board[m->from];
    pos->board[m->from] = 0;
    CLR_BIT(pos->pieces[player], m->from);
    SET_BIT(pos->pieces[player], m->to);
    if(IS_KING(piece)) {
        CLR_BIT(pos->king[player], m->from);
        SET_BIT(pos->king[player], m->to);
        /* king position is tracked using kingSquare too */
        pos->kingSquare[player] = m->to;
        if(IS_CASTLE(m)) {
            moveCastlingExtra(pos, m);
        }
        /* king has moved, cannot castle now */
        castleBits = CASTLE_BITS(player);
        pos->castleFlags &= ~castleBits;
    }
    else if(IS_PAWN(piece)) {
        /* move the pawn as usual */
        CLR_BIT(pos->pawns[player], m->from);
        SET_BIT(pos->pawns[player], m->to);
        /* handle ep, promotion if required */
        movePawnExtra(pos, m, player);
    }
    else if(IS_KNIGHT(piece)) {
        CLR_BIT(pos->knights[player], m->from);
        SET_BIT(pos->knights[player], m->to);
    }
    else if(IS_BISHOP(piece)) {
        CLR_BIT(pos->bishops[player], m->from);
        SET_BIT(pos->bishops[player], m->to);
    }
    else if(IS_ROOK(piece)) {
        CLR_BIT(pos->rooks[player], m->from);
        SET_BIT(pos->rooks[player], m->to);
        /* disable castling if required */
        moveRookExtra(pos, m, player);
    }
    else if(IS_QUEEN(piece)) {
        CLR_BIT(pos->queens[player], m->from);
        SET_BIT(pos->queens[player], m->to);
    }
    else {
        printPosition(pos);
        printMove(m);
        fprintf(stderr, "Piece = %d\n", piece);

        /* Something is wrong, I don't know which piece this is.
         * This must NEVER happen; move generation is screwed.
         */
        assert(0);
    }
    return 0;
}
Exemple #3
0
static void movePawnExtra(position *pos, const move * const m, const int player)
{
    /* if ep, remove the opponents pawn */
    if(IS_EP(m)) {
        if(WHITE == player) {
            CLR_BIT(pos->pieces[BLACK], pos->epSquare - 8);
            CLR_BIT(pos->pawns[BLACK], pos->epSquare - 8);
            pos->board[pos->epSquare - 8] = 0;
        }
        else {
            CLR_BIT(pos->pieces[WHITE], pos->epSquare + 8);
            CLR_BIT(pos->pawns[WHITE], pos->epSquare + 8);
            pos->board[pos->epSquare + 8] = 0;
        }
    }
    else if(IS_PROMOTION(m)) { /* if promotion, replace 'to' pawn by promoted piece */
        pos->board[m->to] = m->promoteTo; /* change board */
        CLR_BIT(pos->pawns[player], m->to); /* pawn gone */
        /* add new piece to its bitmap */
        if(IS_KNIGHT(m->promoteTo)) {
            SET_BIT(pos->knights[player], m->to);
        }
        else if(IS_BISHOP(m->promoteTo)) {
            SET_BIT(pos->bishops[player], m->to);
        }
        else if(IS_ROOK(m->promoteTo)) {
            SET_BIT(pos->rooks[player], m->to);
        }
        else if(IS_QUEEN(m->promoteTo)) {
            SET_BIT(pos->queens[player], m->to);
        }
        else {
            assert(0);
        }
    }
    else {
        /* check if double advance and set ep square */
        if(16 == abs(m->to - m->from)) {
            if(WHITE == player) {
                pos->epSquare = m->to - 8;
            }
            else {
                pos->epSquare = m->to + 8;
            }
        }
    }
}
Exemple #4
0
bool
psionic_mob_fight(struct creature *ch, struct creature *precious_vict)
{
    struct creature *vict = NULL;

    if (!is_fighting(ch))
        return false;

    // pick an enemy
    if (!(vict = choose_opponent(ch, precious_vict)))
        return false;

    int aggression = calculate_mob_aggression(ch, vict);

    // Psions can't really do anything when there's a psishield in place
    if (AFF3_FLAGGED(vict, AFF3_PSISHIELD)
        && can_cast_spell(ch, SPELL_PSIONIC_SHATTER)) {
        cast_spell(ch, vict, NULL, NULL, SPELL_PSIONIC_SHATTER);
        return true;
    }
    // Prioritize healing with aggression
    if (GET_HIT(ch) < (GET_MAX_HIT(ch) * MIN(20, MAX(80, aggression)) / 100)
        && can_cast_spell(ch, SPELL_WOUND_CLOSURE)) {
        cast_spell(ch, ch, NULL, NULL, SPELL_WOUND_CLOSURE);
        return true;
    }

    if (aggression > 75) {
        // extremely aggressive - just attack hard
        if (can_cast_spell(ch, SKILL_PSIBLAST)) {
            perform_offensive_skill(ch, vict, SKILL_PSIBLAST);
            return true;
        } else if (GET_POSITION(vict) > POS_SITTING
            && can_cast_spell(ch, SPELL_EGO_WHIP)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_EGO_WHIP);
            return true;
        }
    }
    if (aggression > 50) {
        // somewhat aggressive - balance attacking with crippling
        if (GET_MANA(ch) < GET_MAX_MANA(ch) / 2
            && can_cast_spell(ch, SKILL_PSIDRAIN)
            && can_psidrain(ch, vict, NULL, false)) {
            perform_psidrain(ch, vict);
            return true;
        } else if (!affected_by_spell(vict, SPELL_PSYCHIC_CRUSH)
            && can_cast_spell(ch, SPELL_PSYCHIC_CRUSH)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_PSYCHIC_CRUSH);
            return true;
        } else if (!affected_by_spell(vict, SPELL_MOTOR_SPASM)
            && can_cast_spell(ch, SPELL_MOTOR_SPASM)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_MOTOR_SPASM);
            return true;
        } else if (!affected_by_spell(ch, SPELL_ADRENALINE)
            && can_cast_spell(ch, SPELL_ADRENALINE)) {
            cast_spell(ch, ch, NULL, NULL, SPELL_ADRENALINE);
            return true;
        } else if (GET_POSITION(vict) > POS_SITTING
            && can_cast_spell(ch, SPELL_EGO_WHIP)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_EGO_WHIP);
            return true;
        } else if (can_cast_spell(ch, SKILL_PSIBLAST)) {
            perform_offensive_skill(ch, vict, SKILL_PSIBLAST);
            return true;
        }
    }
    if (aggression > 25) {
        // not very aggressive - play more defensively
        if (IS_PSIONIC(vict)
            && !affected_by_spell(ch, SPELL_PSYCHIC_RESISTANCE)
            && can_cast_spell(ch, SPELL_PSYCHIC_RESISTANCE)) {
            cast_spell(ch, ch, NULL, NULL, SPELL_PSYCHIC_RESISTANCE);
            return true;
        } else if (!IS_CONFUSED(vict)
            && can_cast_spell(ch, SPELL_CONFUSION)
            && (IS_MAGE(vict) || IS_PSIONIC(vict) || IS_CLERIC(vict) ||
                IS_KNIGHT(vict) || IS_PHYSIC(vict))) {
            cast_spell(ch, vict, NULL, NULL, SPELL_CONFUSION);
            return true;
        } else if (GET_MOVE(ch) < GET_MAX_MOVE(ch) / 4
            && can_cast_spell(ch, SPELL_ENDURANCE)) {
            cast_spell(ch, ch, NULL, NULL, SPELL_ENDURANCE);
            return true;
        } else if (GET_MOVE(ch) < GET_MAX_MOVE(ch) / 4
            && can_cast_spell(ch, SPELL_DERMAL_HARDENING)) {
            cast_spell(ch, ch, NULL, NULL, SPELL_DERMAL_HARDENING);
            return true;
        } else if (!AFF2_FLAGGED(ch, AFF2_VERTIGO)
            && can_cast_spell(ch, SPELL_VERTIGO)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_VERTIGO);
            return true;
        } else if (!affected_by_spell(vict, SPELL_PSYCHIC_FEEDBACK)
            && can_cast_spell(ch, SPELL_PSYCHIC_FEEDBACK)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_PSYCHIC_FEEDBACK);
            return true;
        } else if (!affected_by_spell(vict, SPELL_WEAKNESS)
            && can_cast_spell(ch, SPELL_WEAKNESS)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_WEAKNESS);
            return true;
        } else if (!affected_by_spell(vict, SPELL_CLUMSINESS)
            && can_cast_spell(ch, SPELL_CLUMSINESS)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_CLUMSINESS);
            return true;
        } else if (can_cast_spell(ch, SKILL_PSIBLAST)) {
            perform_offensive_skill(ch, vict, SKILL_PSIBLAST);
            return true;
        }
    }
    if (aggression > 5) {
        // attempt to neutralize or get away
        if (GET_POSITION(vict) > POS_SLEEPING
            && can_cast_spell(ch, SPELL_MELATONIC_FLOOD)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_MELATONIC_FLOOD);
            return true;
        } else if (can_cast_spell(ch, SPELL_ASTRAL_SPELL)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_ASTRAL_SPELL);
            return true;
        } else if (can_cast_spell(ch, SPELL_AMNESIA)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_AMNESIA);
            return true;
        } else if (can_cast_spell(ch, SPELL_FEAR)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_FEAR);
            return true;
        }
    }

    return false;
}
Exemple #5
0
void
psionic_best_attack(struct creature *ch, struct creature *vict)
{
    int aggression = calculate_mob_aggression(ch, vict);

    // Psions can't really do anything when there's a psishield in place
    if (AFF3_FLAGGED(vict, AFF3_PSISHIELD)
        && can_cast_spell(ch, SPELL_PSIONIC_SHATTER)) {
        cast_spell(ch, vict, NULL, NULL, SPELL_PSIONIC_SHATTER);
        return;
    }
    if (aggression > 75) {
        // extremely aggressive - just attack hard
        if (!affected_by_spell(vict, SPELL_PSYCHIC_SURGE)
            && can_cast_spell(ch, SPELL_PSYCHIC_SURGE)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_PSYCHIC_SURGE);
            return;
        } else if (can_cast_spell(ch, SKILL_PSIBLAST)) {
            perform_offensive_skill(ch, vict, SKILL_PSIBLAST);
            return;
        } else if (GET_POSITION(vict) > POS_SITTING
            && can_cast_spell(ch, SPELL_EGO_WHIP)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_EGO_WHIP);
            return;
        }
    }
    if (aggression > 50) {
        // somewhat aggressive - balance attacking with crippling
        if (!affected_by_spell(vict, SPELL_PSYCHIC_CRUSH)
            && can_cast_spell(ch, SPELL_PSYCHIC_CRUSH)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_PSYCHIC_CRUSH);
            return;
        } else if (!affected_by_spell(vict, SPELL_MOTOR_SPASM)
            && can_cast_spell(ch, SPELL_MOTOR_SPASM)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_MOTOR_SPASM);
            return;
        } else if (GET_POSITION(vict) > POS_SITTING
            && can_cast_spell(ch, SPELL_EGO_WHIP)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_EGO_WHIP);
            return;
        } else if (can_cast_spell(ch, SKILL_PSIBLAST)) {
            perform_offensive_skill(ch, vict, SKILL_PSIBLAST);
            return;
        }
    }
    if (aggression > 25) {
        // not very aggressive - play more defensively
        if (!IS_CONFUSED(vict)
            && can_cast_spell(ch, SPELL_CONFUSION)
            && (IS_MAGE(vict) || IS_PSIONIC(vict) || IS_CLERIC(vict) ||
                IS_KNIGHT(vict) || IS_PHYSIC(vict))) {
            cast_spell(ch, vict, NULL, NULL, SPELL_CONFUSION);
            return;
        } else if (!AFF2_FLAGGED(ch, AFF2_VERTIGO)
            && can_cast_spell(ch, SPELL_VERTIGO)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_VERTIGO);
            return;
        } else if (!affected_by_spell(vict, SPELL_PSYCHIC_FEEDBACK)
            && can_cast_spell(ch, SPELL_PSYCHIC_FEEDBACK)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_PSYCHIC_FEEDBACK);
            return;
        } else if (nullpsi_is_advisable(vict)
            && can_cast_spell(ch, SPELL_NULLPSI)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_NULLPSI);
            return;
        } else if (can_cast_spell(ch, SKILL_PSIBLAST)) {
            perform_offensive_skill(ch, vict, SKILL_PSIBLAST);
            return;
        }
    }
    if (aggression > 5) {
        // attempt to neutralize or get away
        if (GET_POSITION(vict) > POS_SLEEPING
            && can_cast_spell(ch, SPELL_MELATONIC_FLOOD)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_MELATONIC_FLOOD);
            return;
        } else if (can_cast_spell(ch, SPELL_ASTRAL_SPELL)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_ASTRAL_SPELL);
            return;
        } else if (can_cast_spell(ch, SPELL_AMNESIA)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_AMNESIA);
            return;
        } else if (can_cast_spell(ch, SPELL_FEAR)) {
            cast_spell(ch, vict, NULL, NULL, SPELL_FEAR);
            return;
        }
    }
    // desperation - just attack full force, as hard as possible
    if (!affected_by_spell(vict, SPELL_PSYCHIC_SURGE)
        && can_cast_spell(ch, SPELL_PSYCHIC_SURGE)) {
        cast_spell(ch, vict, NULL, NULL, SPELL_PSYCHIC_SURGE);
        return;
    } else if (!affected_by_spell(vict, SPELL_PSYCHIC_CRUSH)
        && can_cast_spell(ch, SPELL_PSYCHIC_CRUSH)) {
        cast_spell(ch, vict, NULL, NULL, SPELL_PSYCHIC_CRUSH);
        return;
    } else if (!affected_by_spell(vict, SPELL_MOTOR_SPASM)
        && can_cast_spell(ch, SPELL_MOTOR_SPASM)) {
        cast_spell(ch, vict, NULL, NULL, SPELL_MOTOR_SPASM);
        return;
    } else if (can_cast_spell(ch, SKILL_PSIBLAST)) {
        perform_offensive_skill(ch, vict, SKILL_PSIBLAST);
        return;
    } else if (GET_POSITION(vict) > POS_SITTING
        && can_cast_spell(ch, SPELL_EGO_WHIP)) {
        cast_spell(ch, vict, NULL, NULL, SPELL_EGO_WHIP);
        return;
    } else if (GET_POSITION(vict) > POS_SLEEPING
        && can_cast_spell(ch, SPELL_MELATONIC_FLOOD)) {
        cast_spell(ch, vict, NULL, NULL, SPELL_MELATONIC_FLOOD);
        return;
    } else if (can_cast_spell(ch, SPELL_ASTRAL_SPELL)) {
        cast_spell(ch, vict, NULL, NULL, SPELL_ASTRAL_SPELL);
        return;
    } else if (can_cast_spell(ch, SPELL_AMNESIA)) {
        cast_spell(ch, vict, NULL, NULL, SPELL_AMNESIA);
        return;
    } else if (can_cast_spell(ch, SPELL_FEAR)) {
        cast_spell(ch, vict, NULL, NULL, SPELL_FEAR);
        return;
    } else {
        hit(ch, vict, TYPE_UNDEFINED);
    }
}
Exemple #6
0
static void clearCapturedPiece(position *pos, const move * const m)
{
    int piece;
    int colour;
    int castleBits;

    /*
        ep is handled in movePiece(...) method and not here
        this only handles the "simple" capture
        TODO: change later?
     */
    piece = m->capturedPiece;
    colour = COLOUR(piece);
    assert(!IS_KING(piece));
    /* clear all pieces bitboard */
    CLR_BIT(pos->pieces[colour], m->to);
    /*
        Do NOT set m->to to 0, as board[m->to] contains the moved piece!
        Just update the bitboards.
     */
    if(IS_PAWN(piece)) {
        CLR_BIT(pos->pawns[colour], m->to);
    }
    else if(IS_KNIGHT(piece)) {
        CLR_BIT(pos->knights[colour], m->to);
    }
    else if(IS_BISHOP(piece)) {
        CLR_BIT(pos->bishops[colour], m->to);
    }
    else if(IS_ROOK(piece)) {
        CLR_BIT(pos->rooks[colour], m->to);
    }
    else if(IS_QUEEN(piece)) {
        CLR_BIT(pos->queens[colour], m->to);
    }
    else {
        /* Something is wrong, I don't know which piece this is.
         * This must NEVER happen; move generation is screwed.
         */
        assert(0);
    }

    /* check if rook square has been captured and disable castling */
    if(m->to == 0) {
        castleBits = CASTLE_WK;
        pos->castleFlags &= ~castleBits;
    }
    else if(m->to == 7) {
        castleBits = CASTLE_WQ;
        pos->castleFlags &= ~castleBits;

    }
    else if(m->to == 56) {
        castleBits = CASTLE_BK;
        pos->castleFlags &= ~castleBits;

    }
    else if(m->to == 63) {
        castleBits = CASTLE_BQ;
        pos->castleFlags &= ~castleBits;

    }

}
Exemple #7
0
static bitboard getAttackRange(const int piece, const int type, const int sq, const bitboard allPieces, const int epSquare)
{
    bitboard attackRange = 0;
    int state = 0;
    int rank;
    int file;
    bitboard rotAllPieces = 0;
    bitboard rot_a1h8_allPieces = 0;
    bitboard rot_h1a8_allPieces = 0;
    const bitboard *table1 = 0;
    const bitboard *table2 = 0;
    const bitboard *table_attack = 0;
    /* supports only normal and capture */
    assert(NORMAL == type || CAPTURE == type);
    if(IS_KING(piece)) {
        attackRange = _king[sq];
    }
    else if(IS_PAWN(piece)) {
        if(WHITE == COLOUR(piece)) {
            table1 = _wpawn_advance1;
            table2 = _wpawn_advance2;
            table_attack = _wpawn_attack;
        }
        else {
            table1 = _bpawn_advance1;
            table2 = _bpawn_advance2;
            table_attack = _bpawn_attack;
        }
        if(NORMAL == type) {
            attackRange = table1[sq] & ~allPieces;
            if(attackRange) {
                attackRange |= table2[sq] & ~allPieces;
            }
        }
        else { /* capture */
            attackRange = table_attack[sq];
            /* check for ep */
            if(epSquare != -1) {
                if(table_attack[sq] & _mask[epSquare]) {
                    attackRange |= _mask[epSquare];
                }
            }
        }
    }
    else if(IS_KNIGHT(piece)) {
        attackRange = _knight[sq];
    }
    else if(IS_BISHOP(piece)) {
        rot_a1h8_allPieces = rotate_a1h8(allPieces);
        state = A1H8_STATE(rot_a1h8_allPieces, sq);
        attackRange = _a1h8[sq][state];
        rot_h1a8_allPieces = rotate_h1a8(allPieces);
        state = H1A8_STATE(rot_h1a8_allPieces, sq);
        attackRange |= _h1a8[sq][state];
    }
    else if(IS_ROOK(piece)) {
        rank = sq / 8;
        file = sq % 8;
        state = RANK_STATE(allPieces, rank);
        attackRange = _horz[sq][state];
        rotAllPieces = rotate(allPieces);
        state = FILE_STATE(rotAllPieces, file);
        attackRange |= _vert[sq][state];
    }
    else if(IS_QUEEN(piece)) {
        /* rook like moves */
        rank = sq / 8;
        file = sq % 8;
        state = RANK_STATE(allPieces, rank);
        attackRange = _horz[sq][state];
        rotAllPieces = rotate(allPieces);
        state = FILE_STATE(rotAllPieces, file);
        attackRange |= _vert[sq][state];
        /* bishop like moves */
        rot_a1h8_allPieces = rotate_a1h8(allPieces);
        state = A1H8_STATE(rot_a1h8_allPieces, sq);
        attackRange |= _a1h8[sq][state];
        rot_h1a8_allPieces = rotate_h1a8(allPieces);
        state = H1A8_STATE(rot_h1a8_allPieces, sq);
        attackRange |= _h1a8[sq][state];
    }
    else {
        /* Something is wrong, I don't know which piece this is.
         * This must NEVER happen; move generation is screwed.
         */
        assert(0);
    }
    return attackRange;
}
Exemple #8
0
int
invalid_char_class(struct creature *ch, struct obj_data *obj)
{
    // Protected object
    if (IS_PC(ch) &&
        obj->shared->owner_id != 0 && obj->shared->owner_id != GET_IDNUM(ch)) {
        return true;
    }
    // Unapproved object
    if (!OBJ_APPROVED(obj) && !is_tester(ch) && GET_LEVEL(ch) < LVL_IMMORT)
        return true;

    // Anti class restrictions
    if ((IS_OBJ_STAT(obj, ITEM_ANTI_MAGIC_USER) && IS_MAGIC_USER(ch)) ||
        (IS_OBJ_STAT(obj, ITEM_ANTI_CLERIC) && IS_CLERIC(ch)) ||
        (IS_OBJ_STAT(obj, ITEM_ANTI_WARRIOR) && IS_WARRIOR(ch)) ||
        (IS_OBJ_STAT(obj, ITEM_ANTI_THIEF) && IS_THIEF(ch)) ||
        (IS_OBJ_STAT(obj, ITEM_ANTI_BARB) && IS_BARB(ch)) ||
        (IS_OBJ_STAT(obj, ITEM_ANTI_PSYCHIC) && IS_PSYCHIC(ch)) ||
        (IS_OBJ_STAT(obj, ITEM_ANTI_PHYSIC) && IS_PHYSIC(ch)) ||
        (IS_OBJ_STAT(obj, ITEM_ANTI_CYBORG) && IS_CYBORG(ch)) ||
        (IS_OBJ_STAT(obj, ITEM_ANTI_KNIGHT) && IS_KNIGHT(ch)) ||
        (IS_OBJ_STAT(obj, ITEM_ANTI_RANGER) && IS_RANGER(ch)) ||
        (IS_OBJ_STAT(obj, ITEM_ANTI_BARD) && IS_BARD(ch)) ||
        (IS_OBJ_STAT(obj, ITEM_ANTI_MONK) && IS_MONK(ch)) ||
        (IS_OBJ_STAT2(obj, ITEM2_ANTI_MERC) && IS_MERC(ch)))
        return true;

    // Required class restrictions - any one of them must be met
    if ((IS_OBJ_STAT3(obj, ITEM3_REQ_MAGE) && IS_MAGE(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_CLERIC) && IS_CLERIC(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_THIEF) && IS_THIEF(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_WARRIOR) && IS_WARRIOR(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_BARB) && IS_BARB(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_PSIONIC) && IS_PSIONIC(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_PHYSIC) && IS_PHYSIC(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_CYBORG) && IS_CYBORG(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_KNIGHT) && IS_KNIGHT(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_RANGER) && IS_RANGER(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_BARD) && IS_BARD(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_MONK) && IS_MONK(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_VAMPIRE) && IS_VAMPIRE(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_MERCENARY) && IS_MERC(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_SPARE1) && IS_SPARE1(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_SPARE2) && IS_SPARE2(ch))
        || (IS_OBJ_STAT3(obj, ITEM3_REQ_SPARE3) && IS_SPARE3(ch)))
        return false;

    // A required class existed and the creature didn't fulfill any
    if (IS_OBJ_STAT3(obj, ITEM3_REQ_MAGE
            | ITEM3_REQ_CLERIC
            | ITEM3_REQ_THIEF
            | ITEM3_REQ_WARRIOR
            | ITEM3_REQ_BARB
            | ITEM3_REQ_PSIONIC
            | ITEM3_REQ_PHYSIC
            | ITEM3_REQ_CYBORG
            | ITEM3_REQ_KNIGHT
            | ITEM3_REQ_RANGER
            | ITEM3_REQ_BARD
            | ITEM3_REQ_MONK
            | ITEM3_REQ_VAMPIRE
            | ITEM3_REQ_MERCENARY
            | ITEM3_REQ_SPARE1 | ITEM3_REQ_SPARE2 | ITEM3_REQ_SPARE3))
        return true;

    // Passes all tests
    return false;
}