/** * Performs all the overall functions of the state, this code runs AFTER the explosion state pops. */ void MeleeAttackBState::think() { _parent->getSave()->getBattleState()->clearMouseScrollingState(); // if the unit burns floortiles, burn floortiles if (_unit->getSpecialAbility() == SPECAB_BURNFLOOR || _unit->getSpecialAbility() == SPECAB_BURN_AND_EXPLODE) { _parent->getSave()->getTile(_action.target)->ignite(15); } // Determine if the attack was successful // we do this here instead of letting the explosionBState take care of damage and casualty checking // this is because unlike regular bullet hits or explosions, melee attacks can MISS. // we also do it at this point instead of in performMeleeAttack because we want the scream to come AFTER the hit sound resolveHit(); // aliens if (_unit->getFaction() != FACTION_PLAYER && // not performing a reaction attack _unit->getFaction() == _parent->getSave()->getSide() && // with enough TU for a second attack (*2 because they'll get charged for the initial attack when this state pops.) _unit->getTimeUnits() >= _unit->getActionTUs(BA_HIT, _action.weapon) * 2 && // whose target is still alive or at least conscious _target && _target->getHealth() > 0 && _target->getHealth() > _target->getStunlevel() && // and we still have ammo to make the attack _weapon->getAmmoItem()) { // spend the TUs immediately _unit->spendTimeUnits(_unit->getActionTUs(BA_HIT, _weapon)); performMeleeAttack(); } else { if (_action.cameraPosition.z != -1) { _parent->getMap()->getCamera()->setMapOffset(_action.cameraPosition); _parent->getMap()->invalidate(); } // melee doesn't trigger a reaction, remove comments to enable. // if (!_parent->getSave()->getUnitsFalling()) // { // _parent->getTileEngine()->checkReactionFire(_unit); // } if (_parent->getSave()->getSide() == FACTION_PLAYER || _parent->getSave()->getDebugMode()) { _parent->setupCursor(); } _parent->convertInfected(); _parent->popState(); } }
/** * Performs all the overall functions of the state, this code runs AFTER the explosion state pops. */ void MeleeAttackBState::think() { _parent->getSave()->getBattleState()->clearMouseScrollingState(); if (_reaction && !_parent->getSave()->getUnitsFalling()) { _reaction = false; if (_parent->getTileEngine()->checkReactionFire(_unit, _action)) { return; } } // if the unit burns floortiles, burn floortiles if (_unit->getSpecialAbility() == SPECAB_BURNFLOOR || _unit->getSpecialAbility() == SPECAB_BURN_AND_EXPLODE) { _parent->getSave()->getTile(_action.target)->ignite(15); } if (_hitNumber > 0 && // not performing a reaction attack _unit->getFaction() == _parent->getSave()->getSide() && // whose target is still alive or at least conscious _target && !_target->isOutThresholdExceed() && // and we still have ammo to make the attack _weapon->getAmmoForAction(BA_HIT) && // spend the TUs immediately _action.spendTU()) { --_hitNumber; performMeleeAttack(); } else { if (_action.cameraPosition.z != -1) { _parent->getMap()->getCamera()->setMapOffset(_action.cameraPosition); _parent->getMap()->invalidate(); } if (_parent->getSave()->getSide() == FACTION_PLAYER || _parent->getSave()->getDebugMode()) { _parent->setupCursor(); } _parent->convertInfected(); _parent->popState(); } }
/** * Initializes the sequence. * does a lot of validity checking. */ void MeleeAttackBState::init() { if (_initialized) return; _initialized = true; _weapon = _action.weapon; if (!_weapon) // can't hit without weapon { _parent->popState(); return; } _unit = _action.actor; bool reactionShoot = _unit->getFaction() != _parent->getSave()->getSide(); _ammo = _action.weapon->getAmmoForAction(BA_HIT, reactionShoot ? nullptr : &_action.result); if (!_ammo) { _parent->popState(); return; } if (!_parent->getSave()->getTile(_action.target)) // invalid target position { _parent->popState(); return; } if (_unit->isOut() || _unit->isOutThresholdExceed()) { // something went wrong - we can't shoot when dead or unconscious, or if we're about to fall over. _parent->popState(); return; } // reaction fire if (reactionShoot) { // no ammo or target is dead: give the time units back and cancel the shot. auto target = _parent->getSave()->getTile(_action.target)->getUnit(); if (!target || target->isOut() || target->isOutThresholdExceed() || target != _parent->getSave()->getSelectedUnit()) { _parent->popState(); return; } _unit->lookAt(_action.target, _unit->getTurretType() != -1); while (_unit->getStatus() == STATUS_TURNING) { _unit->turn(); } } //spend TU if (!_action.spendTU(&_action.result)) { _parent->popState(); return; } AIModule *ai = _unit->getAIModule(); if (_unit->getFaction() == _parent->getSave()->getSide() && _unit->getFaction() != FACTION_PLAYER && _parent->_debugPlay == false && ai && ai->getTarget()) { _target = ai->getTarget(); } else { _target = _parent->getSave()->getTile(_action.target)->getUnit(); } int height = _target->getFloatHeight() + (_target->getHeight() / 2) - _parent->getSave()->getTile(_action.target)->getTerrainLevel(); _voxel = _action.target.toVexel() + Position(8, 8, height); if (_unit->getFaction() == FACTION_HOSTILE) { _hitNumber = _weapon->getRules()->getAIMeleeHitCount() - 1; } performMeleeAttack(); }
/** * Initializes the sequence. * does a lot of validity checking. */ void MeleeAttackBState::init() { if (_initialized) return; _initialized = true; _weapon = _action.weapon; _ammo = _weapon->getAmmoItem(); if (!_weapon) // can't shoot without weapon { _parent->popState(); return; } if (!_parent->getSave()->getTile(_action.target)) // invalid target position { _parent->popState(); return; } _unit = _action.actor; if (_unit->isOut() || _unit->getHealth() == 0 || _unit->getHealth() < _unit->getStunlevel()) { // something went wrong - we can't shoot when dead or unconscious, or if we're about to fall over. _parent->popState(); return; } // reaction fire if (_unit->getFaction() != _parent->getSave()->getSide()) { // no ammo or target is dead: give the time units back and cancel the shot. if (_ammo == 0 || !_parent->getSave()->getTile(_action.target)->getUnit() || _parent->getSave()->getTile(_action.target)->getUnit()->isOut() || _parent->getSave()->getTile(_action.target)->getUnit() != _parent->getSave()->getSelectedUnit()) { _unit->setTimeUnits(_unit->getTimeUnits() + _unit->getActionTUs(_action.type, _action.weapon)); _parent->popState(); return; } _unit->lookAt(_action.target, _unit->getTurretType() != -1); while (_unit->getStatus() == STATUS_TURNING) { _unit->turn(); } } AlienBAIState *ai = dynamic_cast<AlienBAIState*>(_unit->getCurrentAIState()); if (_unit->getFaction() != FACTION_PLAYER && _parent->_debugPlay == false && ai && ai->getTarget()) { _target = ai->getTarget(); } else { _target = _parent->getSave()->getTile(_action.target)->getUnit(); } int height = _target->getFloatHeight() + (_target->getHeight() / 2) - _parent->getSave()->getTile(_action.target)->getTerrainLevel(); _voxel = _action.target * Position(16, 16, 24) + Position(8, 8, height); performMeleeAttack(); }