///////////////////////////////////////////////// /// Cooperation: Unit can cooperate with another unit /// /// @note Relations API Tier 1 /// /// Client-side counterpart: <tt>CGUnit_C::CanCooperate(const CGUnit_C *this, const CGUnit_C *unit)</tt> ///////////////////////////////////////////////// bool Unit::CanCooperate(const Unit* unit) const { // Simple sanity check if (!unit) return false; // Original logic // Can't cooperate with yourself if (this == unit) return false; // We can't cooperate while being charmed or with charmed unit if (GetCharmerGuid() || unit->GetCharmerGuid()) return false; if (const FactionTemplateEntry* thisFactionTemplate = GetFactionTemplateEntry()) { if (const FactionTemplateEntry* unitFactionTemplate = unit->GetFactionTemplateEntry()) { if (thisFactionTemplate->factionGroupMask == unitFactionTemplate->factionGroupMask) // Pre-TBC: CanAttack check is not present clientside (always true), but potentially can be useful serverside to resolve some corner cases (e.g. duels). TODO: research needed return (!CanAttack(unit)); } } return false; }
///////////////////////////////////////////////// /// Interaction: Unit can interact with another unit (immediate response) /// /// @note Relations API Tier 1 /// /// Client-side counterpart: <tt>CGUnit_C::CanInteractNow(const CGUnit_C *this, const CGUnit_C *unit)</tt> ///////////////////////////////////////////////// bool Unit::CanInteractNow(const Unit* unit) const { // Simple sanity check if (!unit) return false; // Original logic // We can't intract while on taxi if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_TAXI_FLIGHT)) return false; // We can't interact while being charmed if (GetCharmerGuid()) return false; // We can't interact with anyone while being dead (this does not apply to player ghosts, which allow very limited interactions) if (!isAlive() && (GetTypeId() == TYPEID_UNIT || !(static_cast<const Player*>(this)->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)))) return false; // We can't interact with anyone while being shapeshifted, unless form flags allow us to do so if (IsShapeShifted()) { if (SpellShapeshiftFormEntry const* formEntry = sSpellShapeshiftFormStore.LookupEntry(GetShapeshiftForm())) { if (!(formEntry->flags1 & SHAPESHIFT_FORM_FLAG_ALLOW_NPC_INTERACT)) return false; } } // We can't interact with dead units, unless it's a creature with special flag if (!unit->isAlive()) { if (GetTypeId() != TYPEID_UNIT || !(static_cast<const Creature*>(unit)->GetCreatureInfo()->CreatureTypeFlags & CREATURE_TYPEFLAGS_INTERACT_DEAD)) return false; } // We can't interact with charmed units if (unit->GetCharmerGuid()) return false; // We can't interact with units who are currently fighting if (unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT) || unit->getVictim()) return false; return CanInteract(unit); }
void TemporarySpawn::Update(uint32 update_diff, uint32 diff) { switch (m_type) { case TEMPSPAWN_MANUAL_DESPAWN: break; case TEMPSPAWN_TIMED_DESPAWN: { if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; break; } case TEMPSPAWN_TIMED_OOC_DESPAWN: { if (isAlive()) { if (!isInCombat()) { if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; } else if (m_timer != m_lifetime) m_timer = m_lifetime; } else if (IsDespawned()) { UnSummon(); return; } break; } case TEMPSPAWN_CORPSE_TIMED_DESPAWN: { if (IsCorpse()) { if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; } if (IsDespawned()) { UnSummon(); return; } break; } case TEMPSPAWN_CORPSE_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (isDead()) { UnSummon(); return; } break; } case TEMPSPAWN_DEAD_DESPAWN: { if (IsDespawned()) { UnSummon(); return; } break; } case TEMPSPAWN_TIMED_OOC_OR_CORPSE_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (isDead()) { UnSummon(); return; } if (!isInCombat()) { if (m_timer <= update_diff) { UnSummon(); return; } else m_timer -= update_diff; } else if (m_timer != m_lifetime) m_timer = m_lifetime; break; } case TEMPSPAWN_TIMED_OOC_OR_DEAD_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (IsDespawned()) { UnSummon(); return; } if (!isInCombat() && isAlive() && !GetCharmerGuid()) { if (m_timer <= update_diff) { UnSummon(); return; } else m_timer -= update_diff; } else if (m_timer != m_lifetime) m_timer = m_lifetime; break; } case TEMPSPAWN_TIMED_OR_CORPSE_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (isDead()) { UnSummon(); return; } if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; break; } case TEMPSPAWN_TIMED_OR_DEAD_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (IsDespawned()) { UnSummon(); return; } if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; break; } default: UnSummon(); sLog.outError("Temporary summoned creature (entry: %u) have unknown type %u of ", GetEntry(), m_type); break; } switch (m_deathState) { case ALIVE: if (m_linkedToOwnerAura & TEMPSPAWN_LINKED_AURA_OWNER_CHECK) { if (!CheckAuraOnOwner()) UnSummon(); } break; case DEAD: case CORPSE: if (m_linkedToOwnerAura & TEMPSPAWN_LINKED_AURA_REMOVE_OWNER) { RemoveAuraFromOwner(); m_linkedToOwnerAura = 0; // we dont need to recheck } default: break; } Creature::Update(update_diff, diff); }