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

📄 chars.cpp

📁 这是一个服务端/客户端模式的小型网络游戏
💻 CPP
📖 第 1 页 / 共 4 页
字号:
		if(Character->Type != CHAR_PC && 
			( Character->Action == CHAR_MOVE || Character->Action == CHAR_IDLE)){
			
			sStateChangeMessage Msg;
			Msg.Header.Type     = MSG_STATE_CHANGE;
			Msg.Header.Size     = sizeof(sStateChangeMessage);
			Msg.Header.PlayerID = Character->dpnidPlayer;
			Msg.Action          = Character->Action;
			if(Character->Action == CHAR_MOVE)
				Msg.Direction       = Character->Direction;
			
			// Send message to server
			m_Server->SendNetworkMessage(&Msg, DPNSEND_NOLOOPBACK);
			
		}
		Character->LastAnim = Character->Action;
		
	}

  return TRUE;
}

BOOL cCharacterController::CheckMove(sCharacter *Character,   \
               float *XMove, float *YMove, float *ZMove)
{
  sCharacter *CharPtr;
  float XDiff, YDiff, ZDiff, Dist;
  float Radius1, Radius2;
  float XPos, YPos, ZPos;
  float MinX, MaxX, MinZ, MaxZ;

  // Error checking
  if(Character == NULL)
    return FALSE;  // Don't allow movement

  XPos = Character->XPos + (*XMove);
  YPos = Character->YPos + (*YMove);
  ZPos = Character->ZPos + (*ZMove);

  // Get character's X/Z radius
  GetBounds(Character->ID, &MinX, NULL, &MinZ,             \
                              &MaxX, NULL, &MaxZ, NULL);
  Radius1 = max(MaxX-MinX, MaxZ-MinZ) * 0.5f;

  // Check movement against other characters
  if((CharPtr = m_CharacterParent) != NULL) {
    while(CharPtr != NULL) {

      // Don't check against self or disabled characters
      if(Character != CharPtr && \
				!(Character->Type == CHAR_PC && CharPtr->Type == CHAR_PC)) {

        
        // Get distance between characters
        XDiff = (float)fabs(XPos - CharPtr->XPos);
        YDiff = (float)fabs(YPos - CharPtr->YPos);
        ZDiff = (float)fabs(ZPos - CharPtr->ZPos);
        Dist = XDiff*XDiff + YDiff*YDiff + ZDiff*ZDiff;

        // Get checking character's X/Z bounding radius
        GetBounds(CharPtr->ID, &MinX, NULL, &MinZ,         \
                                  &MaxX, NULL, &MaxZ, NULL);
        Radius2 = max(MaxX-MinX, MaxZ-MinZ) * 0.5f;

        // Don't allow movement if intersecting
        if(Dist <= (Radius1*Radius1 + Radius2*Radius2)  && \
		   Dist <= pow(Character->XPos-CharPtr->XPos,2)+pow(Character->YPos-CharPtr->YPos,2)+pow(Character->ZPos-CharPtr->ZPos,2)){
          return FALSE;
		}
      }

      CharPtr = CharPtr->Next;
    }
  }



  // Call overloaded check custom collisions (maps, etc)
  if(ValidateMove(Character, XMove, YMove, ZMove) == FALSE){
    return FALSE;  // Don't allow movement
  }

  return TRUE;
}

BOOL cCharacterController::ProcessUpdate(                     \
										 sCharacter *Character,
										 float XMove, float YMove, float ZMove)
{
	// Move character
	Character->XPos += XMove;
	Character->YPos += YMove;
	Character->ZPos += ZMove;
	
	return TRUE;
}

