📄 chars.cpp
字号:
BOOL cCharacterController::Move( \
long IDNum, \
float XPos, float YPos, float ZPos)
{
sCharacter *CharPtr;
// Get pointer to character
if((CharPtr = GetCharacter(IDNum)) == NULL)
return FALSE;
// Set new values
CharPtr->XPos = XPos;
CharPtr->YPos = YPos;
CharPtr->ZPos = ZPos;
return TRUE;
}
BOOL cCharacterController::GetPosition( \
long IDNum, \
float *XPos, float *YPos, float *ZPos)
{
sCharacter *CharPtr;
if((CharPtr = GetCharacter(IDNum)) == NULL)
return FALSE;
if(XPos != NULL)
*XPos = CharPtr->XPos;
if(YPos != NULL)
*YPos = CharPtr->YPos;
if(ZPos != NULL)
*ZPos = CharPtr->ZPos;
return TRUE;
}
BOOL cCharacterController::SetBounds( \
long IDNum, \
float MinX, float MinY, float MinZ, \
float MaxX, float MaxY, float MaxZ, float Radius)
{
sCharacter *CharPtr;
// Get pointer to character
if((CharPtr = GetCharacter(IDNum)) == NULL)
return FALSE;
// Set new values
CharPtr->MinX = min(MinX, MaxX);
CharPtr->MinY = min(MinY, MaxY);
CharPtr->MinZ = min(MinZ, MaxZ);
CharPtr->MaxX = max(MinX, MaxX);
CharPtr->MaxY = max(MinY, MaxY);
CharPtr->MaxZ = max(MinZ, MaxZ);
CharPtr->Radius = Radius;
return TRUE;
}
BOOL cCharacterController::GetBounds( \
long IDNum, \
float *MinX, float *MinY, float *MinZ, \
float *MaxX, float *MaxY, float *MaxZ, float *Radius)
{
sCharacter *CharPtr;
if((CharPtr = GetCharacter(IDNum)) == NULL)
return FALSE;
if(MinX != NULL)
*MinX = CharPtr->MinX;
if(MinY != NULL)
*MinY = CharPtr->MinY;
if(MinZ != NULL)
*MinZ = CharPtr->MinZ;
if(MaxX != NULL)
*MaxX = CharPtr->MaxX;
if(MaxY != NULL)
*MaxY = CharPtr->MaxY;
if(MaxZ != NULL)
*MaxZ = CharPtr->MaxZ;
if(Radius != NULL)
*Radius = CharPtr->Radius;
return TRUE;
}
BOOL cCharacterController::SetType(long IDNum, long Type)
{
sCharacter *CharPtr;
// Get pointer to character
if((CharPtr = GetCharacter(IDNum)) == NULL)
return FALSE;
// Set new value
CharPtr->Type = Type;
return TRUE;
}
long cCharacterController::GetType(long IDNum)
{
sCharacter *CharPtr;
if((CharPtr = GetCharacter(IDNum)) == NULL)
return 0;
return CharPtr->Type;
}
BOOL cCharacterController::SetAI(long IDNum, long Type)
{
sCharacter *CharPtr;
// Get pointer to character
if((CharPtr = GetCharacter(IDNum)) == NULL)
return FALSE;
// Set new value
CharPtr->AI = Type;
return TRUE;
}
long cCharacterController::GetAI(long IDNum)
{
sCharacter *CharPtr;
if((CharPtr = GetCharacter(IDNum)) == NULL)
return 0;
return CharPtr->AI;
}
BOOL cCharacterController::SetTargetCharacter(long IDNum, \
long TargetNum)
{
sCharacter *CharPtr, *CharTarget;
// Get pointer to character
if((CharPtr = GetCharacter(IDNum)) == NULL)
return FALSE;
// Clear if TargetNum == -1
if(TargetNum == -1)
CharPtr->TargetChar = NULL;
else {
// Scan through list and target 1st TargetNum found
CharTarget = m_CharacterParent;
while(CharTarget != NULL) {
if(CharTarget->ID == TargetNum) {
CharPtr->TargetChar = CharTarget;
break;
}
CharTarget = CharTarget->Next;
}
// Clear target if not found in list
if(CharTarget == NULL)
CharPtr->TargetChar = NULL;
}
return TRUE;
}
BOOL cCharacterController::CharUpdate( \
sCharacter *Character, long Elapsed, \
float *XMove, float *YMove, float *ZMove)
{
float MoveX, MoveY, MoveZ, Speed;
float XDiff, YDiff, ZDiff, Dist, Radius;
float y1, y2;
long i, SpellNum;
BOOL SpellCast;
sCharacter *CharPtr;
//long VictimDpnid;
// Error checking
if(Character == NULL)
return FALSE;
// Clear movements and action
MoveX = MoveY = MoveZ = 0.0f;
// Calculate movement speed
Speed = (float)Elapsed / 1000.0f * GetSpeed(Character);
// Move character based on their type
switch(Character->AI) {
case CHAR_STAND:
break;
case CHAR_WANDER:
// Calculate new distance and direction if needed
Character->Distance -= Elapsed;
if(Character->Distance <= 0.0f) {
// Calculate a new distance to travel
Character->Distance = (float)(rand() % 2000) + 2000.0f;
// Calculate a new direction
Character->Direction = (float)(rand()%360)*0.01744444f;
}
// Process walk or stand still
if(Character->Distance > 1000.0f) {
MoveX = (float)sin(Character->Direction) * Speed;
MoveZ = (float)cos(Character->Direction) * Speed;
Character->Action = CHAR_MOVE;
} else {
// Stand still for one second
Character->Action = CHAR_IDLE;
}
break;
case CHAR_FOLLOW:
float minDist;
sCharacter *CharPtrMinDist;
minDist = MAX_FLOAT;
CharPtrMinDist = NULL;
// Scan through list and pick a character
CharPtr = m_CharacterParent;
while(CharPtr != NULL) {
// Randomly pick enabled target (a PC),
// and make sure the target is not hurt or dead.
if(CharPtr != Character && CharPtr->Type==CHAR_PC &&
CharPtr->Enabled == TRUE && \
CharPtr->Action != CHAR_DIE ) {
// Get distance to target
XDiff = (float)fabs(Character->XPos - CharPtr->XPos);
YDiff = (float)fabs(Character->YPos - CharPtr->YPos);
ZDiff = (float)fabs(Character->ZPos - CharPtr->ZPos);
Dist = XDiff * XDiff + YDiff * YDiff + ZDiff * ZDiff;
// Attack if in range
if(minDist > Dist) {
minDist = Dist;
CharPtrMinDist = CharPtr;
}
}
// Go to next character
CharPtr = CharPtr->Next;
}
if(CharPtrMinDist != NULL){
// Update if further then distance
if(minDist > (Character->Distance*Character->Distance)) {
// Setup movement towards target
minDist = (float)sqrt(minDist);
if(Speed > minDist)
Speed = minDist;
MoveX = (CharPtrMinDist->XPos - \
Character->XPos) / minDist * Speed;
MoveZ = (CharPtrMinDist->ZPos - \
Character->ZPos) / minDist * Speed;
// Set new direction
Character->Direction = (float)atan2(MoveX, MoveZ);
// Set new action
Character->Action = CHAR_MOVE;
}
}
break;
}
// Process monster actions if at full charge
if(Character->Type == CHAR_MONSTER && \
Character->Charge >= 100.0f) {
// Determine chance of attacking
if((rand() % 100) <= Character->Def.ToAttack) {
// Scan through list and pick a character
CharPtr = m_CharacterParent;
while(CharPtr != NULL) {
// Randomly pick enabled target (a PC),
// and make sure the target is not hurt or dead.
if(CharPtr != Character && CharPtr->Type==CHAR_PC && \
(rand() % 100) < 50 && \
CharPtr->Enabled == TRUE && \
CharPtr->Action != CHAR_DIE && \
CharPtr->Action != CHAR_HURT) {
// Get distance to target
XDiff = (float)fabs(Character->XPos - CharPtr->XPos);
YDiff = (float)fabs(Character->YPos - CharPtr->YPos);
ZDiff = (float)fabs(Character->ZPos - CharPtr->ZPos);
Dist = XDiff * XDiff + YDiff * YDiff + ZDiff * ZDiff;
// Make sure in range to attack
Radius = GetXZRadius(Character);
Radius += Character->Def.Range;
// Attack if in range
if((Radius*Radius) >= Dist && !CheckIntersect(Character->XPos, Character->YPos, Character->ZPos,
CharPtr->XPos, CharPtr->YPos, CharPtr->ZPos) ) {
// Set attack data
Character->Victim = CharPtr;
CharPtr->Attacker = Character;
// Clear movement
MoveX = MoveY = MoveZ = 0.0f;
// Point towards target character
XDiff = CharPtr->XPos - Character->XPos;
ZDiff = CharPtr->ZPos - Character->ZPos;
Character->Direction = (float)atan2(XDiff, ZDiff);
if(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_Server->SendNetworkMessage(&sacm, DPNSEND_NOLOOPBACK, -1);
// Perform attack action
}
break;
}
}
// Go to next character
CharPtr = CharPtr->Next;
}
} else
// Determine chance of spell casting
if((rand() % 100) <= Character->Def.ToMagic && \
m_MSL != NULL && m_SpellController != NULL) {
// Flag no spells cast
SpellCast = FALSE;
// If now spells already cast, then pick a random one
if(SpellCast == FALSE) {
// Pick a random spell to attack with
SpellNum = rand() % 64;
// Scan through list until a spell is found the
// monster can cast.
for(i=0;i<64;i++) {
if(m_MSL[SpellNum].Name[0] && \
Character->Def.MagicSpells[SpellNum / 32] & \
(1 << (SpellNum & 31)) && \
Character->ManaPoints >= m_MSL[SpellNum].Cost && \
(rand() % 100) < 50) {
// Scan through list and pick a character
CharPtr = m_CharacterParent;
while(CharPtr != NULL) {
// Randomly pick an enabled target (a PC),
// and make sure the target is not hurt or dead.
// Also, don't cast self-targeting spells here.
if(CharPtr != Character && \
CharPtr->Type == CHAR_PC && \
m_MSL[SpellNum].Target != TARGET_SELF && \
(rand() % 100) < 50 && \
CharPtr->Enabled == TRUE && \
CharPtr->Action != CHAR_DIE && \
CharPtr->Action != CHAR_HURT) {
// Get heights of attacker and target
// for line of sight checking
GetBounds(CharPtr->ID, NULL,NULL,NULL, \
NULL,&y1,NULL,NULL);
y1 = (y1 * 0.5f) + Character->YPos;
GetBounds(CharPtr->ID, NULL,NULL,NULL, \
NULL,&y2,NULL,NULL);
y2 = (y2 * 0.5f) + CharPtr->YPos;
// Get distance to target
XDiff = (float)fabs(Character->XPos - \
CharPtr->XPos);
YDiff = (float)fabs(Character->YPos - \
CharPtr->YPos);
ZDiff = (float)fabs(Character->ZPos - \
CharPtr->ZPos);
Dist = XDiff*XDiff+YDiff*YDiff+ZDiff*ZDiff;
// Reduce distance by character's radius
Radius = GetXZRadius(CharPtr);
Dist -= (Radius*Radius);
// Get spell radius
Radius = m_MSL[SpellNum].Distance;
// Make sure target is in range and in sight
if(!CheckIntersect( Character->XPos, y1, \
Character->ZPos, \
CharPtr->XPos, y2, \
CharPtr->ZPos) && \
Dist <= (Radius * Radius)) {
// Set the spell data
Character->Victim = CharPtr;
// VictimDpnid = CharPtr->dpnidPlayer;
CharPtr->Attacker = Character;
// AttackerDpnid = Character->dpnidPlayer;
Character->SpellNum = SpellNum;
Character->SpellTarget = CHAR_PC;
// Store target coordinates
Character->TargetX = CharPtr->XPos;
Character->TargetY = CharPtr->YPos;
Character->TargetZ = CharPtr->ZPos;
// Face toward target (only if not self)
if(m_MSL[SpellNum].Target != TARGET_SELF) {
XDiff = CharPtr->XPos - Character->XPos;
ZDiff = CharPtr->ZPos - Character->ZPos;
Character->Direction = \
(float)atan2(XDiff, ZDiff);
}
// Clear movement
MoveX = MoveY = MoveZ = 0.0f;
// Set the spell action
SetAction(Character, CHAR_SPELL);
// Flag spell as cast
SpellCast = TRUE;
break;
}
}
// Go to next character
CharPtr = CharPtr->Next;
}
break;
}
// Go to next spell
SpellNum = (SpellNum + 1) % 64;
}
}
}
if(SpellCast == TRUE){
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_Server->SendNetworkMessage(&spcm, DPNSEND_NOLOOPBACK, -1);
}
}
// Store movement and return
*XMove = MoveX;
*YMove = MoveY;
*ZMove = MoveZ;
// Set new animation
if(Character->LastAnim != Character->Action) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -