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

📄 playerobj.cpp

📁 Blood 2全套源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
		pServerDE->GetObjectPos(m_hObject, &pos);
		pos.y += 50.0;
		pServerDE->MoveObject(m_hObject, &pos);
	}

	// This is a KLUDGE to fix problem with sinking through
	// the ground when switching to spectator mode.  We'll
	// process a frame before we actually switch...
	if (m_bSpectatorMode)
	{
		DDWORD dwFlags = pServerDE->GetObjectFlags(m_hObject);
		DVector dims;

		VEC_INIT(dims)

		HSTRING hstr = pServerDE->FormatString(IDS_GENERAL_SPECTATORON);
		SendConsoleMessage(pServerDE->GetStringData(hstr));
		pServerDE->FreeString(hstr);

//		dwFlags &= ~(FLAG_SHADOW | FLAG_TOUCH_NOTIFY | FLAG_SOLID);
		dwFlags &= ~(FLAG_TOUCH_NOTIFY | FLAG_SOLID);
		dwFlags |= FLAG_GOTHRUWORLD;

		pServerDE->SetObjectFlags(m_hObject, dwFlags);
//		pServerDE->SetObjectDims(m_hObject, &dims);
//		pServerDE->SetVelocity(m_hObject, &dims);
//		pServerDE->SetAcceleration(m_hObject, &dims);
	}
	else
	{
		DDWORD dwFlags = pServerDE->GetObjectFlags(m_hObject);
		dwFlags &= ~FLAG_GOTHRUWORLD;
		dwFlags |= FLAG_TOUCH_NOTIFY | FLAG_SOLID;
//		dwFlags |= FLAG_SHADOW | FLAG_TOUCH_NOTIFY | FLAG_SOLID;
//		DVector dims = {12.0, gCharacterValues[m_nCharacter].fHeightStanding/2, 12.0};

		HSTRING hstr = pServerDE->FormatString(IDS_GENERAL_SPECTATOROFF);
		SendConsoleMessage(pServerDE->GetStringData(hstr));
		pServerDE->FreeString(hstr);

		pServerDE->SetObjectFlags(m_hObject, dwFlags);
	}
}