BOOL cCharacterController::Attack(sCharacter *Attacker,       \
                                  sCharacter *Victim)
{
	long AlterHPAmount, MessageID;
	// Error checking
	if(Attacker == NULL || Victim == NULL)
		return FALSE;
	
	// Don't attack dead or hurt people
	if(Victim->Action == CHAR_DIE || Victim->Action == CHAR_HURT)
		return FALSE;
	
	// Set attacker and victim
	Victim->Attacker = Attacker;
	Attacker->Victim = Victim;
	
	// Return if hit missed
	if((rand() % 1000) > GetToHit(Attacker)) {
		MessageID = MSG_MISSED;
	} else if((rand() % 1000) <= GetAgility(Victim)) {
		MessageID = MSG_DODGED;
	} else {
		// Attack landed, apply damage
		AlterHPAmount = Damage(Victim, TRUE, GetAttack(Attacker), -1, -1, &MessageID);
	}
	sAlterEffectMessage aem;
	aem.Header.Type     = MSG_ALTER_EFFECT;
	aem.Header.Size     = sizeof(sAlterEffectMessage);
	aem.Header.PlayerID = Attacker->dpnidPlayer;
	aem.EffectType     = MessageID;
	aem.HealthPoints       = Victim->HealthPoints;
	aem.ManaPoints	  = Attacker->ManaPoints;
	aem.VictimDpnid	  = Victim->dpnidPlayer;
	aem.AlterHPAmount	 =  AlterHPAmount;

	// Send the message over network
	m_Server->SendNetworkMessage(&aem, DPNSEND_NOLOOPBACK, -1);
	
	return TRUE;
}

long cCharacterController::Damage(sCharacter *Victim,         \
                                  BOOL PhysicalAttack,        \
                                  long Amount,                \
                                  long DmgClass,              \
                                  long CureClass, long *MessageID)
{
//  char Text[128];
  float Resist;
  float Range;
  long  DmgAmount;

  // Error checking
  if(Victim == NULL)
    return FALSE;

  // Can't attack if already dead or being hurt (or not enabled)
  if(Victim->Enabled == FALSE ||                              \
     Victim->Action==CHAR_DIE ||                              \
     Victim->Action==CHAR_HURT)
    return FALSE;

  // Adjust for defense if physical attack
  if(PhysicalAttack == TRUE) {
 
    // Random value for less/more damage (-+20%)
    Range     = (float)((rand() % 20) + 90) / 100.0f;
    DmgAmount = (long)((float)Amount * Range);

   // Subtract for defense of victim (allow -20% difference)
    Range     = (float)((rand() % 20) + 80) / 100.0f;
    DmgAmount -= (long)((float)GetDefense(Victim) * Range);
  } else {
    // Adjust for magical attack
    Resist = 1.0f - ((float)GetResistance(Victim) / 100.0f);
    DmgAmount = (long)((float)Amount * Resist);
  }

  // Bounds check value
  if(DmgAmount < 0)
    DmgAmount = 0;

  // Check for double damage
  if(Victim->Def.Class == DmgClass)
    DmgAmount *= 2;

  // Check for cure damage
  if(Victim->Def.Class == CureClass)
    DmgAmount = -(labs(DmgAmount)/2);

  // If no physical damage is dealt then randomly deal 
  // 10-20% of damage from the original amount.
  if(!DmgAmount && PhysicalAttack == TRUE) {
    Range     = (float)((rand() % 10) + 10) / 100.0f;
    DmgAmount = (long)((float)Amount * Range);
  }

  // Subtract damage amount
  Victim->HealthPoints -= DmgAmount;

  // Set hurt status and display message
  if(DmgAmount >= 0) {
	*MessageID = MSG_ALTERHP;

    // Only set hurt if any damage (and idle or moving)
    if(DmgAmount) {
      if(Victim->Action==CHAR_MOVE || Victim->Action==CHAR_IDLE)
        SetAction(Victim, CHAR_HURT);
        sStateChangeMessage Msg;
        Msg.Header.Type     = MSG_STATE_CHANGE;
        Msg.Header.Size     = sizeof(sStateChangeMessage);
        Msg.Header.PlayerID = Victim->dpnidPlayer;
        Msg.Action          = CHAR_HURT;

        // Send message to server
        m_Server->SendNetworkMessage(&Msg, DPNSEND_NOLOOPBACK);        
        
    }
  } 

  // Display cure amount
  if(DmgAmount < 0) {
	  *MessageID = MSG_ALTERHP;

  }

  return DmgAmount;
}

