virtual MoveInfo getMove() override { const Creature* other = getClosestEnemy(); if (other != nullptr) { double myDamage = creature->getAttr(AttrType::DAMAGE); Item* weapon = getBestWeapon(); if (!creature->getWeapon() && weapon) myDamage += weapon->getModifier(AttrType::DAMAGE); double powerRatio = courage * myDamage / other->getAttr(AttrType::DAMAGE); bool significantEnemy = myDamage < 5 * other->getAttr(AttrType::DAMAGE); double weight = 1. - creature->getHealth() * 0.9; if (powerRatio < maxPowerRatio) weight += 2 - powerRatio * 2; weight = min(1.0, max(0.0, weight)); if (creature->isAffected(Creature::PANIC)) weight = 1; if (other->isAffected(Creature::SLEEP) || other->isStationary()) weight = 0; Debug() << creature->getName() << " panic weight " << weight; if (weight >= 0.5) { double dist = creature->getPosition().dist8(other->getPosition()); if (dist < 7) { if (dist == 1) EventListener::addSurrenderEvent(creature, other); if (MoveInfo move = getPanicMove(other, weight)) return move; else return getAttackMove(other, significantEnemy && chase); } return NoMove; } else return getAttackMove(other, significantEnemy && chase); } else return getLastSeenMove(); }
virtual double itemValue(const Item* item) override { if (contains<EffectType>({ EffectType(EffectId::LASTING, LastingEffect::INVISIBLE), EffectType(EffectId::LASTING, LastingEffect::SLOWED), EffectType(EffectId::LASTING, LastingEffect::BLIND), EffectType(EffectId::LASTING, LastingEffect::SLEEP), EffectType(EffectId::LASTING, LastingEffect::POISON), EffectType(EffectId::LASTING, LastingEffect::POISON_RESISTANT), EffectId::CURE_POISON, EffectId::TELEPORT, EffectType(EffectId::LASTING, LastingEffect::STR_BONUS), EffectType(EffectId::LASTING, LastingEffect::DEX_BONUS)}, item->getEffectType())) return 1; if (item->getClass() == ItemClass::AMMO && creature->getAttributes().getSkills().getValue(SkillId::ARCHERY) > 0) return 0.1; if (!creature->isEquipmentAppropriate(item)) return 0; if (item->getModifier(ModifierType::THROWN_DAMAGE) > 0) return (double)item->getModifier(ModifierType::THROWN_DAMAGE) / 50; int damage = item->getModifier(ModifierType::DAMAGE); Item* best = getBestWeapon(); if (best && best != item && best->getModifier(ModifierType::DAMAGE) >= damage) return 0; return (double)damage / 50; }
void CHLDMBot :: handleWeapons () { // // Handle attacking at this point // if ( m_pEnemy && !hasSomeConditions(CONDITION_ENEMY_DEAD) && hasSomeConditions(CONDITION_SEE_CUR_ENEMY) && wantToShoot() && isVisible(m_pEnemy) && isEnemy(m_pEnemy) ) { CBotWeapon *pWeapon; pWeapon = getBestWeapon(m_pEnemy,true,true,(m_pEnemy==m_NearestBreakable)&&!rcbot_melee_only.GetBool()); if ( m_bWantToChangeWeapon && (pWeapon != NULL) && (pWeapon != getCurrentWeapon()) && pWeapon->getWeaponIndex() ) { //selectWeaponSlot(pWeapon->getWeaponInfo()->getSlot()); selectWeapon(pWeapon->getWeaponIndex()); } setLookAtTask((LOOK_ENEMY)); ///battack = true; if ( !handleAttack ( pWeapon, m_pEnemy ) ) { m_pEnemy = NULL; m_pOldEnemy = NULL; wantToShoot(false); } } }
MoveInfo getAttackMove(Creature* other, bool chase) { int distance = 10000; CHECK(other); if (other->getAttributes().isInvincible()) return NoMove; Debug() << creature->getName().bare() << " enemy " << other->getName().bare(); Vec2 enemyDir = creature->getPosition().getDir(other->getPosition()); distance = enemyDir.length8(); if (creature->getAttributes().isHumanoid() && !creature->getWeapon()) { if (Item* weapon = getBestWeapon()) if (auto action = creature->equip(weapon)) return {3.0 / (2.0 + distance), action.prepend([=](Creature* creature) { creature->setInCombat(); other->setInCombat(); })}; } if (distance == 1) if (MoveInfo move = tryEffect(EffectId::AIR_BLAST, 1)) return move; if (distance <= 5) for (EffectType effect : { EffectType(EffectId::LASTING, LastingEffect::INVISIBLE), EffectType(EffectId::LASTING, LastingEffect::STR_BONUS), EffectType(EffectId::LASTING, LastingEffect::DEX_BONUS), EffectType(EffectId::LASTING, LastingEffect::SPEED), EffectType(EffectId::DECEPTION), EffectType(EffectId::SUMMON, CreatureId::SPIRIT)}) if (MoveInfo move = tryEffect(effect, 1)) return move; if (distance > 1) { if (distance < 10) { if (MoveInfo move = getFireMove(enemyDir)) return move; if (MoveInfo move = getThrowMove(enemyDir)) return move; } if (chase && !other->getAttributes().dontChase() && !isChaseFrozen(other)) { lastSeen = none; if (auto action = creature->moveTowards(other->getPosition())) return {max(0., 1.0 - double(distance) / 10), action.prepend([=](Creature* creature) { creature->setInCombat(); other->setInCombat(); lastSeen = {other->getPosition(), creature->getGlobalTime(), LastSeen::ATTACK, other->getUniqueId()}; if (!chaseFreeze.count(other) || other->getGlobalTime() > chaseFreeze.at(other).second) chaseFreeze[other] = make_pair(other->getGlobalTime() + 20, other->getGlobalTime() + 70); })}; } } if (distance == 1) if (auto action = creature->attack(other, getAttackParams(other))) return {1.0, action.prepend([=](Creature* creature) { creature->setInCombat(); other->setInCombat(); })}; return NoMove; }
MoveInfo getAttackMove(const Creature* other, bool chase) { int radius = 4; int distance = 10000; CHECK(other); if (other->isInvincible()) return NoMove; Debug() << creature->getName() << " enemy " << other->getName(); Vec2 enemyDir = (other->getPosition() - creature->getPosition()); distance = enemyDir.length8(); if (creature->isHumanoid() && !creature->getEquipment().getItem(EquipmentSlot::WEAPON)) { Item* weapon = getBestWeapon(); if (weapon != nullptr && creature->canEquip(weapon, nullptr)) return {3.0 / (2.0 + distance), [this, weapon, other]() { EventListener::addCombatEvent(creature); EventListener::addCombatEvent(other); creature->globalMessage(creature->getTheName() + " draws " + weapon->getAName()); creature->equip(weapon); }}; } if (distance <= 5) for (EffectType effect : {EffectType::INVISIBLE, EffectType::STR_BONUS, EffectType::DEX_BONUS, EffectType::SPEED, EffectType::SUMMON_SPIRIT}) if (MoveInfo move = tryToApplyItem(effect, 1)) return move; if (distance > 1) { if (MoveInfo move = getFireMove(enemyDir)) return move; if (MoveInfo move = getThrowMove(enemyDir)) return move; if (chase && other->getTribe() != Tribes::get(TribeId::WILDLIFE)) { Optional<Vec2> move = creature->getMoveTowards(creature->getPosition() + enemyDir); lastSeen = Nothing(); if (move) return {max(0., 1.0 - double(distance) / 10), [this, enemyDir, move, other]() { EventListener::addCombatEvent(creature); EventListener::addCombatEvent(other); lastSeen = {creature->getPosition() + enemyDir, creature->getTime(), creature->getLevel(), LastSeen::ATTACK, other}; creature->move(*move); }}; } } if (distance == 1) { if (creature->canAttack(other)) return {1.0, [this, other]() { EventListener::addCombatEvent(creature); EventListener::addCombatEvent(other); creature->attack(other); }}; } return NoMove; }
virtual double itemValue(const Item* item) { if (contains({EffectType::INVISIBLE, EffectType::SLOW, EffectType::BLINDNESS, EffectType::SLEEP, EffectType::POISON, EffectType::TELEPORT, EffectType::STR_BONUS, EffectType::DEX_BONUS}, item->getEffectType())) return 1; if (item->getType() == ItemType::AMMO && creature->hasSkill(Skill::archery)) return 0.1; if (item->getType() != ItemType::WEAPON || !creature->hasSkillToUseWeapon(item)) return 0; if (item->getModifier(AttrType::THROWN_DAMAGE) > 0) return (double)item->getModifier(AttrType::THROWN_DAMAGE) / 50; int damage = item->getModifier(AttrType::DAMAGE); Item* best = getBestWeapon(); if (best && best != item && best->getModifier(AttrType::DAMAGE) >= damage) return 0; return (double)damage / 50; }