// --------------------------------------------------------------------------- //
//
//	ROUTINE:	CPlayerObj::Respawn()
//
//	PURPOSE:	Resets player attributes
//
// --------------------------------------------------------------------------- //
void CPlayerObj::Respawn()
{
	// Get our server pointer...
	CServerDE* pServerDE = GetServerDE();

	// If we're currently dead in our humiliation any, gib...
	if (pServerDE->GetModelAnimation(m_hObject) == m_Anim_Sound.m_nAnim_HUMILIATION[3])
	{
		if (m_bDead)
		{
			int    nType   = m_damage.GetLastDamageType();
			DFLOAT fDamage = m_damage.GetLastDamageAmount();

			DVector vDir;
			m_damage.GetLastDamageDirection(&vDir);

			CreateGibs(vDir, ((int)m_damage.GetMass())>>5, nType, fDamage);
		}
	}

	// Check for spectator mode...
	if (m_bSpectatorMode)
		ToggleSpectatorMode();

	// Respawn as necessary...
	if (!m_damage.IsDead() || g_pBloodServerShell->GetGameType() != GAMETYPE_SINGLE)
	{
		// Set up the filenames
		SetCharacter(m_nCharacter);

		// Reset any hidden nodes
		AIShared.ResetNodes(m_hObject);

		// Set flags
		DDWORD  dwFlags = FLAG_VISIBLE | FLAG_MODELKEYS | FLAG_YROTATION | FLAG_ANIMTRANSITION | FLAG_TOUCH_NOTIFY | FLAG_SOLID | FLAG_STAIRSTEP | FLAG_SHADOW;
//		DDWORD  dwFlags = FLAG_SOLID | FLAG_VISIBLE | FLAG_TOUCH_NOTIFY |  FLAG_STAIRSTEP | FLAG_SHADOW | FLAG_KEEPALIVE | FLAG_FULLPOSITIONRES | FLAG_FORCECLIENTUPDATE | FLAG_MODELKEYS | FLAG_YROTATION | FLAG_ANIMTRANSITION | FLAG_GRAVITY;
		pServerDE->SetObjectFlags(m_hObject, dwFlags);

		DVector dims;
		VEC_INIT(dims)
		pServerDE->SetVelocity(m_hObject, &dims);
//		m_fEyeLevel = gCharacterValues[m_nCharacter].fEyeLevelStanding;
//		SendMessageToClient(SMSG_EYELEVEL);

//		m_damage.Reset();
		m_damage.SetHitPoints(100);
		m_damage.SetArmorPoints(0);
		m_bDead = DFALSE;
		m_fAirLevel	= MAX_AIR_LEVEL;

		m_fDeathTimer         = 0;
		m_fSlowDeathSafeTimer = 0;
		m_fSlowDeathStayTimer = 0;
		m_bInSlowDeath        = DFALSE;

		m_bBurning = DFALSE;

		if (g_pBloodServerShell->IsMultiplayerGame())
		{
			DFLOAT fDeltaTime = g_pServerDE->GetTime() - s_fCreatedTime;

			if (fDeltaTime > 5.0f && IsRandomChance(65))
			{
				PlayVoiceGroupEventOnClient(VME_SPAWN);
			}

			SetMultiplayerAmmo();			
		}
		else
		{
			for (int i = AMMO_BULLET; i <= AMMO_MAXAMMOTYPES; i++)
				m_InventoryMgr.SetAmmoCount(i, 0.0f);

			m_InventoryMgr.SetAmmoCount(AMMO_BULLET, DEFAULT_BULLETS);
		}
	}

	// Dump the bomb list.
	if( m_pBombList )
	{
		ObjectLink* pLink = m_pBombList->m_pFirstLink;
		while( pLink )
		{
			g_pServerDE->RemoveObject( pLink->m_hObject );
			pLink = pLink->m_pNext;
		}

		pServerDE->RelinquishList( m_pBombList );
		m_pBombList = DNULL;
	}

	UpdateClientPhysics(); // (to make sure they have their model around)
	TeleportClientToServerPos();
}


// --------------------------------------------------------------------------- //
//
//	ROUTINE:	CPlayerObj::GoToStartPoint()
//
//	PURPOSE:	Teleports the player to a startpoint.
//
// --------------------------------------------------------------------------- //
void CPlayerObj::GoToStartPoint()
{
	CServerDE* pServerDE = GetServerDE();
	if (!pServerDE || !g_pBloodServerShell)
		return;

	DVector pos;

	VEC_INIT(pos)

	// Get all the Blood 2 start points...

	ObjectList*	pList = pServerDE->FindNamedObjects("Blood2StartPoint");
	if (!pList || !pList->m_pFirstLink || pList->m_nInList <= 0) 
	{
		return;
	}

	GameStartPoint* pGSP = DNULL;
	ObjectLink* pLink = pList->m_pFirstLink;

	// For a multiplayer game, just get a random startpoint
	if(g_pBloodServerShell->GetGameType() != GAMETYPE_SINGLE)
	{
		int nStartPoint = pServerDE->IntRandom(0, pList->m_nInList - 1);
		for (int i=0; i < nStartPoint; i++)
		{
			pLink = pLink->m_pNext;
		}

		pGSP = (GameStartPoint*)pServerDE->HandleToObject(pLink->m_hObject);

		// For team-based games, find a start point for our team...
		if (g_pBloodServerShell->IsMultiplayerTeamBasedGame())
		{
			int nSafety = pList->m_nInList;

			while (pGSP && pGSP->GetTeamID() != (int)GetTeamID() && pGSP->GetTeamID() != 0)
			{
				pLink = pLink->m_pNext;
				if (!pLink) pLink = pList->m_pFirstLink;

				if (pLink)
				{
					pGSP = (GameStartPoint*)pServerDE->HandleToObject(pLink->m_hObject);
				}
				else
				{
					pGSP = NULL;
				}

				if (--nSafety < 0)
				{
					pGSP = NULL;
				}
			}

			if (!pGSP)
			{
				pLink = pList->m_pFirstLink;
				if (pLink) pGSP = (GameStartPoint*)pServerDE->HandleToObject(pLink->m_hObject);
			}
		}
	}
	else  // Single player, go to a named startpoint, if it exists
	{
		DBOOL bRemoveString = DFALSE;
		GameStartPoint *pGSPSingle = DNULL;
		HSTRING hstrStartPoint = g_pBloodServerShell->GetStartPointName();

		if (!hstrStartPoint) 
		{
			bRemoveString = DTRUE;
			hstrStartPoint = pServerDE->CreateString("start");
		}

		pGSP = DNULL;
		for (int i=0; i < pList->m_nInList; i++)
		{
			pGSP = (GameStartPoint*)pServerDE->HandleToObject(pLink->m_hObject);

			if (!pGSP->IsMultiplayer())
			{
				// save it just in case
				pGSPSingle = pGSP;

				if (pServerDE->CompareStringsUpper(hstrStartPoint, pGSP->GetName()))
				{
					break;
				}
			}
			pLink = pLink->m_pNext;
			pGSP = DNULL;
		}
		
		if( bRemoveString )
			pServerDE->FreeString( hstrStartPoint );

		// Couldn't find a named startpoint, try to use any single player
		if (!pGSP && pGSPSingle) pGSP = pGSPSingle;
	}

	DRotation rRot;
	ROT_INIT(rRot);
	if (pGSP)
	{
		// Set the rotation..
		m_fYaw = pGSP->GetPitchYawRoll().y;
		m_fPitch = 0.0f;
		HOBJECT hGSP = pServerDE->ObjectToHandle((LPBASECLASS)pGSP);
		pServerDE->GetObjectPos(hGSP, &pos);

		// Send any trigger message this is supposed to cause
		pGSP->SendTrigger();
	}

	pServerDE->TeleportObject(m_hObject, &pos);
	SendMessageToClient(SMSG_FORCEROTATION);

	MoveObjectToGround(m_hObject);
	
	pServerDE->RelinquishList(pList);

	UpdateClientPhysics(); // (to make sure they have their model around)
	TeleportClientToServerPos();
}


// --------------------------------------------------------------------------- //
//
//	ROUTINE:	CPlayerObj::ValidateAttributes()
//
//	PURPOSE:	Make sure that the player's attributes are within valid ranges
//
// --------------------------------------------------------------------------- //
void CPlayerObj::ValidateAttributes()
{
	CServerDE* pServerDE = GetServerDE();

	m_nCharacter		= DCLAMP(m_nCharacter, 0, MAX_CHARACTER);
	m_nSkin				= DCLAMP(m_nSkin, MULTIPLAY_SKIN_MIN, MULTIPLAY_SKIN_MAX);
	m_nAttribStrength	= DCLAMP(m_nAttribStrength, 1, 5);
	m_nAttribSpeed		= DCLAMP(m_nAttribSpeed, 1, 5);
	m_nAttribResistance = DCLAMP(m_nAttribResistance, 1, 5);
	m_nAttribMagic		= DCLAMP(m_nAttribMagic, 1, 5);

	if ((m_nAttribStrength + m_nAttribSpeed + m_nAttribResistance + m_nAttribMagic) > MAX_ATTRIBUTES)
	{
		HSTRING hstr = pServerDE->FormatString(IDS_GENERAL_ATTRIBHIGH);
		SendConsoleMessage(pServerDE->GetStringData(hstr));
		pServerDE->FreeString(hstr);

		//  Attribute maximums exceeded
		m_nAttribStrength = DEFAULT_ATTRIBUTE;
		m_nAttribSpeed = DEFAULT_ATTRIBUTE;
		m_nAttribResistance = DEFAULT_ATTRIBUTE;
		m_nAttribMagic = DEFAULT_ATTRIBUTE;
	}

	m_InventoryMgr.SetStrength(m_nAttribStrength + m_nBindingStrength);
	m_InventoryMgr.SetMagic(m_nAttribMagic + m_nBindingMagic);
	m_damage.CalculateResistance(m_nAttribResistance + m_nBindingResistance);

	SetMoveVel(gMoveVel[m_nAttribSpeed-1]);
	SetJumpVel(DEFAULT_JUMPVEL);
	m_PStateChangeFlags = PSTATE_ALL;

	//	m_InventoryMgr.SetFullAmmo();
/*
	if (m_bBindingBlending)
		pServerDE->SetObjectColor(m_hObject, 0.0f, 0.0f, 0.0f, ALPHA_CLOAKED);

	if (m_bBindingConstitution)
	{
		m_damage.SetHitPoints(150);
		m_damage.SetMaxHitPoints(150);
	}

	if (m_bBindingIncreasedDamage)
	{
		m_InventoryMgr.AddDamageMultiplier(BINDING_INCREASE_DAMAGE_AMT);
	}
	
	if (m_bBindingQuickness)
	{
		m_InventoryMgr.AddFireRateMultiplier(BINDING_QUICKNESS_FACTOR);
	}
*/
	// Set attributes
	m_damage.SetMaxHitPoints(g_fMaxHealth[m_nAttribStrength-1]);
	m_damage.SetMaxMegaHitPoints(g_fMaxMegaHealth[m_nAttribStrength-1]);
	m_damage.SetMaxArmorPoints(g_fMaxArmor[m_nAttribMagic-1]);
	m_damage.SetMaxNecroArmorPoints(g_fMaxMegaArmor[m_nAttribMagic-1]);
}


// --------------------------------------------------------------------------- //
//
//	ROUTINE:	CPlayerObj::SetCharacter
//
//	PURPOSE:	Sets filenames to refer to the current character.
//
// --------------------------------------------------------------------------- //

void CPlayerObj::SetCharacter(DBYTE nCharacter)
{
	CServerDE* pServerDE = GetServerDE();

	if (nCharacter > MAX_CHARACTER) return;
	
	m_nCharacter = nCharacter;

	pServerDE->SetModelFilenames(m_hObject, 
								 gCharacterValues[m_nCharacter].szModelName, 
								 gCharacterSkins[m_nCharacter][m_nSkin]);

	m_PStateChangeFlags |= PSTATE_MODELFILENAMES;

	// Init the animations
	m_Anim_Sound.SetAnimationIndexes(m_hObject);
	m_Anim_Sound.GenerateHitSpheres(m_hObject);

	sprintf(msgbuf, "sounds\\chosen\\%s", gCharacterValues[m_nCharacter].szName);
	m_Anim_Sound.SetSoundRoot(msgbuf);
}