BOOL cCharacterController::Death(sCharacter *Attacker,        \
                                 sCharacter *Victim)
{
	
	if(Victim!=NULL) Victim->Enabled = FALSE;
	// If a PC or NPC dies, then don't remove from list
	if(Victim->Type != CHAR_PC) {
		// Give attacker the victim's experience
		if(Attacker != NULL) {
			if(Experience(Attacker, Victim->Def.Experience) == TRUE) {

			}
		}
	}
	
	return TRUE;
}

BOOL cCharacterController::Spell(sCharacter *Caster,          \
                                 sSpellTracker *SpellTracker, \
                                 sSpell *Spells)
{
  float XDiff, YDiff, ZDiff, Dist, YDist, XZDist;
  float MinX, MaxX, MinY, MaxY, MinZ, MaxZ;
  float SpellRadius, XZRadius, YRadius;
  sSpell *SpellPtr;
  sCharacter *CharPtr, *ClosestChar;
  float Closest;
  BOOL Allow;

  // Error checking
  if(Caster == NULL || SpellTracker == NULL || Spells == NULL)
    return TRUE;

  // Get pointer to spell
  SpellPtr = &Spells[SpellTracker->SpellNum];

  // Reduce magic
  Caster->ManaPoints -= SpellPtr->Cost;
  if(Caster->ManaPoints < 0)
    Caster->ManaPoints = 0;

  // Get radius of spell
  SpellRadius = SpellPtr->Range * SpellPtr->Range;

  // Reset closest character pointer
  ClosestChar = NULL;
  Closest = 0.0f;

  // Scan through all characters and look for hits
  if((CharPtr = m_CharacterParent) == NULL)
    return FALSE;
  while(CharPtr != NULL) {

    // Only bother with characters of allowed types
    // as well as not targeting self. Also, allow 
    // a RAISE_DEAD PC spell to affect any character.
    Allow = FALSE;
    if(CharPtr!=Caster && SpellTracker->Type==CharPtr->Type)
      Allow = TRUE;
    if(CharPtr->Type==CHAR_PC && SpellPtr->Effect==RAISE_DEAD)
      Allow = TRUE;

    // Find target(s) if allowed
    if(Allow == TRUE) {

      // Get distance from target to character
      XDiff = (float)fabs(CharPtr->XPos - SpellTracker->TargetX);
      YDiff = (float)fabs(CharPtr->YPos - SpellTracker->TargetY);
      ZDiff = (float)fabs(CharPtr->ZPos - SpellTracker->TargetZ);

      // Get X/Z and Y distances
      XZDist = (XDiff * XDiff + ZDiff * ZDiff) - SpellRadius;
      YDist  = (YDiff * YDiff) - SpellRadius;

      // Get target X/Z and Y radius
      GetBounds(CharPtr->ID, &MinX,&MinY,&MinZ,
                                &MaxX,&MaxY,&MaxZ,NULL);
      XZRadius = max(MaxX-MinX, MaxZ-MinZ) * 0.5f;
      YRadius = (MaxY-MinY) * 0.5f;

      // Check if character in range
      if(XZDist - (XZRadius * XZRadius) <= 0.0f && 
          YDist - (YRadius  * YRadius)  <= 0.0f) {
	  
        // Determine what to do if in range
        if(SpellPtr->Target == TARGET_SINGLE) {
          // Record closest character in range
          Dist = XDiff * XDiff + YDiff * YDiff + ZDiff * ZDiff;
          if(ClosestChar == NULL) {
            ClosestChar = CharPtr;
            Closest = Dist;
          } else {
            if(Dist < Closest) {
              ClosestChar = CharPtr;
              Closest = Dist;
            }
          }
        } else {
          // Spell hit target if area target
          SpellEffect(Caster, CharPtr, SpellPtr);
        }
      }
    }

    // Go to next character
    CharPtr = CharPtr->Next;
  }

  // Process spell on closest character if needed
  if(SpellPtr->Target==TARGET_SINGLE && ClosestChar!=NULL){
    SpellEffect(Caster, ClosestChar, SpellPtr);
  }

  return TRUE;
}

