📄 chars.cpp
字号:
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 + -