📄 winmain.cpp
字号:
/**************************************************
WinMain.cpp
Chapter 19 Multiplayer Client Demo
Programming Role-Playing Games with DirectX
by Jim Adams (01 Jan 2002)
Required libraries:
D3D8.LIB, D3DX8.LIB, DINPUT8.LIB, D3DXOF.LIB,
DXGUID.LIB, DPNET.LIB, DPLAY.LIB, and DPNADDR.LIB
**************************************************/
#include "Core_Global.h"
#include "Frustum.h"
#include "NodeTree.h"
#include "WinMain.h"
#include "resource.h"
#include "Chars.h"
#include "Script.h"
#include "Window.h"
// 4. 实例化一个category对象
log4cpp::Category& warn_log =
log4cpp::Category::getInstance("Debug_log4cpp");
char sTemp[1024] = "";
// Global names of character meshes
char *g_CharMeshNames[] = {
{ "..\\Data\\Warrior.x" }, // Mesh # 0
{ "..\\Data\\Yodan.x" } // Mesh # 1
};
sCharAnimationInfo g_CharAnimations[] = {
{ "Idle", TRUE },
{ "Walk", TRUE },
{ "Swing", FALSE },
{ "Spell", FALSE },
{ "Spell", FALSE },
{ "Hurt", FALSE },
{ "Die", FALSE },
{ "Idle", TRUE }
};
char *g_SpellMeshNames[] = {
{ "..\\Data\\Fireball.x" },
{ "..\\Data\\Explosion.x" },
{ "..\\Data\\Groundball.x" },
{ "..\\Data\\ice.x" },
{ "..\\Data\\bomb.x" },
};
cApp *g_Application; // Global application pointer
cNetworkAdapter *g_Adapters; // Global adapter list pointer
///////////////////////////////////////////////////////////
// cApp functions
///////////////////////////////////////////////////////////
cApp::cApp()
{
// Setup main window information
m_Width = 640;
m_Height = 480;
m_Style = WS_BORDER | WS_CAPTION | \
WS_MINIMIZEBOX | WS_SYSMENU;
strcpy(m_Class, "ClientClass");
strcpy(m_Caption, "Network Client Demo by Jim Adams");
// Clear class data
g_Application = this;
g_Adapters = &m_Adapters;
m_Status = MSG_NORMAL;
MoveAction = 0;
CamMoved = FALSE;
m_CamAngle = 0.0f;
m_YCamAngle = 0.1f;
m_Count = 0;
ScripteHandle.Renderflag = FALSE;
ScripteHandle.EffectCounter = 0;
}
BOOL cApp::Init()
{
// Select a network adapter to use (or quit if selected)
if(SelectAdapter() == FALSE)
return FALSE;
// Initialize the game, set video mode, load data, etc
if(InitializeGame() == FALSE) {
Error(FALSE, "Unable to initialize game.");
return FALSE;
}
// Join networked game
if(JoinGame() == FALSE) {
Error(FALSE, "Unable to connect to server.");
return FALSE;
}
return TRUE;
}
BOOL cApp::Shutdown()
{
// Shutdown network
m_Adapters.Shutdown();
m_Client.Disconnect();
m_Client.Shutdown();
// clean up and flush all appenders
log4cpp::Category::shutdown();
// Free controllers
m_CharController.Free();
m_SpellController.Free();
m_Script.Free();
// Free the options texture
m_Options.Free();
// Free meshes
m_NodeTreeMesh.Free();
m_TerrainMesh.Free();
// Shutdown input
m_Keyboard.Free();
m_Mouse.Free();
m_Input.Shutdown();
// Shutdown graphics
m_Font.Free();
m_Graphics.Shutdown();
return TRUE;
}
BOOL cApp::Frame()
{
static DWORD UpdateCounter = timeGetTime();
static DWORD LatencyCounter = timeGetTime();
// Get local input every frame
m_Keyboard.Acquire(TRUE);
m_Mouse.Acquire(TRUE);
m_Keyboard.Read();
m_Mouse.Read();
// Pressing ESC quits program
if(m_Keyboard.GetKeyState(KEY_ESC) == TRUE ){
if(m_Status == MSG_NORMAL && ScripteHandle.Renderflag == FALSE) return FALSE;
}
if(!m_CharController.m_Messages.empty()){
sMessage pm;
sAssignPlayerIDProcMessage *apidm;
sCreatePlayerProcMessage *cppm;
sFileProcMessage *fpm;
// Enter critical section
EnterCriticalSection(&m_CharController.m_UpdateCS);
pm = m_CharController.m_Messages.front();
// Leave critical section
LeaveCriticalSection(&m_CharController.m_UpdateCS);
switch( pm.Header.Type){
case MSG_ASSIGNID:
apidm = (sAssignPlayerIDProcMessage *)±
m_CharController.GetCharacter(0)->dpnidPlayer = apidm->Header.PlayerID;
break;
case MSG_INIT_FILE:
FILE *fp;
char FilenameBuffer[MAX_PATH];
fpm = (sFileProcMessage *)±
sCharacter *Character;
Character = m_CharController.GetCharacter(0);
if(fpm->FileType == MSG_ICS)
sprintf(FilenameBuffer, "Save\\ICS%s.dat", Character->Def.Name);
else if(fpm->FileType == MSG_CHARACTER)
sprintf(FilenameBuffer, "Save\\%s.dat", Character->Def.Name);
if((fp=fopen(FilenameBuffer, "wb"))==NULL)
if((fp=fopen(FilenameBuffer, "wb+"))==NULL)
break;
fwrite(fpm->Data, 1, fpm->FileSize, fp);
fclose(fp);
if(fpm->FileType == MSG_ICS)
Character->CharICS->Load(FilenameBuffer);
else if(fpm->FileType == MSG_CHARACTER) m_CharController.Load(Character, FilenameBuffer);
break;
case MSG_RELIVE_CHANGE:
sReliveChangeProcMessage *rcpm;
rcpm = (sReliveChangeProcMessage *)±
if((Character = GetCharacterPoint(rcpm->Header.PlayerID)) == NULL) break;
if(Character->Type == CHAR_PC) Character->Def.Experience = rcpm->Experience;
Character->Enabled = TRUE;
if(Character->Type == CHAR_PC || Character->AI == CHAR_STAND) Character->Action = CHAR_IDLE;
else Character->Action = CHAR_MOVE;
Character->HealthPoints = Character->Def.HealthPoints;
Character->ManaPoints = Character->Def.ManaPoints;
break;
case MSG_PLAYER_INFO:
case MSG_CREATE_PLAYER:
cppm = (sCreatePlayerProcMessage *)±
m_CharController.Add(cppm->Header.PlayerID, cppm->Header.PlayerID, cppm->Definition, cppm->Type, cppm->AI, \
cppm->XPos, cppm->YPos, cppm->ZPos, cppm->Direction, cppm->Action, cppm->Name);
break;
case MSG_ALTER_EFFECT:
sAlterEffectProcMessage *aepm;
sCharacter *Attacker, *Victim;
char Text[128];
aepm = (sAlterEffectProcMessage *)±
Attacker = m_CharController.GetCharacter(aepm->Header.ID);
Victim = m_CharController.GetCharacter(aepm->VictimID);
if(Victim!=NULL){
switch( aepm->EffectType){
case MSG_FAILED:
m_CharController.SetMessage(Victim, "Failed!", 500);
break;
case MSG_MISSED:
m_CharController.SetMessage(Victim, "Missed!", 500);
break;
case MSG_DODGED:
m_CharController.SetMessage(Victim, "Dodged!", 500);
break;
case MSG_ALTERHP:
if(aepm->AlterHPAmount >= 0) {
sprintf(Text, "-%lu HP", aepm->AlterHPAmount);
m_CharController.SetMessage(Victim, Text, 500, D3DCOLOR_RGBA(255,64,0,255));
} else {
sprintf(Text, "+%lu HP", -aepm->AlterHPAmount);
m_CharController.SetMessage(Victim, Text, 500, D3DCOLOR_RGBA(0,64,255,255));
}
break;
}
Victim->HealthPoints = aepm->HealthPoints;
}
if(Attacker!=NULL){
Attacker->ManaPoints = aepm->ManaPoints;
}
break;
case MSG_DESTROY_PLAYER:
sDestroyPlayerProcMessage *dppm;
dppm = (sDestroyPlayerProcMessage *)±
Character = m_CharController.GetCharacter(dppm->Header.ID);
m_CharController.Remove(Character);
break;
}
// Enter critical section
EnterCriticalSection(&m_CharController.m_UpdateCS);
m_CharController.m_Messages.pop_front();
// Leave critical section
LeaveCriticalSection(&m_CharController.m_UpdateCS);
}
// Handle connection and waiting for data screen
if(m_Client.m_Connected == FALSE || !m_CharController.GetCharacter(0)->dpnidPlayer) {
// Display message(s)
m_Graphics.Clear();
if(m_Graphics.BeginScene() == TRUE) {
m_Font.Print("Connecting to server...", 0, 0);
if(!m_CharController.GetCharacter(0)->dpnidPlayer)
m_Font.Print("Waiting for server data...", 0, 20);
m_Graphics.EndScene();
}
m_Graphics.Display();
// Request player ID from server every 2 seconds
if(timeGetTime() > UpdateCounter + 2000) {
UpdateCounter = timeGetTime(); // Update counter
sAssignPlayerIDMessage apidm;
apidm.Header.Type = MSG_ASSIGNID;
apidm.Header.Size = sizeof(sAssignPlayerIDMessage);
SendNetworkMessage(&apidm, DPNSEND_NOLOOPBACK | \
DPNSEND_GUARANTEED);
}
// Update player latency values every 10 seconds
if(timeGetTime() > LatencyCounter + 10000) {
UpdateLatency();
LatencyCounter = timeGetTime(); // Reset counter
}
return TRUE;
}
// Store movements every frame
if(m_Keyboard.GetKeyState(KEY_UP) == TRUE)
MoveAction |= 1;
if(m_Keyboard.GetKeyState(KEY_RIGHT) == TRUE)
MoveAction |= 2;
if(m_Keyboard.GetKeyState(KEY_DOWN) == TRUE)
MoveAction |= 4;
if(m_Keyboard.GetKeyState(KEY_LEFT) == TRUE)
MoveAction |= 8;
// Store attack action
if(m_Keyboard.GetKeyState(KEY_SPACE) == TRUE)
MoveAction |= 16;
if(m_Mouse.GetButtonState(MOUSE_LBUTTON) == TRUE)
MoveAction |= 16;
if(m_Keyboard.GetKeyState(KEY_1) == TRUE) {
MoveAction |= 32;
m_Keyboard.SetLock(KEY_1, TRUE);
m_Keyboard.SetKeyState(KEY_1, FALSE);
}
if(m_Keyboard.GetKeyState(KEY_2) == TRUE) {
MoveAction |= 64;
m_Keyboard.SetLock(KEY_2, TRUE);
m_Keyboard.SetKeyState(KEY_2, FALSE);
}
if(m_Keyboard.GetKeyState(KEY_3) == TRUE) {
MoveAction |= 128;
m_Keyboard.SetLock(KEY_3, TRUE);
m_Keyboard.SetKeyState(KEY_3, FALSE);
}
if(m_Keyboard.GetKeyState(KEY_P) == TRUE) {
MoveAction |= 256;
m_Keyboard.SetLock(KEY_P, TRUE);
m_Keyboard.SetKeyState(KEY_P, FALSE);
}
if(m_Keyboard.GetKeyState(KEY_U) == TRUE) {
MoveAction |= 512;
m_Keyboard.SetLock(KEY_U, TRUE);
m_Keyboard.SetKeyState(KEY_U, FALSE);
}
if(m_Keyboard.GetKeyState(KEY_S) == TRUE) {
MoveAction |= 1024;
m_Keyboard.SetLock(KEY_S, TRUE);
m_Keyboard.SetKeyState(KEY_S, FALSE);
}
if(m_Status == MSG_NORMAL){
// Rotate camera
if(m_Mouse.GetXDelta() > 0) {
m_CamAngle -= 0.1f;
CamMoved = TRUE;
if(m_CamAngle <= -3.14f)m_CamAngle = 3.14f;
}
if(m_Mouse.GetXDelta() < 0) {
m_CamAngle += 0.1f;
CamMoved = TRUE;
if(m_CamAngle >= 3.14f)m_CamAngle = -3.14f;
}
// Rotate camera
if(m_Mouse.GetYDelta() > 0) {
m_YCamAngle += 0.1f;
if(m_YCamAngle > 1.4f)m_YCamAngle = 1.4f;
}
if(m_Mouse.GetYDelta() < 0) {
m_YCamAngle -= 0.1f;
if(m_YCamAngle < 0.1f)m_YCamAngle = 0.1f;
}
}
// Only update players every 33ms (30 times a second)
if(timeGetTime() < UpdateCounter + 33)
return TRUE;
////////////////////////////////////////////////////////////////////////////////////
///////////33秒刷新率
////////////////////////////////////////////////////////////////////////////////////
m_Count++;
if(m_Count > 2000){
if(rand() %2){
MapICS->Add((rand()%2?1:9), 1, -1650 + rand()%3300, 0, rand()%290);
} else {
MapICS->Add((rand()%2?1:9), 1, -1650 + rand()%3300, 0, -1259+rand()%397);
}
m_Count = 0;
}
// Attack a nearby monster or process NPC script
if(MoveAction & 512) {
if(m_Status != MSG_ITEMS){
m_Status = MSG_ITEMS;
ShowMouse(TRUE);
}
else {
m_Status = MSG_NORMAL;
ShowMouse(FALSE);
}
} else if(MoveAction & 1024) {
if(m_Status != MSG_STATUS ){
if(m_Status == MSG_ITEMS)ShowMouse(FALSE);
m_Status = MSG_STATUS;
} else {
m_Status = MSG_NORMAL;
}
}
// Update all players
UpdateCamera();
// Update controllers
m_CharController.Update();
m_SpellController.Update();
// Render the scene
RenderScene();
MoveAction = 0; // Clear action data for next frame
UpdateCounter = timeGetTime(); // Reset update counter
return TRUE;
}
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, \
LPSTR szCmdLine, int nCmdShow)
{
cApp App;
return App.Run();
}
///////////////////////////////////////////////////////////
// Select adapter dialog and other functions
///////////////////////////////////////////////////////////
BOOL CALLBACK ConnectDialogProc(HWND hWnd, UINT uMsg, \
WPARAM wParam, LPARAM lParam)
{
int Selection;
long i;
char Name[32], IP[16], Text[256];
static HWND hAdapters;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -