📄 game_chars.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 + -