// --------------------------------------------------------------------------- //
//
//	ROUTINE:	CPlayerObj::ObjectTouch()
//
//	PURPOSE:	Called when the player is touching another TouchNotify object.
//
// --------------------------------------------------------------------------- //
void CPlayerObj::ObjectTouch(HOBJECT hObj, DFLOAT fData)
{
	CServerDE* pServerDE = GetServerDE();
	DBOOL bDoFallingDamage;


	// Hack to see if we are being pushed by a rotating door. If so, set velocity back
	if( hObj )
	{
		HCLASS hObjClass  = pServerDE->GetObjectClass( hObj );
		HCLASS hDoorClass = pServerDE->GetClass( "RotatingDoor" );
		if ( pServerDE->IsKindOf( hObjClass, hDoorClass ) && !m_bDoorPush )
		{
			RotatingDoor *pRotDoor = (RotatingDoor*)pServerDE->HandleToObject(hObj);
			if( pRotDoor && pRotDoor->GetDoorState() == DOORSTATE_OPENING && pRotDoor->CanPushPlayerBack())
			{
				// Get my vectors
				DRotation rRot;
				DVector vF, vU, vR;
				pServerDE->GetObjectRotation(m_hObject, &rRot);
				pServerDE->GetRotationVectors(&rRot, &vU, &vR, &vF);

				// Set some backwards velocity to the player to try to move him out of the way
				VEC_MULSCALAR(m_vDoorPush, vF, -500.0f);
				m_bDoorPush = DTRUE;
//				pServerDE->SetVelocity(m_hObject, &vF);

				return;
			}
		}
	}

	bDoFallingDamage = DTRUE;
	if( g_pBloodServerShell->IsMultiplayerGame( ))
	{
		if( !g_pBloodServerShell->GetNetGameInfo( )->m_bFallDamage )
			bDoFallingDamage = DFALSE;
	}
/*
	if (fData >= PA_MIN_DAMAGE_FORCE && bDoFallingDamage )
	{
		pServerDE->BPrint("impact force=%f", fData);
		// Damage myself
		DVector vFall, vPos;
		VEC_SET(vFall, 0.0f, -1.0f, 0.0f);
		DFLOAT fDamage;
		
		// Set some minimum guidelines
		if (m_bFalling && (pServerDE->GetTime() - m_startFall) >= 2.0f) 
		{
			fDamage = (fData - PA_MIN_DAMAGE_FORCE) / 25;

			pServerDE->GetObjectPos(m_hObject, &vPos);

			DamageObject(m_hObject, this, m_hObject, fDamage, vFall, vPos, DAMAGE_TYPE_NORMAL);
		}
	}
*/
	DVector vCurVel;
	pServerDE->GetVelocity(m_hObject, &vCurVel);

	if (bDoFallingDamage )
	{
		// Damage myself
		// Set some minimum guidelines
		if ((m_bFalling || m_bServerFalling) && vCurVel.y < -1100.0f) 
		{
			DVector vFall, vPos;
			VEC_SET(vFall, 0.0f, -1.0f, 0.0f);
			DFLOAT fDamage;
			
			fDamage = (fData - PA_MIN_DAMAGE_FORCE) / 25;

			if (fDamage > 0)
			{
				pServerDE->GetObjectPos(m_hObject, &vPos);
				DamageObject(m_hObject, this, m_hObject, fDamage, vFall, vPos, DAMAGE_TYPE_NORMAL);
			}
		}
	}
}



// --------------------------------------------------------------------------- //
//
//	ROUTINE:	CPlayerObj::ObjectCrush()
//
//	PURPOSE:	Called when the player is touching another TouchNotify object.
//
// --------------------------------------------------------------------------- //
void CPlayerObj::ObjectCrush(HOBJECT hObj, DFLOAT fData)
{
	CServerDE* pServerDE = GetServerDE();

	// if we are being crushed by a rotating door, tell it to stop moving.
	if (hObj)
	{
		HCLASS hObjClass  = pServerDE->GetObjectClass( hObj );
		HCLASS hDoorClass = pServerDE->GetClass( "RotatingDoor" );
		if ( pServerDE->IsKindOf( hObjClass, hDoorClass ))
		{
			RotatingDoor *pRotDoor = (RotatingDoor*)pServerDE->HandleToObject(hObj);
			if (pRotDoor->GetDoorState() == DOORSTATE_OPENING)
			{
				// Send the message back to the RotatingDoor
				HMESSAGEWRITE hMessage = pServerDE->StartMessageToObject(this, hObj, MID_DOORBLO

⌨️ 快捷键说明

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