//-----------------------------------------------------------------------------
// Purpose: For create nodes in wc edit mode
// Input  :
// Output :
//-----------------------------------------------------------------------------
void NWCEdit::CreateAINode( CBasePlayer *pPlayer )
{
	// -------------------------------------------------------------
	//  Check that WC is running with the right map version
	// -------------------------------------------------------------
	if ( !IsWCVersionValid() || !pPlayer )
		return;

	pPlayer->AddSolidFlags( FSOLID_NOT_SOLID );
	UTIL_Relink(pPlayer);

	int hullType = g_pAINetworkManager->GetEditOps()->m_iHullDrawNum;

	// -----------------------------------
	//  Get position of node to create
	// -----------------------------------
	Vector vNewNodePos = vec3_origin;
	bool bPositionValid = false;
	if (g_pAINetworkManager->GetEditOps()->m_bAirEditMode)
	{
		vNewNodePos = NWCEdit::AirNodePlacementPosition();

		// Make sure we can see the node
		trace_t tr;
		UTIL_TraceLine(pPlayer->EyePosition(), vNewNodePos, MASK_NPCSOLID_BRUSHONLY, pPlayer, COLLISION_GROUP_NONE, &tr);
		if (tr.fraction == 1.0)
		{
			bPositionValid = true;
		}
	}
	else
	{
		// Place node by where the player is looking
		Vector forward;
		pPlayer->EyeVectors( &forward );
		Vector	startTrace	= pPlayer->EyePosition();
		Vector	endTrace	= pPlayer->EyePosition() + forward * MAX_TRACE_LENGTH;
		trace_t	tr;
		UTIL_TraceLine(startTrace,endTrace,MASK_NPCSOLID, pPlayer, COLLISION_GROUP_NONE, &tr );
		if ( tr.fraction != 1.0)
		{
			// Raise the end position up off the floor, place the node and drop him down
			tr.endpos.z += 48;
			vNewNodePos = tr.endpos;
			bPositionValid = true;
		}
	}

	// -------------------------------------------------------------------------------
	// Now check that this is a valid location for the new node bu using test hull
	// -------------------------------------------------------------------------------
	if (bPositionValid)
	{
		CBaseEntity *testHull = (CBaseEntity*)CAI_TestHull::GetTestHull();

		// Set the size of the test hull
		UTIL_SetSize(testHull, NAI_Hull::Mins(hullType), NAI_Hull::Maxs(hullType));

		// Set origin of test hull
		testHull->SetLocalOrigin( vNewNodePos );

		// -----------------------------------------------------------------------
		// If a ground node, drop to floor and make sure can stand at test postion
		// -----------------------------------------------------------------------
		if (!g_pAINetworkManager->GetEditOps()->m_bAirEditMode)
		{
			UTIL_DropToFloor( testHull, MASK_NPCSOLID );
			vNewNodePos = testHull->GetAbsOrigin();
			CTraceFilterSimple traceFilter( testHull, COLLISION_GROUP_NONE );
			if (!UTIL_CheckBottom(testHull, &traceFilter, sv_stepsize.GetFloat()))
			{
				CAI_TestHull::ReturnTestHull();
				bPositionValid = false;
				goto DoneCreate;
			}
		}

		// -----------------------------------------------------------------------
		// Make sure hull fits at location by seeing if it can move up a fraction
		// -----------------------------------------------------------------------
		Vector vUpBit = testHull->GetAbsOrigin();
		vUpBit.z += 1;
		trace_t tr;
		UTIL_TraceHull( testHull->GetAbsOrigin(), vUpBit, NAI_Hull::Mins(hullType), 
			NAI_Hull::Maxs(hullType), MASK_NPCSOLID, testHull, COLLISION_GROUP_NONE, &tr );
		if (tr.startsolid || tr.fraction != 1.0)
		{
			CAI_TestHull::ReturnTestHull();
			bPositionValid = false;
			goto DoneCreate;
		}

		// <<TEMP>> Round position till DS fixed WC bug
		testHull->SetLocalOrigin( Vector( floor(testHull->GetAbsOrigin().x),
			floor(testHull->GetAbsOrigin().y ), floor(testHull->GetAbsOrigin().z) ) );

		// ---------------------------------------
		//  Send new node to WC
		// ---------------------------------------
		int status;
		if (g_pAINetworkManager->GetEditOps()->m_bAirEditMode)
		{
			status = Editor_CreateNode("info_node_air", g_pAINetworkManager->GetEditOps()->m_nNextWCIndex, testHull->GetLocalOrigin().x, testHull->GetLocalOrigin().y, testHull->GetLocalOrigin().z, false);
		}
		else
		{
			// Create slightly higher in WC so it can be dropped when its loaded again
			Vector origin = testHull->GetLocalOrigin();
			origin.z += 24.0;
			testHull->SetLocalOrigin( origin );
			status = Editor_CreateNode("info_node", g_pAINetworkManager->GetEditOps()->m_nNextWCIndex, testHull->GetLocalOrigin().x, testHull->GetLocalOrigin().y, testHull->GetLocalOrigin().z, false);
		}
		if (status == Editor_BadCommand)
		{
			Msg( "Worldcraft failed on creation...\n" );
			CAI_TestHull::ReturnTestHull();
		}
		else if (status == Editor_OK)
		{
			// -----------------------
			// Create a new ai node
			// -----------------------
			CNodeEnt *pNodeEnt;
			if (g_pAINetworkManager->GetEditOps()->m_bAirEditMode)
			{
				pNodeEnt = (CNodeEnt*)CreateEntityByName("info_node_air");
			}
			else
			{
				pNodeEnt = (CNodeEnt*)CreateEntityByName("info_node");
			}

			// Note this is a new entity being created as part of wc editing
			pNodeEnt->SetLocalOrigin( testHull->GetLocalOrigin() );
			CAI_TestHull::ReturnTestHull();

			pNodeEnt->m_nWCNodeID =	g_pAINetworkManager->GetEditOps()->m_nNextWCIndex;

			pNodeEnt->m_debugOverlays |= OVERLAY_WC_CHANGE_ENTITY;
			pNodeEnt->Spawn();
		}	
	}

DoneCreate:
	// ----------------------------------------------------------
	// Flash a red box as a warning that the hull won't fit here
	// ----------------------------------------------------------
	if (!bPositionValid)
	{
		NDebugOverlay::Box(vNewNodePos, NAI_Hull::Mins(hullType), NAI_Hull::Maxs(hullType), 255,0,0,0,0.1);
	}

	// Restore player collidability
	pPlayer->SetSolid( SOLID_BBOX );
	UTIL_Relink(pPlayer);
}
//-----------------------------------------------------------------------------
// Purpose: Creates the NPC.
//-----------------------------------------------------------------------------
void CNPCMaker::MakeNPC( void )
{
	if (!CanMakeNPC())
		return;

	CAI_BaseNPC	*pent = (CAI_BaseNPC*)CreateEntityByName( STRING(m_iszNPCClassname) );

	if ( !pent )
	{
		Warning("NULL Ent in NPCMaker!\n" );
		return;
	}
	
	// ------------------------------------------------
	//  Intialize spawned NPC's relationships
	// ------------------------------------------------
	pent->SetRelationshipString( m_RelationshipString );

	m_OnSpawnNPC.Set( pent, pent, this );

	pent->SetAbsOrigin( GetAbsOrigin() );

	// Strip pitch and roll from the spawner's angles. Pass only yaw to the spawned NPC.
	QAngle angles = GetAbsAngles();
	angles.x = 0.0;
	angles.z = 0.0;
	pent->SetAbsAngles( angles );

	pent->AddSpawnFlags( SF_NPC_FALL_TO_GROUND );

	if ( m_spawnflags & SF_NPCMAKER_FADE )
	{
		pent->AddSpawnFlags( SF_NPC_FADE_CORPSE );
	}

	pent->m_spawnEquipment	= m_spawnEquipment;
	pent->SetSquadName( m_SquadName );
	pent->SetHintGroup( m_strHintGroup );

	ChildPreSpawn( pent );

	DispatchSpawn( pent );
	pent->SetOwnerEntity( this );
	DispatchActivate( pent );

	if ( m_ChildTargetName != NULL_STRING )
	{
		// if I have a netname (overloaded), give the child NPC that name as a targetname
		pent->SetName( m_ChildTargetName );
	}

	ChildPostSpawn( pent );

	m_nLiveChildren++;// count this NPC

	if (!(m_spawnflags & SF_NPCMAKER_INF_CHILD))
	{
		m_nMaxNumNPCs--;

		if ( IsDepleted() )
		{
			m_OnAllSpawned.FireOutput( this, this );

			// Disable this forever.  Don't kill it because it still gets death notices
			SetThink( NULL );
			SetUse( NULL );
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input  : pTarget - 
//-----------------------------------------------------------------------------
CEntityDissolve *CEntityDissolve::Create( CBaseEntity *pTarget, const char *pMaterialName, 
	float flStartTime, int nDissolveType, bool *pRagdollCreated )
{
	if ( pRagdollCreated )
	{
		*pRagdollCreated = false;
	}

	if ( !pMaterialName )
	{
		pMaterialName = DISSOLVE_SPRITE_NAME;
	}

	if ( pTarget->IsPlayer() )
	{
		// Simply immediately kill the player.
		CBasePlayer *pPlayer = assert_cast< CBasePlayer* >( pTarget );
		pPlayer->SetArmorValue( 0 );
		CTakeDamageInfo info( pPlayer, pPlayer, pPlayer->GetHealth(), DMG_GENERIC | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE );
		pPlayer->TakeDamage( info );
		return NULL;
	}

	CEntityDissolve *pDissolve = (CEntityDissolve *) CreateEntityByName( "env_entity_dissolver" );

	if ( pDissolve == NULL )
		return NULL;

	pDissolve->m_nDissolveType = nDissolveType;
	if ( (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
	{
		if ( pTarget->IsNPC() && pTarget->MyNPCPointer()->CanBecomeRagdoll() )
		{
			CTakeDamageInfo info;
			CBaseEntity *pRagdoll = CreateServerRagdoll( pTarget->MyNPCPointer(), 0, info, COLLISION_GROUP_DEBRIS, true );
			pRagdoll->SetCollisionBounds( pTarget->CollisionProp()->OBBMins(), pTarget->CollisionProp()->OBBMaxs() );

			// Necessary to cause it to do the appropriate death cleanup
			if ( pTarget->m_lifeState == LIFE_ALIVE )
			{
				CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
				CTakeDamageInfo ragdollInfo( pPlayer, pPlayer, 10000.0, DMG_SHOCK | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE );
				pTarget->TakeDamage( ragdollInfo );
			}

			if ( pRagdollCreated )
			{
				*pRagdollCreated = true;
			}

			UTIL_Remove( pTarget );
			pTarget = pRagdoll;
		}
	}

	pDissolve->SetModelName( AllocPooledString(pMaterialName) );
	pDissolve->AttachToEntity( pTarget );
	pDissolve->SetStartTime( flStartTime );
	pDissolve->Spawn();

	// Send to the client even though we don't have a model
	pDissolve->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );

	// Play any appropriate noises when we start to dissolve
	if ( (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
	{
		pTarget->DispatchResponse( "TLK_ELECTROCUTESCREAM" );
	}
	else
	{
		pTarget->DispatchResponse( "TLK_DISSOLVESCREAM" );
	}
	return pDissolve;
}
//-----------------------------------------------------------------------------
// Purpose: Creates the NPC.
//-----------------------------------------------------------------------------
void CNPCMakerXenInvasion::MakeNPC(void)
{
	if (!CanMakeNPC())
		return;
	
	if (g_pGameRules->bHasRandomized)
	{
		if (g_pGameRules->iRandomGamemode == FIREFIGHT_PRIMARY_XENINVASION)
		{
			int nNPCs = ARRAYSIZE(g_charNPCSXenInvasionSupport);
			int randomChoice = rand() % nNPCs;
			const char *pRandomName = g_charNPCSXenInvasionSupport[randomChoice];

			CAI_BaseNPC	*pent = (CAI_BaseNPC*)CreateEntityByName(pRandomName);

			if (!pent)
			{
				Warning("npc_maker_firefight: Entity classname does not exist in database.\n");
				return;
			}

			// ------------------------------------------------
			//  Intialize spawned NPC's relationships
			// ------------------------------------------------
			pent->SetRelationshipString(m_RelationshipString);

			m_OnSpawnNPC.Set(pent, pent, this);

			pent->SetAbsOrigin(GetAbsOrigin());

			// Strip pitch and roll from the spawner's angles. Pass only yaw to the spawned NPC.
			QAngle angles = GetAbsAngles();
			angles.x = 0.0;
			angles.z = 0.0;
			pent->SetAbsAngles(angles);

			pent->AddSpawnFlags(SF_NPC_FALL_TO_GROUND);

			if (m_spawnflags & SF_NPCMAKER_FADE)
			{
				pent->AddSpawnFlags(SF_NPC_FADE_CORPSE);
			}

			pent->m_isRareEntity = false;
			pent->SetSquadName(m_SquadName);
			pent->SetHintGroup(m_strHintGroup);

			ChildPreSpawn(pent);

			DispatchSpawn(pent);
			pent->SetOwnerEntity(this);
			DispatchActivate(pent);

			if (m_ChildTargetName != NULL_STRING)
			{
				// if I have a netname (overloaded), give the child NPC that name as a targetname
				pent->SetName(m_ChildTargetName);
			}

			ChildPostSpawn(pent);
		}
		else
		{
			CAI_BaseNPC	*pent = (CAI_BaseNPC*)CreateEntityByName(STRING(m_iszNPCClassname));

			if (!pent)
			{
				Warning("npc_maker_firefight: Entity classname does not exist in database.\n");
				return;
			}

			// ------------------------------------------------
			//  Intialize spawned NPC's relationships
			// ------------------------------------------------
			pent->SetRelationshipString(m_RelationshipString);

			m_OnSpawnNPC.Set(pent, pent, this);

			pent->SetAbsOrigin(GetAbsOrigin());

			// Strip pitch and roll from the spawner's angles. Pass only yaw to the spawned NPC.
			QAngle angles = GetAbsAngles();
			angles.x = 0.0;
			angles.z = 0.0;
			pent->SetAbsAngles(angles);

			pent->AddSpawnFlags(SF_NPC_FALL_TO_GROUND);

			if (m_spawnflags & SF_NPCMAKER_FADE)
			{
				pent->AddSpawnFlags(SF_NPC_FADE_CORPSE);
			}

			pent->m_spawnEquipment = m_spawnEquipment;
			pent->m_isRareEntity = false;
			pent->SetSquadName(m_SquadName);
			pent->SetHintGroup(m_strHintGroup);

			ChildPreSpawn(pent);

			DispatchSpawn(pent);
			pent->SetOwnerEntity(this);
			DispatchActivate(pent);

			if (m_ChildTargetName != NULL_STRING)
			{
				// if I have a netname (overloaded), give the child NPC that name as a targetname
				pent->SetName(m_ChildTargetName);
			}

			ChildPostSpawn(pent);
		}
	}
	else
	{
		if (g_pGameRules->GetGamemode() == FIREFIGHT_PRIMARY_XENINVASION)
		{
			int nNPCs = ARRAYSIZE(g_charNPCSXenInvasionSupport);
			int randomChoice = rand() % nNPCs;
			const char *pRandomName = g_charNPCSXenInvasionSupport[randomChoice];

			CAI_BaseNPC	*pent = (CAI_BaseNPC*)CreateEntityByName(pRandomName);

			if (!pent)
			{
				Warning("npc_maker_firefight: Entity classname does not exist in database.\n");
				return;
			}

			// ------------------------------------------------
			//  Intialize spawned NPC's relationships
			// ------------------------------------------------
			pent->SetRelationshipString(m_RelationshipString);

			m_OnSpawnNPC.Set(pent, pent, this);

			pent->SetAbsOrigin(GetAbsOrigin());

			// Strip pitch and roll from the spawner's angles. Pass only yaw to the spawned NPC.
			QAngle angles = GetAbsAngles();
			angles.x = 0.0;
			angles.z = 0.0;
			pent->SetAbsAngles(angles);

			pent->AddSpawnFlags(SF_NPC_FALL_TO_GROUND);

			if (m_spawnflags & SF_NPCMAKER_FADE)
			{
				pent->AddSpawnFlags(SF_NPC_FADE_CORPSE);
			}

			pent->m_isRareEntity = false;
			pent->SetSquadName(m_SquadName);
			pent->SetHintGroup(m_strHintGroup);

			ChildPreSpawn(pent);

			DispatchSpawn(pent);
			pent->SetOwnerEntity(this);
			DispatchActivate(pent);

			if (m_ChildTargetName != NULL_STRING)
			{
				// if I have a netname (overloaded), give the child NPC that name as a targetname
				pent->SetName(m_ChildTargetName);
			}

			ChildPostSpawn(pent);
		}
		else
		{
			CAI_BaseNPC	*pent = (CAI_BaseNPC*)CreateEntityByName(STRING(m_iszNPCClassname));

			if (!pent)
			{
				Warning("npc_maker_firefight: Entity classname does not exist in database.\n");
				return;
			}

			// ------------------------------------------------
			//  Intialize spawned NPC's relationships
			// ------------------------------------------------
			pent->SetRelationshipString(m_RelationshipString);

			m_OnSpawnNPC.Set(pent, pent, this);

			pent->SetAbsOrigin(GetAbsOrigin());

			// Strip pitch and roll from the spawner's angles. Pass only yaw to the spawned NPC.
			QAngle angles = GetAbsAngles();
			angles.x = 0.0;
			angles.z = 0.0;
			pent->SetAbsAngles(angles);

			pent->AddSpawnFlags(SF_NPC_FALL_TO_GROUND);

			if (m_spawnflags & SF_NPCMAKER_FADE)
			{
				pent->AddSpawnFlags(SF_NPC_FADE_CORPSE);
			}

			pent->m_spawnEquipment = m_spawnEquipment;
			pent->m_isRareEntity = false;
			pent->SetSquadName(m_SquadName);
			pent->SetHintGroup(m_strHintGroup);

			ChildPreSpawn(pent);

			DispatchSpawn(pent);
			pent->SetOwnerEntity(this);
			DispatchActivate(pent);

			if (m_ChildTargetName != NULL_STRING)
			{
				// if I have a netname (overloaded), give the child NPC that name as a targetname
				pent->SetName(m_ChildTargetName);
			}

			ChildPostSpawn(pent);
		}
	}

	m_nLiveChildren++;// count this NPC
}
//-----------------------------------------------------------------------------
// Create a corpse 
//-----------------------------------------------------------------------------
void CPropAPC2::CreateCorpse( )
{
	m_lifeState = LIFE_DEAD;

	for ( int i = 0; i < APC_MAX_GIBS; ++i )
	{
		CPhysicsProp *pGib = assert_cast<CPhysicsProp*>(CreateEntityByName( "prop_physics_multiplayer" ));
		pGib->SetAbsOrigin( GetAbsOrigin() );
		pGib->SetAbsAngles( GetAbsAngles() );
		pGib->SetAbsVelocity( GetAbsVelocity() );
		pGib->SetModel( s_pGibModelName[i] );
		pGib->Spawn();
		pGib->SetMoveType( MOVETYPE_VPHYSICS );

		float flMass = pGib->GetMass();
		/*if ( flMass < 200 )
		{*/
			Vector vecVelocity;
			pGib->GetMassCenter( &vecVelocity );
			vecVelocity -= WorldSpaceCenter();
			vecVelocity.z = fabs(vecVelocity.z);
			VectorNormalize( vecVelocity );

			// Apply a force that would make a 100kg mass travel 150 - 300 m/s
			float flRandomVel = random->RandomFloat( 150, 300 );
			vecVelocity *= (100 * flRandomVel) / flMass;
			vecVelocity.z += 100.0f;
			AngularImpulse angImpulse = RandomAngularImpulse( -500, 500 );
			
			IPhysicsObject *pObj = pGib->VPhysicsGetObject();
			if ( pObj != NULL )
			{
				pObj->AddVelocity( &vecVelocity, &angImpulse );
			}
			pGib->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
		/*}*/
		//pGib->Ignite( 60, false );
		pGib->Dissolve( NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL );
	}

//

	CPropAPC2 *pAPC = (CPropAPC2 *)CreateEntityByName( "prop_vehicle_apc2" );
		
	if ( pAPC )
	{
		pAPC->InicialSpawn=m_vOriginalSpawnOrigin;
		pAPC->InicialAngle=m_vOriginalSpawnAngles;
		pAPC->m_bSpawn=true;
		pAPC->SetThink( &CPropAPC2::Materialize );
		pAPC->SetContextThink( &CPropAPC2::Materialize, gpGlobals->curtime + 5.0f, "RESPAWNING" );
		pAPC->SetNextThink( gpGlobals->curtime + 5.0f );
	}
	else
	{
		Warning("Respawn failed to create %s!\n", GetClassname() );
	}

//

	AddSolidFlags( FSOLID_NOT_SOLID );
	AddEffects( EF_NODRAW );
	UTIL_Remove( this );
}