⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 interface.cpp.svn-base

📁 絲路server源碼 Silk Road server source
💻 SVN-BASE
📖 第 1 页 / 共 5 页
字号:
		{
		case AGENT_MELEE:
			{
				float combatReach[2]; // Calculate Combat Reach
				float distance = m_Unit->CalcDistance(m_nextTarget);

				combatReach[0] = PLAYER_SIZE;
				combatReach[1] = _CalcCombatRange(m_nextTarget, false);

				if(	
					distance >= combatReach[0] && 
					distance <= combatReach[1] + DISTANCE_TO_SMALL_TO_WALK) // Target is in Range -> Attack
				{
					if(UnitToFollow != NULL)
					{
						UnitToFollow = NULL; //we shouldn't be following any one
						m_lastFollowX = m_lastFollowY = 0;
						//m_Unit->setAttackTarget(NULL);  // remove ourselves from any target that might have been followed
					}
					
					FollowDistance = 0.0f;
//					m_move = false;
					//FIXME: offhand shit
					if(m_Unit->isAttackReady(false) && !m_fleeTimer)
					{
						m_MONSTERState = ATTACKING;
						bool infront = m_Unit->isInFront(m_nextTarget);

						if(!infront) // set InFront
						{
							//prevent mob from rotating while stunned
							if(!m_Unit->IsStunned ())
							{
								setInFront(m_nextTarget);
								infront = true;
							}							
						}
						if(infront)
						{
							m_Unit->setAttackTimer(0, false);
#ifdef ENABLE_MONSTER_DAZE
							//we require to know if strike was succesfull. If there was no dmg then target cannot be dazed by it
							uint32 health_before_strike=m_nextTarget->GetUInt32Value(UNIT_FIELD_HEALTH);
#endif
							m_Unit->Strike( m_nextTarget, ( agent == AGENT_MELEE ? MELEE : RANGED ), NULL, 0, 0, 0, false, false );
#ifdef ENABLE_MONSTER_DAZE
							//now if the target is facing his back to us then we could just cast dazed on him :P
							//as far as i know dazed is casted by most of the MONSTERs but feel free to remove this code if you think otherwise
							if(m_nextTarget &&
								!(m_Unit->m_factionDBC->RepListId == -1 && m_Unit->m_faction->FriendlyMask==0 && m_Unit->m_faction->HostileMask==0) /* neutral MONSTER */
								&& m_nextTarget->IsPlayer() && !m_Unit->IsPet() && health_before_strike>m_nextTarget->GetUInt32Value(UNIT_FIELD_HEALTH)
								&& Rand(m_Unit->get_chance_to_daze(m_nextTarget)))
							{
								float our_facing=m_Unit->calcRadAngle(m_Unit->GetPositionX(),m_Unit->GetPositionY(),m_nextTarget->GetPositionX(),m_nextTarget->GetPositionY());
								float his_facing=m_nextTarget->GetOrientation();
								if(fabs(our_facing-his_facing)<MONSTER_DAZE_TRIGGER_ANGLE && !m_nextTarget->HasNegativeAura(MONSTER_SPELL_TO_DAZE))
								{
									SpellEntry *info = dbcSpell.LookupEntry(MONSTER_SPELL_TO_DAZE);
									Spell *sp = new Spell(m_Unit, info, false, NULL);
									SpellCastTargets targets;
									targets.m_unitTarget = m_nextTarget->GetGUID();
									sp->prepare(&targets);
								}
							}
#endif
						}
					}
				}
				else // Target out of Range ->  to it
				{
					//calculate next move
					float dist = combatReach[1]-PLAYER_SIZE;

					if(dist < PLAYER_SIZE)
						dist = PLAYER_SIZE; //unbelievable how this could happen
					if (distance<combatReach[0])
						dist = -(distance+combatReach[0]*0.6666f);

					m_move = true;
					_CalcDestinationAndMove(m_nextTarget, dist);
				}
			}break;
		case AGENT_RANGED:
			{
				float combatReach[2]; // Calculate Combat Reach
				float distance = m_Unit->CalcDistance(m_nextTarget);

				combatReach[0] = 8.0f;
				combatReach[1] = 30.0f;

				if(distance >= combatReach[0] && distance <= combatReach[1]) // Target is in Range -> Attack
				{
					if(UnitToFollow != NULL)
					{
						UnitToFollow = NULL; //we shouldn't be following any one
						m_lastFollowX = m_lastFollowY = 0;
						//m_Unit->setAttackTarget(NULL);  // remove ourselves from any target that might have been followed
					}
					
					FollowDistance = 0.0f;
//					m_move = false;
					//FIXME: offhand shit
					if(m_Unit->isAttackReady(false) && !m_fleeTimer)
					{
						m_MONSTERState = ATTACKING;
						bool infront = m_Unit->isInFront(m_nextTarget);

						if(!infront) // set InFront
						{
							//prevent mob from rotating while stunned
							if(!m_Unit->IsStunned ())
							{
								setInFront(m_nextTarget);
								infront = true;
							}							
						}

						if(infront)
						{
							m_Unit->setAttackTimer(0, false);
							SpellEntry *info = dbcSpell.LookupEntry(SPELL_RANGED_GENERAL);
							if(info)
							{
								Spell *sp = new Spell(m_Unit, info, false, NULL);
								SpellCastTargets targets;
								targets.m_unitTarget = m_nextTarget->GetGUID();
								sp->prepare(&targets);
								//Lets make spell handle this
								//m_Unit->Strike( m_nextTarget, ( agent == AGENT_MELEE ? MELEE : RANGED ), NULL, 0, 0, 0 );
							}
						}
					}
				}
				else // Target out of Range ->  to it
				{
					//calculate next move
					float dist;

					if(distance < combatReach[0])// Target is too near
						dist = 9.0f;
					else
						dist = 20.0f;

					m_move = true;
					_CalcDestinationAndMove(m_nextTarget, dist);
				}
			}break;
		case AGENT_SPELL:
			{
				if(!m_nextSpell || !m_nextTarget)
					return;  // this shouldnt happen

				/* stop moving so we don't interrupt the spell */
				//this the way justly suggested
//				if(m_nextSpell->spell->CastingTimeIndex != 1)
				//do not stop for instant SKILLS
				SpellCastTime *sd = dbcSpellCastTime.LookupEntry(m_nextSpell->spell->CastingTimeIndex);
				if(GetCastTime(sd) != 0)
					StopMovement(0);

				float distance = m_Unit->GetDistanceSq(m_nextTarget);
				bool los = true;
#ifdef COLLISION
				los = CollideInterface.CheckLOS(m_Unit->GetMapId(), m_Unit->GetPositionNC(),m_nextTarget->GetPositionNC());
#endif
				if(los && ((distance <= (m_nextSpell->maxrange*m_nextSpell->maxrange)  && distance >= (m_nextSpell->minrange*m_nextSpell->minrange)) || m_nextSpell->maxrange == 0)) // Target is in Range -> Attack
				{
					SpellEntry* spellInfo = m_nextSpell->spell;
/*					if(m_nextSpell->procCount)
						m_nextSpell->procCount--;*/

					SpellCastTargets targets = setSpellTargets(spellInfo, m_nextTarget);
					uint32 targettype = m_nextSpell->spelltargetType;
					switch(targettype)
					{
					case TTYPE_CASTER:
					case TTYPE_SINGLETARGET:
						{
							CastSpell(m_Unit, spellInfo, targets);
							break;
						}
					case TTYPE_SOURCE:
						{
							m_Unit->CastSpellAoF(targets.m_srcX,targets.m_srcY,targets.m_srcZ, spellInfo, true);
							break;
						}
					case TTYPE_DESTINATION:
						{
							m_Unit->CastSpellAoF(targets.m_destX,targets.m_destY,targets.m_destZ, spellInfo, true);
							break;
						}
					}
					// CastSpell(m_Unit, spellInfo, targets);
					if(m_nextSpell&&m_nextSpell->cooldown)
						m_nextSpell->cooldowntime = getMSTime() + m_nextSpell->cooldown;

					//add pet spell after use to pet owner with some chance
					if(m_Unit->IsPet() && m_PetOwner->IsPlayer())
					{	
						Pet * pPet = static_cast<Pet*>(m_Unit);
						if(pPet && Rand(10))
							pPet->AddPetSpellToOwner(spellInfo->Id);
					}
					m_nextSpell = NULL;
				}
				else // Target out of Range ->  to it
				{
					//calculate next move
					m_move = true;
					if(m_nextSpell->maxrange < 5.0f)
						_CalcDestinationAndMove(m_nextTarget, 0.0f);
					else
						_CalcDestinationAndMove(m_nextTarget, m_nextSpell->maxrange - 5.0f);
					/*Destination* dst = _CalcDestination(m_nextTarget, dist);
					MoveTo(dst->x, dst->y, dst->z,0);
					delete dst;*/
				}
			}break;
		case AGENT_FLEE:
			{
				//float dist = 5.0f;

				m_move = false;
				if(m_fleeTimer == 0)
					m_fleeTimer = m_FleeDuration;

				/*Destination* dst = _CalcDestination(m_nextTarget, dist);
				MoveTo(dst->x, dst->y, dst->z,0);
				delete dst;*/
				_CalcDestinationAndMove(m_nextTarget, 5.0f);
				if(!m_hasFleed)
					CALL_SCRIPT_EVENT(m_Unit, OnFlee)(m_nextTarget);

				m_AIState = STATE_FLEEING;
				//removed by Zack : somehow MONSTER starts to attack sefl. Just making sure it is not this one
//				m_nextTarget = m_Unit;
//				m_Unit->SetUInt64Value(UNIT_FIELD_TARGET, 0);
				SetNextTarget(NULL);

				WorldPacket data( SMSG_MESSAGECHAT, 100 );
				string msg = "%s attempts to  away in fear!";
				data << (uint8)CHAT_MSG_CHANNEL;
				data << (uint32)LANG_UNIVERSAL;
				data << (uint32)( strlen( static_cast< MONSTER* >( m_Unit )->GetMONSTERName()->Name ) + 1 );
				data << static_cast< MONSTER* >( m_Unit )->GetMONSTERName()->Name;
				data << (uint64)0;
				data << (uint32)(msg.size() + 1);
				data << msg;
				data << uint8(0);

				m_Unit->SendMessageToSet(&data, false);

				//m_Unit->SendChatMessage(CHAT_MSG_MONSTER_EMOTE, LANG_UNIVERSAL, msg);
				//sChatHandler.FillMessageData(&data, CHAT_MSG_MONSTER_EMOTE, LANG_UNIVERSAL, msg, m_Unit->GetGUID());			   
			   
				m_hasFleed = true;
			}break;
		case AGENT_CALLFORHELP:
			{
				FindFriends( 50.0f /*7.0f*/ );
				m_hasCalledForHelp = true; // We only want to call for Help once in a Fight.
				if( m_Unit->GetTypeId() == TYPEID_UNIT )
						objmgr.HandleMonsterSayEvent( static_cast< MONSTER* >( m_Unit ), MONSTER_SAY_EVENT_CALL_HELP );
				CALL_SCRIPT_EVENT( m_Unit, OnCallForHelp )();
			}break;
		}
	}
	else if( !m_nextTarget || m_nextTarget->GetInstanceID() != m_Unit->GetInstanceID() || !m_nextTarget->isAlive() || !cansee )
	{
		SetNextTarget( NULL );
		// no more target
		//m_Unit->setAttackTarget(NULL);
	}
}

