📄 chars.cpp
字号:
Character->TargetChar->ZPos);
Dist = XDiff*XDiff + YDiff*YDiff + ZDiff*ZDiff;
// Update if closer then distance
if(Dist < (Character->Distance*Character->Distance)) {
// Setup movement away from target
Dist = (float)sqrt(Dist);
if(Speed > Dist)
Speed = Dist;
MoveX = -(Character->TargetChar->XPos - \
Character->XPos) / Dist * Speed;
MoveZ = -(Character->TargetChar->ZPos - \
Character->ZPos) / Dist * 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) {
// 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);
// Perform attack action
SetAction(Character, CHAR_ATTACK);
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 health is less then half, then there's a 50% chance
// of healing (if the monster knows any heal spells)
if(Character->HealthPoints <= \
(Character->Def.HealthPoints / 2)) {
// Search for a known heal spell
for(i=0;i<64;i++) {
if(m_MSL[i].Name[0] && \
m_MSL[i].Effect == ALTER_HEALTH && \
m_MSL[i].Value[0] > 0.0f && \
Character->ManaPoints >= m_MSL[i].Cost && \
Character->Def.MagicSpells[i/32] & (1<<(i&31))) {
// This is the spell, determine chance to heal
if((rand() % 100) < 50) {
// Set spell data
Character->Victim = Character;
Character->Attacker = Character;
Character->SpellNum = i;
Character->SpellTarget = CHAR_MONSTER;
// Store target coordinates
Character->TargetX = Character->XPos;
Character->TargetY = Character->YPos;
Character->TargetZ = Character->ZPos;
// Clear movement
MoveX = MoveY = MoveZ = 0.0f;
// Perform spell action
SetAction(Character, CHAR_SPELL);
// Flag spell as cast
SpellCast = TRUE;
break;
}
}
}
}
// If there are bad status ailments, then there's a
// 50% chance of dispeling magic.
if(Character->Ailments & AILMENT_POISON || \
Character->Ailments & AILMENT_SLEEP || \
Character->Ailments & AILMENT_PARALYZE || \
Character->Ailments & AILMENT_ENCHANTED || \
Character->Ailments & AILMENT_DUMBFOUNDED || \
Character->Ailments & AILMENT_SLOW || \
Character->Ailments & AILMENT_BLIND || \
Character->Ailments & AILMENT_SILENCED && \
SpellCast == FALSE) {
// Search for a known dispel spell
for(i=0;i<64;i++) {
if(m_MSL[i].Name[0] && \
m_MSL[i].Effect == DISPEL_MAGIC && \
Character->ManaPoints >= m_MSL[i].Cost && \
Character->Def.MagicSpells[i/32] & (1<<(i&31))) {
// This is the spell, determine chance to dispel
if((rand() % 100) < 50) {
// Set spell data
Character->Victim = Character;
Character->Attacker = Character;
Character->SpellNum = i;
Character->SpellTarget = CHAR_MONSTER;
// Store target coordinates
Character->TargetX = Character->XPos;
Character->TargetY = Character->YPos;
Character->TargetZ = Character->ZPos;
// Clear movement
MoveX = MoveY = MoveZ = 0.0f;
// Perform spell action
SetAction(Character, CHAR_SPELL);
// Flag spell as cast
SpellCast = TRUE;
break;
}
}
}
}
// 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
Character->Object.GetBounds(NULL,NULL,NULL, \
NULL,&y1,NULL,NULL);
y1 = (y1 * 0.5f) + Character->YPos;
CharPtr->Object.GetBounds(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(LineOfSight(Character, CharPtr, \
Character->XPos, y1, \
Character->ZPos, \
CharPtr->XPos, y2, \
CharPtr->ZPos) && \
Dist <= (Radius * Radius)) {
// Set the spell data
Character->Victim = CharPtr;
CharPtr->Attacker = Character;
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 still no spell cast, try casting a known
// self-enhancing ailment-effecting spell.
if(SpellCast == FALSE) {
for(i=0;i<64;i++) {
if(m_MSL[i].Name[0] && \
m_MSL[i].Effect == CAUSE_AILMENT && \
Character->ManaPoints >= m_MSL[i].Cost && \
Character->Def.MagicSpells[i/32]&(1<<(i&31)) && \
(rand()%100) < 10) {
// Make sure it's self-enhancing
if((long)m_MSL[i].Value[0]&AILMENT_STRONG || \
(long)m_MSL[i].Value[0]&AILMENT_BARRIER || \
(long)m_MSL[i].Value[0]&AILMENT_SUREFOOTED || \
(long)m_MSL[i].Value[0]&AILMENT_FAST || \
(long)m_MSL[i].Value[0]&AILMENT_HAWKEYE) {
// Make sure ailment not already set
if(!(Character->Ailments & \
(long)m_MSL[i].Value[0])) {
// Set spell data
Character->Victim = Character;
Character->Attacker = Character;
Character->SpellNum = i;
Character->SpellTarget = CHAR_MONSTER;
// Store target coordinates
Character->TargetX = Character->XPos;
Character->TargetY = Character->YPos;
Character->TargetZ = Character->ZPos;
// Clear movement
MoveX = MoveY = MoveZ = 0.0f;
// Perform spell action
SetAction(Character, CHAR_SPELL);
break;
}
}
}
}
}
}
}
// Store movement and return
*XMove = MoveX;
*YMove = MoveY;
*ZMove = MoveZ;
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
Character->Object.GetBounds(&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 && CharPtr->Enabled == TRUE) {
// Don't check against other PC characters
if(Character->Type == CHAR_PC && \
CharPtr->Type == CHAR_PC)
break;
// 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
CharPtr->Object.GetBounds(&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))
return FALSE;
}
CharPtr = CharPtr->Next;
}
}
// Bounds check movement if MinX != MaxX
if(Character->MinX != Character->MaxX) {
if(XPos < Character->MinX || XPos > Character->MaxX)
*XMove = 0.0f;
if(YPos < Character->MinY || YPos > Character->MaxY)
*YMove = 0.0f;
if(ZPos < Character->MinZ || ZPos > Character->MaxZ)
*ZMove = 0.0f;
// Return no movement at all
if(!(*XMove) && !(*YMove) && !(*ZMove))
return FALSE;
}
// 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;
// Move object and point in direction
Character->Object.Move(Character->XPos, \
Character->YPos, \
Character->ZPos); \
Character->Object.Rotate(0.0f, Character->Direction, 0.0f);
// Set new animation
if(Character->LastAnim != Character->Action) {
Character->LastAnim = Character->Action;
if(m_NumAnimations && m_Animations != NULL) {
Character->LastAnimTime = timeGetTime() / 30;
Character->Object.SetAnimation( \
&m_Meshes[Character->Def.MeshNum].Animation, \
m_Animations[Character->Action].Name, \
Character->LastAnimTime);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -