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

📄 game_chars.cpp

📁 这是一个服务端/客户端模式的小型网络游戏
💻 CPP
字号:
#include "Global.h"
#include "Game_Chars.h"
#include "WinMain.h"

///////////////////////////////////////////////////////////
// Overloaded character controller class functions
///////////////////////////////////////////////////////////
cChars::cChars(){
	LastMove = 0;
	
}

BOOL cChars::SetData(cApp *App)
{
	if((m_App = App) == FALSE)
		return FALSE;
	return TRUE;
}

BOOL cChars::PCUpdate(sCharacter *Character, long Elapsed,    \
					  float *XMove, float *YMove, float *ZMove)
{
	
	BOOL AllowMovement;
	long Dir;
	sCharacter *CharPtr;
	float XDiff, YDiff, ZDiff, Dist;
	float Speed;
	long  SpellNum;
	float SpellRadius, SpellRadius2;
	float DirectionXPos, DirectionZPos;
	
	// If not PC, then let controller handle movement
	if(Character->ID != 0)	return TRUE;
	
	
	// Update action timer if in use
	if(m_App->ScripteHandle.EffectCounter != 0) {
		m_App->ScripteHandle.EffectCounter -= Character->Elapsed;
		if(m_App->ScripteHandle.EffectCounter < 0)
			m_App->ScripteHandle.EffectCounter = 0;
		if(m_App->ScripteHandle.EffectCounter != 0)return TRUE;
	}
	
	Speed = (float)Elapsed / 1000.0f * GetSpeed(Character);
	
	
	// Set flag to allow player movement
	AllowMovement = FALSE;
	
	// Don't allow movement if still swinging weapon
	if(Character->Action == CHAR_MOVE || Character->Action == CHAR_IDLE)
		AllowMovement = TRUE;
	
	
	// Handle movements if allowed
	if(AllowMovement == TRUE) {
		
		// Process local player movements
		if((Dir = m_App->MoveAction) > 0 && Dir < 13) {
			// Set new player state (w/time and direction)
			Character->Direction = Angles[Dir] - m_App->m_CamAngle + 4.71f;
			
			// Reset last move if camera moved since last update
			if(m_App->CamMoved == TRUE) {
				m_App->CamMoved = FALSE;
				LastMove = 0;
			}
			
			// Send actions to server if changed from last move
			if(m_App->MoveAction != LastMove || Character->LastAnim ==CHAR_HURT) {
				LastMove = m_App->MoveAction;  // Store last action
				
				// Construct message
				sStateChangeMessage Msg;
				Msg.Header.Type     = MSG_STATE_CHANGE;
				Msg.Header.Size     = sizeof(sStateChangeMessage);
				Msg.Header.PlayerID = Character->dpnidPlayer;
				Msg.Action          = CHAR_MOVE;
				Msg.Direction       = Character->Direction;
				
				// Send message to server
				m_App->SendNetworkMessage(&Msg, DPNSEND_NOLOOPBACK);
			}
			
			// Set new player state (w/time and direction)
			Character->Action     = CHAR_MOVE;
			
			*XMove = (float)sin(Character->Direction) * Speed;
			*ZMove = (float)cos(Character->Direction) * Speed;
			
		} else {
			// Change to idle state
			Character->Action = CHAR_IDLE;
			
			// Send update only if player moved last update
			if(LastMove) {
				LastMove = 0;
				
				sStateChangeMessage Msg;
				Msg.Header.Type     = MSG_STATE_CHANGE;
				Msg.Header.Size     = sizeof(sStateChangeMessage);
				Msg.Header.PlayerID = Character->dpnidPlayer;
				Msg.Action          = CHAR_IDLE;
				
				// Send message to server
				m_App->SendNetworkMessage(&Msg, DPNSEND_NOLOOPBACK);
			}
		}
	}
	if(m_App->m_Status == MSG_ITEMS ){
		// Determine which item is selected with mouse
		if((m_Select = m_App->m_Mouse.GetYPos() - 32) >= 0)
			m_Select /= 32;
	}
	// Attack a nearby monster or process NPC script
	if(m_App->MoveAction & 16) {
		if(m_App->m_Status == MSG_ITEMS ){
			
			
			// Get pointer to item
			if((Character->CharItem = Character->CharICS->GetItem(m_Select)) != NULL){
				Character->ItemNum = Character->CharItem->ItemNum;
				
				if(m_App->m_CharController.SetAction(Character, CHAR_ITEM)){
					sItemChangeMessage icm;
					icm.Header.Type     = MSG_ITEM_CHANGE;
					icm.Header.Size     = sizeof(sItemChangeMessage);
					icm.Header.PlayerID = Character->dpnidPlayer;
					icm.ItemNum			= Character->ItemNum;
					icm.IsAdd			= FALSE;
					icm.TargetDpnid       = Character->dpnidPlayer;
					
					// Send the message over network
					m_App->SendNetworkMessage(&icm, DPNSEND_NOLOOPBACK);
				};
			}
			
		}else{
			
			DirectionXPos = Character->XPos + 100.0f * sin(Character->Direction);
			DirectionZPos = Character->ZPos + 100.0f * cos(Character->Direction);
			CharPtr = GetParentCharacter();
			while(CharPtr != NULL) {
				
				// Only check other characters
				if(CharPtr->ID != Character->ID && CharPtr->Enabled == TRUE && CharPtr->Type != CHAR_PC) {
					XDiff = (float)fabs(CharPtr->XPos - DirectionXPos);
					YDiff = (float)fabs(CharPtr->YPos - Character->YPos);
					ZDiff = (float)fabs(CharPtr->ZPos - DirectionZPos);
					Dist = XDiff*XDiff+YDiff*YDiff+ZDiff*ZDiff;
					
					// Only check characters within 100.0 units distance
					if(Dist <= 10000.0f && \
						m_App->m_NodeTreeMesh.CheckIntersect(Character->XPos, Character->YPos, Character->ZPos,
						CharPtr->XPos, CharPtr->YPos, CharPtr->ZPos,
						&Dist) == FALSE) {
						
						// Process script or attack?
						if(CharPtr->ScriptFilename[0]){
							if(!m_App->ScripteHandle.Renderflag){
								m_App->ScripteHandle.Renderflag = TRUE;
								m_App->ScripteHandle.ScriptCharID = CharPtr->ID;
								m_App->ScripteHandle.EffectCounter = 300;
								m_App->ScripteHandle.last_XPos = Character->XPos;
								m_App->ScripteHandle.last_YPos = Character->YPos;
								m_App->ScripteHandle.last_ZPos = Character->ZPos;
							} else{
								m_App->ScripteHandle.Renderflag = FALSE;
								m_App->ScripteHandle.EffectCounter = 300;
							}
							
						}
						else {
							
							// Set attack data
							Character->Victim = CharPtr;
							CharPtr->Attacker = Character;
							
							// Set attack action
							if(m_App->m_CharController.SetAction(Character, CHAR_ATTACK)){
								sAttackChangeMessage sacm;
								sacm.Header.Type     = MSG_ATTACK_CHANGE;
								sacm.Header.Size     = sizeof(sAttackChangeMessage);
								sacm.Header.PlayerID = Character->dpnidPlayer;
								sacm.VictimDpnid     = CharPtr->dpnidPlayer;
								
								// Send the message over network
								m_App->SendNetworkMessage(&sacm, DPNSEND_NOLOOPBACK);
							}
						}
						
						break;
					}
				}
				
				CharPtr = CharPtr->Next;
			}
			if(CharPtr == NULL){
				// Set attack action
				if(m_App->m_CharController.SetAction(Character, CHAR_ATTACK)){
					sAttackChangeMessage sacm;
					sacm.Header.Type     = MSG_ATTACK_CHANGE;
					sacm.Header.Size     = sizeof(sAttackChangeMessage);
					sacm.Header.PlayerID = Character->dpnidPlayer;
					sacm.VictimDpnid     = NULL;
					
					// Send the message over network
					m_App->SendNetworkMessage(&sacm, DPNSEND_NOLOOPBACK);
				}
			}
		}
	}
	
	
	// Cast spells
	if(m_App->MoveAction & 32 || m_App->MoveAction & 64 || m_App->MoveAction & 128) {
		// Get spell number to cast
		if(m_App->MoveAction & 32)
			SpellNum = 0;
		if(m_App->MoveAction & 64)
			SpellNum = 1;
		if(m_App->MoveAction & 128)
			SpellNum = 2;
		float Dist;
		// Get spell distance
		SpellRadius = m_App->m_SpellController.GetSpell(SpellNum)->Distance;
		SpellRadius2 = SpellRadius / 2.0f;
		
		DirectionXPos = Character->XPos + SpellRadius2 * sin(Character->Direction);
		DirectionZPos = Character->ZPos + SpellRadius2 * cos(Character->Direction);
		
		// Search for closest monster
		CharPtr = GetParentCharacter();
		while(CharPtr != NULL) {
			// Only check other characters
			if(CharPtr->Type == CHAR_MONSTER) {
				XDiff = (float)fabs(CharPtr->XPos - DirectionXPos);
				YDiff = (float)fabs(CharPtr->YPos - Character->YPos);
				ZDiff = (float)fabs(CharPtr->ZPos - DirectionZPos);
				Dist = XDiff*XDiff+YDiff*YDiff+ZDiff*ZDiff;
				
				// Only check characters within 100.0 units distance
				if(Dist <= (SpellRadius2 * SpellRadius2)) {
					Character->SpellNum = SpellNum;
					Character->SpellTarget = CHAR_MONSTER;
					Character->TargetX = CharPtr->XPos;
					Character->TargetY = CharPtr->YPos;
					Character->TargetZ = CharPtr->ZPos;
					
					
					if(m_App->m_NodeTreeMesh.CheckIntersect(Character->XPos, Character->YPos, Character->ZPos,
						CharPtr->XPos, CharPtr->YPos, CharPtr->ZPos,
						&Dist) == TRUE) {
						// Adjust coordinates to be exactly 5.0 units away from target
						Dist -=  5.0f;
						Character->TargetX = Character->XPos + Dist * sin(Character->Direction);
						Character->TargetZ = Character->ZPos + Dist * cos(Character->Direction);
						
					} 
					
					
					if(m_App->m_CharController.SetAction(Character, CHAR_SPELL)){
						
						sSpellChangeMessage spcm;
						spcm.Header.Type     = MSG_SPELL_CHANGE;
						spcm.Header.Size     = sizeof(sSpellChangeMessage);
						spcm.Header.PlayerID = Character->dpnidPlayer;
						spcm.SpellNum        = Character->SpellNum;
						spcm.SpellTarget     = Character->SpellTarget;
						spcm.TargetX         = Character->TargetX;
						spcm.TargetY         = Character->TargetY;
						spcm.TargetZ         = Character->TargetZ;
						
						// Send the message over network
						m_App->SendNetworkMessage(&spcm, DPNSEND_NOLOOPBACK);
					}
					break;
				}
			}
			
			CharPtr = CharPtr->Next;
		}
		if(CharPtr == NULL){
			Character->SpellNum = SpellNum;
			Character->SpellTarget = -1;
			
			Character->TargetX = Character->XPos + SpellRadius * sin(Character->Direction);
			Character->TargetY = Character->YPos;
			Character->TargetZ = Character->ZPos + SpellRadius * cos(Character->Direction);
			
			if(m_App->m_NodeTreeMesh.CheckIntersect(Character->XPos, Character->YPos, Character->ZPos,
				Character->TargetX, Character->TargetY, Character->TargetZ,
				&Dist) == TRUE) {
				// Adjust coordinates to be exactly 5.0 units away from target
				Dist -=  5.0f;
				Character->TargetX = Character->XPos + Dist * sin(Character->Direction);
				Character->TargetZ = Character->ZPos + Dist * cos(Character->Direction);
				
			} 
			if(m_App->m_CharController.SetAction(Character, CHAR_SPELL)){
				sSpellChangeMessage spcm;
				spcm.Header.Type     = MSG_SPELL_CHANGE;
				spcm.Header.Size     = sizeof(sSpellChangeMessage);
				spcm.Header.PlayerID = Character->dpnidPlayer;
				spcm.SpellNum        = Character->SpellNum;
				spcm.SpellTarget     = Character->SpellTarget;
				spcm.TargetX         = Character->TargetX;
				spcm.TargetY         = Character->TargetY;
				spcm.TargetZ         = Character->TargetZ;
				
				// Send the message over network
				m_App->SendNetworkMessage(&spcm, DPNSEND_NOLOOPBACK);
			}
		}	
	}
	// Attack a nearby monster or process NPC script
	if(m_App->MoveAction & 256) {
		CharPtr = GetParentCharacter();
		
		sMapItem *mapItem;
		// Draw all items, scanning for closest one to viewer
		if((mapItem = m_App->MapICS->GetParentItem()) != NULL) {
			while(mapItem != NULL) {
				
				// Don't bother with child objects
				if(mapItem->Parent == NULL) {
					XDiff = (float)fabs(Character->XPos - mapItem->XPos);
					YDiff = (float)fabs(Character->YPos - mapItem->YPos);
					ZDiff = (float)fabs(Character->ZPos - mapItem->ZPos);
					Dist = XDiff*XDiff+YDiff*YDiff+ZDiff*ZDiff;
					// Only check characters within 100.0 units distance
					if(Dist <= 2500.0f) {
						
						if(Character->CharICS->advAdd(mapItem->ItemNum, 1)){
							sItemChangeMessage icm;
							icm.Header.Type     = MSG_ITEM_CHANGE;
							icm.Header.Size     = sizeof(sItemChangeMessage);
							icm.Header.PlayerID = Character->dpnidPlayer;
							icm.ItemNum			= mapItem->ItemNum;
							icm.IsAdd			= TRUE;
							icm.TargetDpnid       = Character->dpnidPlayer;
							
							// Send the message over network
							m_App->SendNetworkMessage(&icm, DPNSEND_NOLOOPBACK);
						}
						m_App->MapICS->Remove(mapItem);
						break;
					}
					
				}
				// Go to next object
				mapItem = mapItem->Next;
			}
		}
	}
	
	return TRUE;
}