void AIInterface::DismissPet()
{
	/*
	if(m_AIType != AITYPE_PET)
		return;

	if(!m_PetOwner)
		return;
	
	if(m_PetOwner->GetTypeId() != TYPEID_PLAYER)
		return;

	if(m_Unit->GetUInt32Value(UNIT_CREATED_BY_SPELL) == 0)
		static_cast< Player* >( m_PetOwner )->SetFreePetNo(false, (int)m_Unit->GetUInt32Value(UNIT_FIELD_PETNUMBER));
	static_cast< Player* >( m_PetOwner )->SetPet(NULL);
	static_cast< Player* >( m_PetOwner )->SetPetName("");
	
	//FIXME:Check hunter pet or not
	//FIXME:Check enslaved MONSTER
	m_PetOwner->SetUInt64Value(UNIT_FIELD_SUMMON, 0);
	
	WorldPacket data;
	data.Initialize(SMSG_PET_SKILLS);
	data << (uint64)0;
	static_cast< Player* >( m_PetOwner )->GetSession()->SendPacket(&data);
	
	sEventMgr.RemoveEvents(((MONSTER*)m_Unit));
	if(m_Unit->IsInWorld())
	{
		m_Unit->RemoveFromWorld();
	}
	//setup an event to delete the MONSTER
	sEventMgr.AddEvent(((MONSTER*)this->m_Unit), &MONSTER::DeleteMe, EVENT_DELETE_TIMER, 1, 1);*/
}

void AIInterface::AttackReaction(Unit* pUnit, uint32 damage_dealt, uint32 spellId)
{
	if( m_AIState == STATE_EVADE || m_fleeTimer != 0 || !pUnit || !pUnit->isAlive() || m_Unit->IsPacified() || m_Unit->IsFeared() || m_Unit->IsStunned() || !m_Unit->isAlive() )
	{
		return;
	}

	if( m_Unit == pUnit )
	{
		return;
	}

	if( m_AIState == STATE_IDLE || m_AIState == STATE_FOLLOWING )
	{
		WipeTargetList();
		
		HandleEvent(EVENT_ENTERCOMBAT, pUnit, 0);
	}

	HandleEvent(EVENT_DAMAGETAKEN, pUnit, _CalcThreat(damage_dealt, spellId ? dbcSpell.LookupEntryForced(spellId) : NULL, pUnit));
}

bool AIInterface::HealReaction(Unit* caster, Unit* victim, uint32 amount)
{
	if(!caster || !victim)
	{
		printf("!!!BAD POINTER IN AIInterface::HealReaction!!!\n");
		return false;
	}

	int casterInList = 0, victimInList = 0;

	if(m_aiTargets.find(caster) != m_aiTargets.end())
		casterInList = 1;

	if(m_aiTargets.find(victim) != m_aiTargets.end())
		victimInList = 1;

	/*for(i = m_aiTargets.begin(); i != m_aiTargets.end(); i++)
	{
		if(casterInList && victimInList)
		{ // no need to check the rest, just break that
			break;
		}
		if(i->target == victim)
		{
			victimInList = true;
		}
		if(i->target == caster)
		{
			casterInList = true;
		}
	}*/
	if(!victimInList && !casterInList) // none of the Casters is in the MONSTERs Threat list
	{
		return false;
	}
	if(!casterInList && victimInList) // caster is not yet in Combat but victim is
	{
		// get caster into combat if he's hostile
		if(isHostile(m_Unit, caster))
		{
			//AI_Target trgt;
			//trgt.target = caster;
			//trgt.threat = amount;
			//m_aiTargets.push_back(trgt);
			m_aiTargets.insert(TargetMap::value_type(caster, amount));
			return true;
		}
		return false;
	}
	else if(casterInList && victimInList) // both are in combat already
	{
		// mod threat for caster
		modThreatByPtr(caster, amount);
		return true;
	}
	else // caster is in Combat already but victim is not
	{
		modThreatByPtr(caster, amount);
		// both are players so they might be in the same group
		if( caster->GetTypeId() == TYPEID_PLAYER && victim->GetTypeId() == TYPEID_PLAYER )
		{
			if( static_cast< Player* >( caster )->GetGroup() == static_cast< Player* >( victim )->GetGroup() )
			{
				// get victim into combat since they are both
				// in the same party
				if( isHostile( m_Unit, victim ) )
				{
					m_aiTargets.insert( TargetMap::value_type( victim, 1 ) );
					return true;
				}
				return false;
			}
		}
	}

	return false;
}

void AIInterface::OnDeath(Object* pKiller)
{
	if(pKiller->GetTypeId() == TYPEID_PLAYER || pKiller->GetTypeId() == TYPEID_UNIT)
		HandleEvent(EVENT_UNITDIED, static_cast<Unit*>(pKiller), 0);
	else
		HandleEvent(EVENT_UNITDIED, m_Unit, 0);
}

Unit* AIInterface::FindTarget()
{// find nearest hostile Target to attack
	if( !m_AllowedToEnterCombat ) 
		return NULL;

	Unit* target = NULL;
	Unit* critterTarget = NULL;
	float distance = 999999.0f; // that should do it.. :p
	float crange;
	float z_diff;
#ifdef LOS_CHECKS
#ifdef LOS_ONLY_IN_INSTANCE
	bool los = true;
	bool check_los = true;
	if( m_Unit->GetMapMgr()->GetMapInfo()->type == INSTANCE_NULL )
		check_los = false;
#endif
#endif

	std::set<Object*>::iterator itr, it2;
	Object *pObj;
	Unit *pUnit;
	float dist;
	bool pvp=true;
	if(m_Unit->GetTypeId()==TYPEID_UNIT&&((MONSTER*)m_Unit)->GetMONSTERName()&&((MONSTER*)m_Unit)->GetMONSTERName()->Civilian)
		pvp=false;

	//target is immune to all form of attacks, cant attack either.
	if(m_Unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
	{
		return 0;
	}

	for( itr = m_Unit->GetInRangeOppFactsSetBegin(); itr != m_Unit->GetInRangeOppFactsSetEnd(); )
	{
		it2 = itr;
		++itr;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -