//-------------------------------------------------------------------------------------------- int randomize_action( int action, int slot ) { /// @details BB@> this function actually determines whether the action fillows the /// pattern of ACTION_?A, ACTION_?B, ACTION_?C, ACTION_?D, with /// A and B being for the left hand, and C and D being for the right hand int diff = 0; // a valid slot? if ( slot < 0 || slot >= SLOT_COUNT ) return action; // a valid action? if ( action < 0 || action >= ACTION_COUNT ) return bfalse; diff = slot * 2; //---- non-randomizable actions if ( ACTION_MG == action ) return action; // MG = Open Chest else if ( ACTION_MH == action ) return action; // MH = Sit else if ( ACTION_MI == action ) return action; // MI = Ride else if ( ACTION_MJ == action ) return action; // MJ = Object Activated else if ( ACTION_MK == action ) return action; // MK = Snoozing else if ( ACTION_ML == action ) return action; // ML = Unlock else if ( ACTION_JA == action ) return action; // JA = Jump else if ( ACTION_RA == action ) return action; // RA = Roll else if ( ACTION_IS_TYPE( action, W ) ) return action; // WA - WD = Walk //---- do a couple of special actions that have left/right else if ( ACTION_EA == action || ACTION_EB == action ) action = ACTION_JB + slot; // EA/EB = Evade left/right else if ( ACTION_JB == action || ACTION_JC == action ) action = ACTION_JB + slot; // JB/JC = Dropped item left/right else if ( ACTION_MA == action || ACTION_MB == action ) action = ACTION_MA + slot; // MA/MB = Drop left/right item else if ( ACTION_MC == action || ACTION_MD == action ) action = ACTION_MC + slot; // MC/MD = Slam left/right else if ( ACTION_ME == action || ACTION_MF == action ) action = ACTION_ME + slot; // ME/MF = Grab item left/right else if ( ACTION_MM == action || ACTION_MN == action ) action = ACTION_MM + slot; // MM/MN = Held left/right //---- actions that can be randomized, but are not left/right sensitive // D = dance else if ( ACTION_IS_TYPE( action, D ) ) action = ACTION_TYPE( D ) + generate_randmask( 0, 3 ); //---- handle all the normal attack/defense animations // U = unarmed else if ( ACTION_IS_TYPE( action, U ) ) action = ACTION_TYPE( U ) + diff + generate_randmask( 0, 1 ); // T = thrust else if ( ACTION_IS_TYPE( action, T ) ) action = ACTION_TYPE( T ) + diff + generate_randmask( 0, 1 ); // C = chop else if ( ACTION_IS_TYPE( action, C ) ) action = ACTION_TYPE( C ) + diff + generate_randmask( 0, 1 ); // S = slice else if ( ACTION_IS_TYPE( action, S ) ) action = ACTION_TYPE( S ) + diff + generate_randmask( 0, 1 ); // B = bash else if ( ACTION_IS_TYPE( action, B ) ) action = ACTION_TYPE( B ) + diff + generate_randmask( 0, 1 ); // L = longbow else if ( ACTION_IS_TYPE( action, L ) ) action = ACTION_TYPE( L ) + diff + generate_randmask( 0, 1 ); // X = crossbow else if ( ACTION_IS_TYPE( action, X ) ) action = ACTION_TYPE( X ) + diff + generate_randmask( 0, 1 ); // F = fling else if ( ACTION_IS_TYPE( action, F ) ) action = ACTION_TYPE( F ) + diff + generate_randmask( 0, 1 ); // P = parry/block else if ( ACTION_IS_TYPE( action, P ) ) action = ACTION_TYPE( P ) + diff + generate_randmask( 0, 1 ); // Z = zap else if ( ACTION_IS_TYPE( action, Z ) ) action = ACTION_TYPE( Z ) + diff + generate_randmask( 0, 1 ); //---- these are passive actions // H = hurt else if ( ACTION_IS_TYPE( action, H ) ) action = ACTION_TYPE( H ) + generate_randmask( 0, 3 ); // K = killed else if ( ACTION_IS_TYPE( action, K ) ) action = ACTION_TYPE( K ) + generate_randmask( 0, 3 ); return action; }
void Enchantment::applyEnchantment(std::shared_ptr<Object> target) { //Invalid target? if( target->isTerminated() || (!target->isAlive() && !_enchantProfile->_target._stay) ) { Log::get().warn("%s:%d: invalid target\n", __FILE__, __LINE__); requestTerminate(); return; } //Already added to a target? if(_target.lock()) { throw std::logic_error("Enchantment::applyEnchantment() - Already applied\n"); } // do retargeting, if necessary // Should it choose an inhand item? if (_enchantProfile->retarget) { // Left, right, or both are valid if (target->getRightHandItem()) { // Only right hand is valid target = target->getRightHandItem(); } else if (target->getLeftHandItem()) { // Pick left hand target = target->getLeftHandItem(); } else { // No weapons to pick, make it fail Log::get().debug("Enchantment::applyEnchantment() - failed because target has no valid items in hand\n"); requestTerminate(); return; } } //Set our target, stored as a weak_ptr _target = target; // Check damage type, 90% damage resistance is enough to resist the enchant if (_enchantProfile->required_damagetype < DAMAGE_COUNT) { if (target->getDamageReduction(_enchantProfile->required_damagetype) >= 0.90f) { Log::get().debug("Enchantment::applyEnchantment() - failed because the target is immune to the enchant.\n"); requestTerminate(); return; } } // Check if target has the required damage type we need if (_enchantProfile->require_damagetarget_damagetype < DAMAGE_COUNT) { if (target->damagetarget_damagetype != _enchantProfile->require_damagetarget_damagetype) { Log::get().warn("%s:%d: application of enchantment failed because the target not have the right damagetarget_damagetype.\n", __FILE__, __LINE__); requestTerminate(); return; } } //modify enchant duration with damage resistance (bad resistance actually *increases* duration!) if ( _lifeTime > 0 && _enchantProfile->required_damagetype < DAMAGE_COUNT && target ) { _lifeTime -= std::ceil(target->getDamageReduction(_enchantProfile->required_damagetype) * _enchantProfile->lifetime); } // Create an overlay character? if (_enchantProfile->spawn_overlay) { std::shared_ptr<Object> overlay = _currentModule->spawnObject(target->getPosition(), _spawnerProfileID, target->team, 0, target->ori.facing_z, "", ObjectRef::Invalid ); if (overlay) { _overlay = overlay; //Kill this character on end... overlay->ai.setTarget(target->getObjRef()); overlay->is_overlay = true; overlay->ai.state = _enchantProfile->spawn_overlay; // ??? WHY DO THIS ??? // Start out with ActionMJ... Object activated int action = overlay->getProfile()->getModel()->getAction(ACTION_MJ); if ( !ACTION_IS_TYPE( action, D ) ) { chr_start_anim( overlay.get(), action, false, true ); } // Assume it's transparent... overlay->setLight(254); overlay->setAlpha(128); } } //Check if this enchant has any set modifiers that conflicts with another enchant _modifiers.remove_if([this, &target](const EnchantModifier &modifier) { //Only set types can conflict if(!Ego::Attribute::isOverrideSetAttribute(modifier._type)) { return false; } //Is there no conflict? if(target->getTempAttributes().find(modifier._type) == target->getTempAttributes().end()) { return false; } //Ok there exist a conflict, so now we have to resolve it somehow //Does this enchant override other enchants? if(getProfile()->_override) { bool conflictResolved = false; //Find the active enchant that conflicts with us for(const std::shared_ptr<Ego::Enchantment> &conflictingEnchant : target->getActiveEnchants()) { conflictingEnchant->_modifiers.remove_if([this, &conflictingEnchant, &modifier, &conflictResolved](const EnchantModifier &otherModifier) { //Is this the one? if(modifier._type == otherModifier._type) { conflictResolved = true; //Remove Enchants that conflict with this one? if(getProfile()->remove_overridden) { conflictingEnchant->requestTerminate(); } return true; } //Nope, keep looking return false; }); //Has it been resolved? if(conflictResolved) { break; } } //We have higher priority than exiting enchants return false; } else { //The existing enchant has higher priority than ours return true; } }); //Now actually apply the values to the target for(const EnchantModifier &modifier : _modifiers) { //These should never occur if(modifier._type == Ego::Attribute::NR_OF_PRIMARY_ATTRIBUTES || modifier._type == Ego::Attribute::NR_OF_ATTRIBUTES) { throw std::logic_error("Enchant.cpp - Invalid enchant type: meta-type as modifier"); } //Morph is special and handled differently than others if(modifier._type == Ego::Attribute::MORPH) { //Store target's original armor target->getTempAttributes()[Ego::Attribute::MORPH] = target->skin; //Transform the object target->polymorphObject(_spawnerProfileID, 0); } //Is it a set type? else if(Ego::Attribute::isOverrideSetAttribute(modifier._type)) { target->getTempAttributes()[modifier._type] = modifier._value; } //It's a cumulative addition else { target->getTempAttributes()[modifier._type] += modifier._value; } } //Finally apply boost values to owner as well std::shared_ptr<Object> owner = _owner.lock(); if(owner != nullptr && !owner->isTerminated()) { owner->getTempAttributes()[Ego::Attribute::MANA_REGEN] += _ownerManaSustain; owner->getTempAttributes()[Ego::Attribute::LIFE_REGEN] += _ownerLifeSustain; } //Insert this enchantment into the Objects list of active enchants target->getActiveEnchants().push_front(shared_from_this()); }