BOOL cChars::ValidateMove(sCharacter *Character,              \
						  float *XMove, float *YMove, float *ZMove)
{
	float Height;
	
	// Check for height changes (can step up to 64 units)
	Height = m_App->m_NodeTreeMesh.GetHeightBelow(*XMove + Character->XPos, Character->YPos + 64.0f, *ZMove + Character->ZPos);
	
	// Print item name
	*YMove = Height - Character->YPos;
	// Check against terrain mesh for collision
	if(m_App != NULL) {
		if(m_App->CheckIntersect(                                 \
			Character->XPos,                                     \
			Character->YPos+64.0f,                                \
			Character->ZPos,                                     \
			*XMove + Character->XPos,                            \
			*YMove + Character->YPos + 64.0f,                     \
			*ZMove + Character->ZPos) == TRUE)
			return FALSE;
	}
	
	return TRUE;
}


void cChars::Render2D(){
	long Color, Num;
	char Text[256];
	sCharItem *ItemPtr;
	sCharacter *Character;
	Num = 0;
	
    ItemPtr = GetCharacter(0)->CharICS->GetParentItem();
	Character = GetCharacter(0);
	
	m_App->m_Options.Blit(26,20, 0,0,256,256,1,1, 0x88888888);
	
    while(ItemPtr != NULL) {
		
		// Calculate color to draw based on mouse position
		if(Num == m_Select)
			Color = D3DCOLOR_RGBA(255,255,0,255);
		else
			Color = D3DCOLOR_RGBA(128,128,128,255);
		
		// Display item name w/quantity
		sprintf(Text, "%lu x %s", ItemPtr->Quantity,            \
			m_MIL[ItemPtr->ItemNum].Name);
		m_Font->Print(Text, 32, Num*32 + 32, 0, 0, Color);
		
		// Go down one line
		Num++;
		
		// Go to next item
		ItemPtr = ItemPtr->Next;
    }
}



void cChars::RenderStatus(){
	char Text[1024];
	sCharacter *Character;
	Character = GetCharacter(0);
	m_App->m_Options.Blit(26,20, 0,0,256,256,1,1, 0x88888888);
    // Display character's stats at top-right
    m_App->m_Font.Print("Stats", 32, 32);
    sprintf(Text, "%ld / %ld HP", Character->HealthPoints,     \
		Character->Def.HealthPoints);
    m_App->m_Font.Print(Text, 32, 64);
    sprintf(Text, "%ld / %ld MP", Character->ManaPoints,       \
		Character->Def.ManaPoints);
    m_App->m_Font.Print(Text, 32, 96);
    sprintf(Text, "Exp: %ld", Character->Def.Experience);
    m_App->m_Font.Print(Text, 32, 128);
}


⌨️ 快捷键说明

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