BOOL cCharacterController::SpellEffect(sCharacter *Caster,    \
                                       sCharacter *Target,    \
                                       sSpell *Spell)
{
	BOOL CanHit;
	long Chance;
	//  char Text[64];
    long  AlterHPAmount, MessageID;

	// Error checking
	if(Target == NULL || Spell == NULL)
		return FALSE;
	
	// Calculate chance of hitting
	if(Caster != NULL) {
		// A spell always lands if target=caster
		if(Caster == Target)
			Chance = 100;
		else
			Chance = (long)(((float)GetMental(Caster) / 100.0f +    \
			1.0f) * (float)Spell->Chance);
	} else {
		Chance = Spell->Chance;
	}
	
	// Alter chance by target's resistance
	if(Caster != Target)
		Chance = (long)((1.0f - (float)GetResistance(Target) /    \
		100.0f) * (float)Chance);
	
	// See if spell failed
	if(Chance != 100 && (rand() % 100) >= Chance) {
		MessageID = MSG_FAILED;

	} else {
		
		// Flag character to allow effect
		CanHit = TRUE;
		if(Target->Action==CHAR_HURT || Target->Action==CHAR_DIE)
			CanHit = FALSE;
		
		// Store attacker and victim
		if((Target->Attacker = Caster) != NULL)
			Caster->Victim = Target;
		
		// Process spell effect
		switch(Spell->Effect) {
		case ALTER_HEALTH:     // Alter health
			if(CanHit == FALSE)
				break;
			
			// Apply damage if value < 0
			if(Spell->Value[0] < 0.0f)
				AlterHPAmount= Damage(Target,FALSE,-(long)Spell->Value[0],           \
				Spell->DmgClass, Spell->CureClass, &MessageID);
			
			// Cure damage if value > 0
			if(Spell->Value[0] > 0.0f) {
				Target->HealthPoints += (long)Spell->Value[0];
				if(Target->HealthPoints > Target->Def.HealthPoints)
					Target->HealthPoints = Target->Def.HealthPoints;
				MessageID = MSG_ALTERHP;
				AlterHPAmount = (long)Spell->Value[0];

			}
			
			break;
			
			
		}
	}
	sAlterEffectMessage aem;
	aem.Header.Type     = MSG_ALTER_EFFECT;
	aem.Header.Size     = sizeof(sAlterEffectMessage);
	aem.Header.PlayerID = Caster->dpnidPlayer;
	aem.EffectType     = MessageID;
	aem.HealthPoints       = Target->HealthPoints;
	aem.ManaPoints	  = Caster->ManaPoints;
	aem.VictimDpnid	  = Target->dpnidPlayer;
	aem.AlterHPAmount = AlterHPAmount;

	// Send the message over network
	m_Server->SendNetworkMessage(&aem, DPNSEND_NOLOOPBACK, -1);
	
	return TRUE;
}

BOOL cCharacterController::Item(sCharacter *Owner,            \
                                sCharacter *Target,           \
                                long ItemNum,                 \
                                sCharItem *CharItem)
{
	sItem *Item;
	
	// Error checking
	if(Owner == NULL || Target == NULL || m_MIL == NULL)
		return FALSE;

	// Make sure restritions allow equiping of item
	if(!CheckUsageBit(m_MIL[ItemNum].Usage, Target->Def.Class))
		return FALSE;
	
	// Get pointer to item
	Item = (sItem*)&m_MIL[ItemNum];

	// Use specified item
	switch(Item->Category) {
    case EDIBLE:
		Target->HealthPoints += m_MIL[ItemNum].Value;
		if(Target->HealthPoints > Target->Def.HealthPoints)
			Target->HealthPoints = Target->Def.HealthPoints;
		break;
    case HEALING:
		// Alter health
		Target->ManaPoints += m_MIL[ItemNum].Value;
		if(Target->ManaPoints > Target->Def.ManaPoints)
			Target->ManaPoints = Target->Def.ManaPoints;
		break;
	}
	
	// Decrease quanity (and remove object) if needed
	if(CheckItemFlag(Item->Flags, USEONCE) && CharItem != NULL) {
		CharItem->Quantity--;
		if(CharItem->Quantity <= 0 && Owner->CharICS != NULL)
			Owner->CharICS->Remove(CharItem);
	}
	
	return TRUE;
}

⌨️ 快捷键说明

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