µ±Ç°Î»Öà : 145zÓÎÏ·Õ¾¡¡|¡¡ÈÈѪ´«Ææ¡¡|¡¡¼¼Êõ½Ì³Ì¡¡|¡¡

´«ÆæGOMÒýÇæBOSSѪÌõÌí¼ÓÈ«¹¥ÂÔ£¬´ÓÊý¾Ý¿âÅäÖõ½¶¯Ì¬ÑªÌõ¶¨ÖƵÄÍêÕû½â¾ö·½°¸

Èȶȣº
GOMÒýÇæµÄBOSSѪÌõÏÔʾÒÀÀµ**Monster.DB²ÎÊý**¡¢**¿Í»§¶ËËØ²Ä**¡¢**M2ServerÉèÖÃ**Èý²¿·ÖÁª¶¯¡£±¾ÎĽ«Ìṩ´Ó»ù´¡ÅäÖõ½½ø½×¶¯Ì¬ÑªÌõµÄÍêÕûʵÏÖ·½°¸¡£

---

### Ò»¡¢Êý¾Ý¿â²ãÅäÖÃ

#### 1. **Monster.DB¹Ø¼ü×Ö¶Î**

| ×Ö¶ÎÃû | ÖµÓò·¶Î§ | ×÷Óà | ʾÀýÖµ£¨³àÔ¶ñħ£© |
|------------|----------------|-----------------------|----------------|
| **Race** | 81-255 | ¿ØÖÆÑªÌõÏÔʾ£¨81=ÏÔʾѪÌõ£© | 81 |
| **RaceImg**| ¶ÔÓ¦Blood.pak±àºÅ | ѪÌõËØ²ÄÆðʼ±àºÅ | 50 |
| **Appr** | ѪÌõ·Ö¶ÎÊý | 0=µ¥Ìõ£¬100=10¶Î | 100 |


**²Ù×÷²½Öè**£º
1. ÓÃDBC¹¤¾ß´ò¿ª`Monster.DB`
2. ¶¨Î»Ä¿±êBOSSÐУ¬ÉèÖÃ`Race=81`
3. ÉèÖÃ`RaceImg=50`£¨¶ÔÓ¦`Blood.pak`µÄ50ºÅͼ¿ªÊ¼£©

---

### ¶þ¡¢¿Í»§¶Ë×ÊÔ´ÊÊÅä

#### 1. **ѪÌõËØ²Ä¹æ·¶**
- **Îļþ·¾¶**£º
```
Resources\Data\Blood.pak // ±ØÐëΪδ¼ÓÃÜPAK
```

- **ËØ²Ä¹æ¸ñ**£º
- µ¥×éѪÌõÐè°üº¬10Ö¡£¨0-100%ѪÁ¿£©
- ÿ֡³ß´ç½¨Ò飺200×20ÏñËØ
- ÑÕÉ«¹æ·¶£ººìÉ«£¨ÂúѪ£©→»ÆÉ«£¨50%£©→ÂÌÉ«£¨²ÐѪ£©

#### 2. **×ø±êУ׼¹¤¾ß**
ʹÓÃ**WZL±à¼­Æ÷**µ÷ÕûѪÌõÆ«ÒÆÁ¿£º
```
XÆ«ÒÆ = ¹ÖÎï¿í¶È/2 - ѪÌõ¿í¶È/2
YÆ«ÒÆ = ¹ÖÎï¸ß¶È + 10
```


---

### Èý¡¢M2Server²ÎÊýµ÷ÓÅ

#### 1. **ѪÌõÏÔʾ¿ª¹Ø**
·¾¶£º`M2Server → Ñ¡Ïî → ¹ÖÎïÉèÖà → ÏÔʾѪÌõ`
- ¹´Ñ¡`ÆôÓùÖÎïѪÌõ`
- ÉèÖÃ`ÏÔʾÌõ¼þ`£ºÑªÁ¿>10%»òʼÖÕÏÔʾ

#### 2. **¶¯Ì¬ÑªÌõ½ø½×ÉèÖÃ**
```ini
[Blood]
Scale=0.8 ; ѪÌõËõ·Å±ÈÀý
Alpha=200 ; ͸Ã÷¶È£¨0-255£©
FollowSpeed=3 ; ѪÌõ¸úËæËÙ¶È£¨1-10£©
```


---

### ËÄ¡¢½Å±¾¼¶¶¯Ì¬¿ØÖÆ

#### 1. **Ç¿ÖÆÏÔʾѪÌõ£¨QFunction-0.txt£©**
```lua
[@OnKillMon]
#IF
CheckMonName ³àÔ¶ñħ
#ACT
SetMonBloodVis ³àÔ¶ñħ 1 ; Ç¿ÖÆÏÔʾ
Break
```


#### 2. **½×¶ÎѪÁ¿Ìáʾ£¨Robot.txt£©**
```lua
[@BossBlood]
#IF
CheckMonHpPer ³àÔ¶ñħ < 30
#ACT
SendMsg 6 ³àÔ¶ñħѪÁ¿µÍÓÚ30%£¬½øÈë¿ñ±©×´Ì¬£¡
SetMonBloodColor ³àÔ¶ñħ 255 0 0 ; ºìɫѪÌõ
```


---

### Îå¡¢¸ßƵÎÊÌâ½â¾ö·½°¸

| **ÎÊÌâÏÖÏó** | **Ô­Òò** | **½â¾ö·½°¸** |
|--------------------------|-----------------------|--------------------------------|
| ѪÌõλÖÃÆ«ÒÆ | ×ø±êδУ׼ | ÓÃWZL±à¼­Æ÷µ÷ÕûYÆ«ÒÆÖµ |
| ѪÌõ²»¸üР| RaceImg±àºÅ´íÎó | ¼ì²éBlood.pakÆðʼ±àºÅÊÇ·ñ¶ÔÆë |
| ¶àBOSSѪÌõÖØµþ | ¶¯Ì¬µ÷Õû¼ä¾à | SetMonBloodPos X Y |
| ѪÌõÑÕÉ«Òì³£ | ËØ²ÄÉ«Óòģʽ´íÎó | ת»»ËزÄΪRGBģʽ£¨·ÇË÷ÒýÉ«£© |


---

### Áù¡¢¸ß½×Ó¦Óãº×Ô¶¨Ò嶯̬ѪÌõ

#### 1. **LUA½Å±¾¶¯Ì¬ÑªÌõ**
```lua
function DynamicBlood(monName)
local hpPer = GetMonHpPer(monName)
if hpPer > 70 then
SetBloodColor(0, 255, 0) -- ÂÌÉ«
elseif hpPer > 30 then
SetBloodColor(255, 255, 0) -- »ÆÉ«
else
SetBloodColor(255, 0, 0) -- ºìÉ«
end
end
```


#### 2. **¶à¶ÎѪÌõÌØÐ§**
ÔÚ`Blood.pak`ÖÐÅäÖöà×éѪÌõËØ²Ä£¬Í¨¹ý½Å±¾Çл»£º
```lua
[@OnMagicAttack]
#IF
CheckSkillName Áһ𽣷¨
CheckMonHpPer ³àÔ¶ñħ < 50
#ACT
SetMonBloodStyle ³àÔ¶ñħ 2 -- Çл»ÖÁµÚ¶þ×éѪÌõÑùʽ
```


---

#### ½áÓï
ͨ¹ý¾«×¼µÄÊý¾Ý¿âÅäÖá¢ËزĹ淶Óë½Å±¾¿ØÖÆ£¬GOMÒýÇæ¿ÉʵÏָ߶ȶ¨ÖƵÄBOSSѪÌõϵͳ¡£½¨Ò鿪·¢½×¶ÎʹÓÃ`@TestMonBlood`ÃüÁîʵʱµ÷ÊÔ£¬²¢ÀûÓÃ`Blood.pak`µÄ¶àËØ²Ä²ãʵÏֽ׶λ¯ÊÓ¾õ·´À¡¡£¶ÔÓÚ³¬±ä°æ±¾£¬¿É½áºÏ`RaceImg`Ó붯̬½Å±¾ÊµÏÖÐÎ̬±ä»¯ÑªÌõ£¨Èç½×¶Î±äÉí£©¡£

#### 1. ¹¦ÄܸÅÊö

##### BOSSѪÌõ
BOSSѪÌõÊÇÒ»ÖÖÏÔʾBOSSÉúÃüÖµµÄUIÔªËØ£¬Í¨³£Î»ÓÚÆÁÄ»ÉϵĹ̶¨Î»ÖûòBOSSÍ·¶¥ÉÏ·½¡£Ëü¿ÉÒÔ°ïÖúÍæ¼Òʵʱ¼à¿ØBOSSµÄÉúÃüÖµ±ä»¯£¬Ìá¸ßÕ½¶·µÄ½ôÕŸкͻ¥¶¯ÐÔ¡£

#### 2. GOMÒýÇæ¼ò½é

##### GOMÒýÇæÌØµã
- **¸ßЧÎȶ¨**£ºGOMÒýÇæÒÔÆä¸ßЧµÄ´¦ÀíÄÜÁ¦ºÍÎȶ¨µÄÔËÐбíÏÖÖø³Æ¡£
- **Ò×ÓÃÐÔÇ¿**£ºGOMÒýÇæÌṩÁ˼ò½àÃ÷Á˵ÄAPI½Ó¿Ú£¬·½±ã¿ª·¢Õß½øÐжþ´Î¿ª·¢¡£
- **¹¦ÄÜÈ«Ãæ**£ºÖ§³Ö¶àÖÖÓÎÏ·ÔªËØµÄÌí¼Ó£¬°üÀ¨µ«²»ÏÞÓÚ¼¼ÄÜ¡¢¹ÖÎï¡¢µØÍ¼µÈ¡£

##### Ö§³Ö×Ô¶¨Ò幦ÄÜ
GOMÒýÇæÔÊÐí¿ª·¢Õßͨ¹ýÐ޸ĴúÂëºÍÅäÖÃÎļþÀ´ÊµÏÖ¸÷ÖÖ×Ô¶¨Ò幦ÄÜ£¬°üÀ¨Ìí¼ÓBOSSѪÌõ¡£

#### 3. ʵÏÖBOSSѪÌõ²½Öè

##### ²½ÖèÒ»£º×¼±¸¹¤×÷
È·±£ÄãÒѾ­°²×°ÁËGOMÒýÇæ£¬²¢ÇÒÓÐÒ»¸ö»ù±¾µÄÓÎÏ·¿ò¼Ü´î½¨Íê³É¡£´ËÍ⣬»¹ÐèҪ׼±¸ºÃËùÓбØÒªµÄ¿Í»§¶ËºÍ·þÎñÆ÷¶ËÎļþ¡£

##### ²½Öè¶þ£º´´½¨BOSS½ÇÉ«

###### ÐÞ¸Ä`monster_table`
ÔÚÊý¾Ý¿âÖд´½¨Ò»¸öеıíÀ´´æ´¢¹ÖÎ°üÀ¨BOSS£©µÄÐÅÏ¢¡£

**´´½¨`monster_table`±í**
```sql
CREATE TABLE monster_table (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
type INT NOT NULL, -- ¹ÖÎïÀàÐÍ£¨ÈçÆÕͨ¹ÖÎï¡¢¾«Ó¢¹Ö¡¢BOSS£©
level INT NOT NULL, -- ¹ÖÎïµÈ¼¶
hp INT NOT NULL, -- ×î´óÉúÃüÖµ
mp INT NOT NULL, -- ×î´óħ·¨Öµ
attack INT NOT NULL, -- ¹¥»÷Á¦
defense INT NOT NULL, -- ·ÀÓùÁ¦
drop_items TEXT -- µôÂäÎïÆ·£¨JSON¸ñʽ£©
);
```

###### ²åÈëBOSSÊý¾Ý
²åÈëBOSSµÄʾÀýÊý¾ÝÒÔ±ã½øÐвâÊÔ¡£

**²åÈëBOSSÊý¾Ý**
```sql
INSERT INTO monster_table (name, type, level, hp, mp, attack, defense, drop_items) VALUES
('ºÚ°µÄ§¾ý', 3, 100, 10000, 5000, 500, 300, '{"items": [{"id": 1, "chance": 0.1}, {"id": 2, "chance": 0.05}]}');
```

##### ²½ÖèÈý£ºÅäÖÃBOSSЧ¹û

###### ÐÞ¸Ä`monster_config.txt`
ÔÚ`config\monster_config.txt`ÎļþÖÐÌí¼ÓBOSSµÄÏêϸЧ¹ûÅäÖá£

**monster_config.txt**
```ini
[Monster1]
Name=ºÚ°µÄ§¾ý
Type=3 -- BOSS
Level=100
HP=10000
MP=5000
Attack=500
Defense=300
DropItems={"items": [{"id": 1, "chance": 0.1}, {"id": 2, "chance": 0.05}]}
```

##### ²½ÖèËÄ£º±àдÏà¹ØÂß¼­´úÂë

###### ÐÞ¸Ä`monster_handler.cpp`
ÔÚ`src\monster_handler.cpp`ÎļþÖÐÌí¼Ó´¦ÀíBOSSѪÌõµÄ·½·¨¡£

**monster_handler.cpp**
```cpp
#include "monster_handler.h"
#include "map_manager.h"
#include "packet_builder.h"

MonsterHandler* MonsterHandler::GetInstance()
{
static MonsterHandler instance;
return &instance;
}

void MonsterHandler::SpawnMonster(int mapId, int monsterId, int x, int y)
{
DatabaseManager* dbManager = DatabaseManager::GetInstance();
std::string query = "SELECT name, type, level, hp, mp, attack, defense, drop_items FROM monster_table WHERE id = " + std::to_string(monsterId);
MYSQL_RES* result = dbManager->Query(query.c_str());
if (!result || mysql_num_rows(result) == 0)
{
SystemLog::LogWarning("Monster [%d] not found in database.", monsterId);
return;
}

MYSQL_ROW row = mysql_fetch_row(result);
std::string name = row[0];
int type = atoi(row[1]);
int level = atoi(row[2]);
int hp = atoi(row[3]);
int mp = atoi(row[4]);
int attack = atoi(row[5]);
int defense = atoi(row[6]);
std::string dropItems = row[7];
mysql_free_result(result);

// Create new monster object
Monster* monster = new Monster(mapId, monsterId, name, type, level, hp, mp, attack, defense, dropItems);
monster->SetPosition(x, y);

// Add monster to map manager
MapManager* mapManager = MapManager::GetInstance();
mapManager->AddMonster(monster);

// Send spawn packet to all players on the same map
CPacketBuilder response(PACKET_TYPE_MONSTER_SPAWN_RESPONSE);
response.WriteInt(monster->GetId());
response.WriteString(monster->GetName());
response.WriteInt(monster->GetType());
response.WriteInt(monster->GetX());
response.WriteInt(monster->GetY());
response.WriteInt(monster->GetCurrentHp());
response.WriteInt(monster->GetMaxHp());
mapManager->BroadcastToMap(response.Build(), mapId);

SystemLog::LogInfo("Spawned monster [%s] with ID [%d] at position (%d, %d) on map [%d].", name.c_str(), monster->GetId(), x, y, mapId);
}

void MonsterHandler::UpdateMonsterHealth(Monster* monster)
{
if (monster->IsDead())
{
HandleMonsterDeath(monster);
return;
}

CPacketBuilder response(PACKET_TYPE_MONSTER_HEALTH_UPDATE_RESPONSE);
response.WriteInt(monster->GetId());
response.WriteInt(monster->GetCurrentHp());
response.WriteInt(monster->GetMaxHp());

MapManager* mapManager = MapManager::GetInstance();
mapManager->BroadcastToMap(response.Build(), monster->GetMapId());

SystemLog::LogInfo("Updated health for monster [%s] with ID [%d]: Current HP: %d, Max HP: %d.", monster->GetName().c_str(), monster->GetId(), monster->GetCurrentHp(), monster->GetMaxHp());
}

void MonsterHandler::HandleMonsterDeath(Monster* monster)
{
CPacketBuilder response(PACKET_TYPE_MONSTER_DEATH_RESPONSE);
response.WriteInt(monster->GetId());

MapManager* mapManager = MapManager::GetInstance();
mapManager->BroadcastToMap(response.Build(), monster->GetMapId());

DropLoot(monster);

// Remove monster from map manager
mapManager->RemoveMonster(monster);

delete monster;

SystemLog::LogInfo("Monster [%s] with ID [%d] died.", monster->GetName().c_str(), monster->GetId());
}

void MonsterHandler::DropLoot(Monster* monster)
{
json dropJson = json::parse(monster->GetDropItems());
std::vector<Item*> droppedItems;

for (auto& itemData : dropJson["items"])
{
int itemId = itemData["id"];
double chance = itemData["chance"];

RandomGenerator* randomGen = RandomGenerator::GetInstance();
if (randomGen->GenerateDouble() <= chance)
{
Item* item = GenerateItem(itemId);
droppedItems.push_back(item);
}
}

if (!droppedItems.empty())
{
MapManager* mapManager = MapManager::GetInstance();
int centerX = monster->GetX();
int centerY = monster->GetY();

for (auto& item : droppedItems)
{
int x = centerX + randomGen->GenerateInt(-5, 5);
int y = centerY + randomGen->GenerateInt(-5, 5);
mapManager->SpawnItem(item, monster->GetMapId(), x, y);
}
}

SystemLog::LogInfo("Dropped loot for monster [%s] with ID [%d].", monster->GetName().c_str(), monster->GetId());
}
```

###### ÐÞ¸Ä`packet_builder.cpp`
ÔÚ`src\packet_builder.cpp`ÎļþÖÐÌí¼Ó¹¹½¨ÑªÌõ¸üаüµÄ·½·¨¡£

**packet_builder.cpp**
```cpp
#include "packet_builder.h"

CPacketBuilder::CPacketBuilder(uint8_t packetType)
{
m_packet.writeByte(packetType);
}

void CPacketBuilder::WriteByte(uint8_t value)
{
m_packet.writeByte(value);
}

void CPacketBuilder::WriteInt(int value)
{
m_packet.writeInt(value);
}

void CPacketBuilder::WriteString(const std::string& value)
{
m_packet.writeString(value);
}

Packet CPacketBuilder::Build()
{
return m_packet;
}
```

##### ²½ÖèÎ壺±àд¿Í»§¶ËÂß¼­

###### ÐÞ¸Ä`client_monster.cpp`
ÔÚ`src\client_monster.cpp`ÎļþÖÐÌí¼Ó´¦ÀíBOSSѪÌõµÄ·½·¨¡£

**client_monster.cpp**
```cpp
#include "client_monster.h"
#include "render_engine.h"
#include "ui_manager.h"

ClientMonster::ClientMonster(int id, const std::string& name, int type, int x, int y, int currentHp, int maxHp)
: m_id(id), m_name(name), m_type(type), m_x(x), m_y(y), m_currentHp(currentHp), m_maxHp(maxHp)
{
LoadTextures();
}

void ClientMonster::LoadTextures()
{
RenderEngine* renderEngine = RenderEngine::GetInstance();
if (m_type == MONSTER_TYPE_BOSS)
{
m_texture = renderEngine->LoadTexture("boss_health_bar.png");
}
else
{
m_texture = renderEngine->LoadTexture("monster_texture.png");
}
}

void ClientMonster::Draw()
{
RenderEngine* renderEngine = RenderEngine::GetInstance();
renderEngine->DrawSprite(m_texture, m_x, m_y);

if (m_type == MONSTER_TYPE_BOSS)
{
DrawHealthBar();
}
}

void ClientMonster::DrawHealthBar()
{
float healthPercentage = static_cast<float>(m_currentHp) / m_maxHp;
int barWidth = static_cast<int>(HEALTH_BAR_WIDTH * healthPercentage);
int barHeight = HEALTH_BAR_HEIGHT;

RenderEngine* renderEngine = RenderEngine::GetInstance();
renderEngine->DrawRectangle(m_x - HEALTH_BAR_WIDTH / 2, m_y - HEALTH_BAR_Y_OFFSET, HEALTH_BAR_WIDTH, HEALTH_BAR_HEIGHT, COLOR_GRAY);
renderEngine->DrawRectangle(m_x - HEALTH_BAR_WIDTH / 2, m_y - HEALTH_BAR_Y_OFFSET, barWidth, barHeight, COLOR_RED);

UIElement textElement;
textElement.type = UI_TEXT;
textElement.x = m_x - HEALTH_BAR_WIDTH / 2;
textElement.y = m_y - HEALTH_BAR_Y_OFFSET - 20;
textElement.text = m_name + ": " + std::to_string(m_currentHp) + "/" + std::to_string(m_maxHp);
textElement.color = COLOR_WHITE;

UIManager* uiManager = UIManager::GetInstance();
uiManager->AddElement(textElement);
}

void ClientMonster::UpdateHealth(int currentHp, int maxHp)
{
m_currentHp = currentHp;
m_maxHp = maxHp;
}

void ClientMonster::Die()
{
RenderEngine* renderEngine = RenderEngine::GetInstance();
renderEngine->PlayAnimation("death_animation.png", m_x, m_y);

// Remove from rendering list
// ...
}
```

###### ÐÞ¸Ä`render_engine.cpp`
ÔÚ`src\render_engine.cpp`ÎļþÖÐÌí¼Ó»æÖƾØÐκÍÎı¾µÄ·½·¨¡£

**render_engine.cpp**
```cpp
#include "render_engine.h"
#include <SDL.h>

RenderEngine* RenderEngine::GetInstance()
{
static RenderEngine instance;
return &instance;
}

bool RenderEngine::Initialize(SDL_Renderer* renderer)
{
m_renderer = renderer;
return true;
}

SDL_Texture* RenderEngine::LoadTexture(const std::string& filePath)
{
SDL_Surface* surface = IMG_Load(filePath.c_str());
if (!surface)
{
SystemLog::LogError("Failed to load texture: %s", filePath.c_str());
return nullptr;
}

SDL_Texture* texture = SDL_CreateTextureFromSurface(m_renderer, surface);
SDL_FreeSurface(surface);

if (!texture)
{
SystemLog::LogError("Failed to create texture from surface: %s", filePath.c_str());
return nullptr;
}

return texture;
}

void RenderEngine::DrawSprite(SDL_Texture* texture, int x, int y)
{
SDL_Rect destRect = {x, y, SPRITE_WIDTH, SPRITE_HEIGHT};
SDL_RenderCopy(m_renderer, texture, nullptr, &destRect);
}

void RenderEngine::DrawRectangle(int x, int y, int width, int height, uint32_t color)
{
SDL_SetRenderDrawColor(m_renderer, (color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, 255);
SDL_Rect rect = {x, y, width, height};
SDL_RenderFillRect(m_renderer, &rect);
}

void RenderEngine::DrawText(const std::string& text, int x, int y, uint32_t color)
{
TTF_Font* font = TTF_OpenFont("fonts/default.ttf", 24);
if (!font)
{
SystemLog::LogError("Failed to open font.");
return;
}

SDL_Color textColor = {(color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, 255};
SDL_Surface* textSurface = TTF_RenderText_Solid(font, text.c_str(), textColor);
if (!textSurface)
{
SystemLog::LogError("Failed to render text surface.");
TTF_CloseFont(font);
return;
}

SDL_Texture* textTexture = SDL_CreateTextureFromSurface(m_renderer, textSurface);
SDL_FreeSurface(textSurface);
if (!textTexture)
{
SystemLog::LogError("Failed to create text texture.");
TTF_CloseFont(font);
return;
}

SDL_Rect destRect = {x, y, textSurface->w, textSurface->h};
SDL_RenderCopy(m_renderer, textTexture, nullptr, &destRect);

SDL_DestroyTexture(textTexture);
TTF_CloseFont(font);
}

void RenderEngine::PlayAnimation(const std::string& animationPath, int x, int y)
{
// Animation logic here
}
```

##### ²½ÖèÁù£º±àÒë²¢²âÊÔ
È·±£ËùÓÐÐ޸ĺóµÄ´úÂë¶¼Äܳɹ¦±àÒë¡£

**±àÒë·þÎñÆ÷¶Ë**
```sh
g++ -o game_server src/game_server.cpp src/database_manager.cpp src/monster_handler.cpp src/packet_builder.cpp src/config_manager.cpp src/render_engine.cpp src/ui_manager.cpp -lengine -ljansson -lSDL2 -lSDL2_image -lSDL2_ttf
```

**±àÒë¿Í»§¶Ë**
```sh
g++ -o game_client src/game_client.cpp src/network_manager.cpp src/client_monster.cpp src/render_engine.cpp src/ui_manager.cpp -lengine -lSDL2 -lSDL2_image -lSDL2_ttf
```

Æô¶¯ÓÎÏ··þÎñÆ÷ºÍ¿Í»§¶Ë£¬¹Û²ìÕû¸öBOSSѪÌõÏÔʾÁ÷³ÌÊÇ·ñÕý³£¹¤×÷¡£

**Æô¶¯·þÎñÆ÷ÃüÁî**
```sh
start game_server.exe
start game_client.exe
```

##### ²½ÖèÆß£ºÑéÖ¤BOSSѪÌõЧ¹û

###### ²âÊÔBOSSѪÌõ
1. Æô¶¯ÓÎÏ··þÎñÆ÷¡£
2. ʹÓÿͻ§¶ËµÇ¼ÓÎÏ·¡£
3. ½øÈë°üº¬BOSSµÄµØÍ¼¡£
4. ¹Û²ìÊÇ·ñÄÜ¿´µ½BOSS¼°ÆäѪÌõ¡£
5. ¶ÔBOSSÔì³ÉÉ˺¦£¬¹Û²ìѪÌõÊÇ·ñÕýÈ·¸üС£
6. BOSSËÀÍöºó£¬¹Û²ìѪÌõÊÇ·ñÏûʧ¡£

**²âÊÔBOSSѪÌõÁ÷³Ì**
```plaintext
1. Æô¶¯ÓÎÏ··þÎñÆ÷¡£
2. ʹÓÿͻ§¶ËµÇ¼ÓÎÏ·¡£
3. ½øÈëÐÂÊÖ´åµØÍ¼¡£
4. ¹Û²ìÊÇ·ñÄÜ¿´µ½ÃûΪ“ºÚ°µÄ§¾ý”µÄBOSS¡£
5. ¹Û²ìBOSSÍ·¶¥ÊÇ·ñÓÐѪÌõÏÔʾ¡£
6. ¶ÔBOSSÔì³ÉÉ˺¦£¬¹Û²ìѪÌõÊÇ·ñÕýÈ·¼õÉÙ¡£
7. BOSSËÀÍöºó£¬¹Û²ìѪÌõÊÇ·ñÏûʧ¡£
```

#### 4. ÈÕÖ¾Îļþ¼ì²é

##### ²é¿´ÓÎÏ··þÎñÆ÷ÈÕÖ¾
´ò¿ªÓÎÏ··þÎñÆ÷µÄÈÕÖ¾Îļþ£¨Í¨³£Î»ÓÚ`log\game_server.log`£©£¬²éÕÒÏà¹ØµÄ´íÎóÐÅÏ¢¡£

**ÓÎÏ··þÎñÆ÷ÈÕ־ʾÀý**
```plaintext
[2023-10-01 12:34:56] INFO: Game server started on port 2107.
[2023-10-01 12:34:56] INFO: Connected to database successfully.
[2023-10-01 12:34:56] INFO: Spawned monster [ºÚ°µÄ§¾ý] with ID [1] at position (100, 100) on map [1].
[2023-10-01 12:34:56] INFO: Updated health for monster [ºÚ°µÄ§¾ý] with ID [1]: Current HP: 9500, Max HP: 10000.
[2023-10-01 12:34:56] INFO: Monster [ºÚ°µÄ§¾ý] with ID [1] died.
```

¸ù¾ÝÈÕÖ¾ÖеÄÐÅÏ¢£¬È·ÈÏÓÎÏ··þÎñÆ÷ÊÇ·ñÕý³£ÔËÐÐÒÔ¼°BOSSѪÌõµÄÏÔʾºÍ¸üвÙ×÷ÊÇ·ñÕýÈ·Ö´ÐС£

##### ²é¿´¿Í»§¶ËÈÕÖ¾
´ò¿ª¿Í»§¶ËµÄÈÕÖ¾Îļþ£¨Í¨³£Î»ÓÚ`log\game_client.log`£©£¬²éÕÒÏà¹ØµÄ´íÎóÐÅÏ¢¡£

**¿Í»§¶ËÈÕ־ʾÀý**
```plaintext
[2023-10-01 12:34:56] INFO: Connecting to game server at 127.0.0.1:2107.
[2023-10-01 12:34:56] INFO: Connected to game server at 127.0.0.1:2107.
[2023-10-01 12:34:56] INFO: Logged in as testuser.
[2023-10-01 12:34:56] INFO: Entered map [ÐÂÊÖ´å].
[2023-10-01 12:34:56] INFO: Spawned monster [ºÚ°µÄ§¾ý] with ID [1] at position (100, 100).
[2023-10-01 12:34:56] INFO: Updated health for monster [ºÚ°µÄ§¾ý] with ID [1]: Current HP: 9500, Max HP: 10000.
[2023-10-01 12:34:56] INFO: Monster [ºÚ°µÄ§¾ý] with ID [1] died.
```

¸ù¾ÝÈÕÖ¾ÖеÄÐÅÏ¢£¬È·ÈϿͻ§¶ËÊÇ·ñÕýÈ·½ÓÊÕÁË·þÎñÆ÷µÄÏìÓ¦²¢ÇÒÏÔʾÁËÏàÓ¦µÄ½á¹û¡£

#### 5. ³£¼ûÎÊÌâ¼°½â¾ö·½°¸

##### ÎÊÌâÒ»£ºÎÞ·¨Á¬½Óµ½ÓÎÏ··þÎñÆ÷
- **¼ì²éÍøÂçÉèÖÃ**£ºÈ·±£¿Í»§¶ËºÍÓÎÏ··þÎñÆ÷Ö®¼äµÄÍøÂçÁ¬½ÓÕý³£¡£
- **¼ì²éÅäÖÃÎļþ**£ºÈ·±£`client_config.txt`ÖеÄÓÎÏ··þÎñÆ÷IPºÍ¶Ë¿ÚÅäÖÃÕýÈ·¡£
- **¼ì²é·À»ðǽÉèÖÃ**£ºÈ·±£·À»ðǽûÓÐ×èÖ¹ÓÎÏ··þÎñÆ÷µÄ¶Ë¿Ú¡£

##### ÎÊÌâ¶þ£ºµÇ¼ʧ°Ü
- **¼ì²éÊý¾Ý¿âÅäÖÃ**£ºÈ·±£`game_config.txt`ÖеÄÊý¾Ý¿âÅäÖÃÕýÈ·¡£
- **¼ì²éÊý¾Ý¿â·þÎñ**£ºÈ·±£Êý¾Ý¿â·þÎñÕýÔÚÔËÐв¢ÇÒ¿ÉÒÔ·ÃÎÊ¡£
- **¼ì²éÓû§Êý¾Ý**£ºÈ·±£`account_table`Öаüº¬ÕýÈ·µÄÓû§ÐÅÏ¢¡£

##### ÎÊÌâÈý£º½ÇÉ«¼ÓÔØÊ§°Ü
- **¼ì²é½ÇÉ«Êý¾Ý**£ºÈ·±£`char_table`Öаüº¬ÕýÈ·µÄ½ÇÉ«ÐÅÏ¢¡£
- **¼ì²éÎïÆ·Êý¾Ý**£ºÈ·±£`item_table`Öаüº¬ÕýÈ·µÄÎïÆ·ÐÅÏ¢¡£
- **¼ì²é¼¼ÄÜÊý¾Ý**£ºÈ·±£`skill_table`Öаüº¬ÕýÈ·µÄ¼¼ÄÜÐÅÏ¢¡£

##### ÎÊÌâËÄ£º¿Í»§¶Ë°æ±¾²»Æ¥Åä
- **¸üпͻ§¶Ë**£ºÈ·±£¿Í»§¶Ë°æ±¾Óë·þÎñÆ÷°æ±¾¼æÈÝ¡£
- **ͬ²½×ÊÔ´Îļþ**£ºÈ·±£¿Í»§¶ËºÍ·þÎñÆ÷Ö®¼äµÄ×ÊÔ´ÎļþÒ»Ö¡£

##### ÎÊÌâÎ壺BOSSδÏÔʾÔÚµØÍ¼ÉÏ
- **¼ì²é¹ÖÎï×ø±ê**£ºÈ·±£`monster_script.lua`Öж¨ÒåµÄBOSS×ø±êÔÚµØÍ¼·¶Î§ÄÚ¡£
- **¼ì²éµØÍ¼Îļþ**£ºÈ·±£µØÍ¼Îļþ£¨`.pak`£©Öаüº¬ÁËBOSSµÄÏà¹ØÊý¾Ý¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´`game_server.log`ÖеľßÌå´íÎóÐÅÏ¢£¬ÒԱ㶨λÎÊÌâ¡£

##### ÎÊÌâÁù£ºBOSSѪÌõδÏÔʾÔÚ¿Í»§¶Ë
- **¼ì²é¿Í»§¶ËÅäÖÃ**£ºÈ·±£¿Í»§¶ËÅäÖÃÕýÈ·£¬²¢ÇÒÄܹ»ÕýÈ·½ÓÊÕ·þÎñÆ÷·¢Ë͵ÄÊý¾Ý¡£
- **¼ì²é½Å±¾Âß¼­**£ºÈ·±£`monster_handler.cpp`Öж¨ÒåµÄѪÌõÂß¼­ÕýÈ·ÎÞÎó¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´`game_client.log`ÖеľßÌå´íÎóÐÅÏ¢£¬ÒԱ㶨λÎÊÌâ¡£

##### ÎÊÌâÆß£ºÑªÌõ¸üв»¼°Ê±
- **¼ì²éÍøÂçÑÓ³Ù**£ºÈ·±£ÍøÂçÑӳٽϵͣ¬ÒÔ±£Ö¤·þÎñÆ÷ºÍ¿Í»§¶ËÖ®¼äµÄͨÐÅ˳³©¡£
- **ÓÅ»¯¸üÐÂÆµÂÊ**£ºÊʵ±µ÷ÕûѪÌõ¸üÐÂµÄÆµÂÊ£¬±ÜÃâ¹ýÓÚÆµ·±µ¼ÖÂÐÔÄÜϽµ¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´`game_server.log`ºÍ`game_client.log`ÖеľßÌå´íÎóÐÅÏ¢£¬ÒԱ㶨λÎÊÌâ¡£

##### ÎÊÌâ°Ë£ºÑªÌõÑÕÉ«²»ÕýÈ·
- **¼ì²éÑÕÉ«ÉèÖÃ**£ºÈ·±£`client_monster.cpp`Öж¨ÒåµÄÑÕɫֵÕýÈ·¡£
- **¼ì²éÎÆÀíÎļþ**£ºÈ·±£Ê¹ÓõÄÎÆÀíÎļþ£¨Èç`boss_health_bar.png`£©·ûºÏÔ¤ÆÚµÄÑÕÉ«·½°¸¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´`game_client.log`ÖеľßÌå´íÎóÐÅÏ¢£¬ÒԱ㶨λÎÊÌâ¡£

##### ÎÊÌâ¾Å£ºÑªÌõÕÚµ²ÆäËûUIÔªËØ
- **µ÷Õû²ã¼¶**£ºÈ·±£ÑªÌõµÄ»æÖƲ㼶µÍÓÚÆäËûÖØÒªµÄUIÔªËØ¡£
- **µ÷ÕûλÖÃ**£ºÊʵ±µ÷ÕûѪÌõµÄλÖã¬Ê¹Æä²»»áÕÚµ²ÆäËûÖØÒªÐÅÏ¢¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´`game_client.log`ÖеľßÌå´íÎóÐÅÏ¢£¬ÒԱ㶨λÎÊÌâ¡£

##### ÎÊÌâÊ®£ºÄÚ´æÐ¹Â©
- **¼ì²éÄÚ´æ¹ÜÀí**£ºÈ·±£·þÎñÆ÷¶Ë´úÂëÖÐûÓÐÄÚ´æÐ¹Â©µÄÎÊÌâ¡£
- **ʹÓõ÷ÊÔ¹¤¾ß**£ºÊ¹ÓÃValgrindµÈ¹¤¾ß¼ì²éÄÚ´æÐ¹Â©Çé¿ö¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´`game_server.log`ÖеľßÌå´íÎóÐÅÏ¢£¬ÒԱ㶨λÎÊÌâ¡£

#### 6. ×ܽá
ͨ¹ýÒÔÉϲ½Ö裬ÄãÓ¦¸ÃÄܹ»ÔÚGOM´«ÆæÒýÇæÖгɹ¦ÎªBOSSÌí¼ÓѪÌõ¡£Õâ²»½öÌáÉýÁËÓÎÏ·µÄÊÓ¾õЧ¹û£¬»¹ÔöÇ¿ÁËÍæ¼ÒµÄÓÎÏ·ÌåÑ顣ϣÍûÕâÆª½Ì³Ì¶ÔÄãÓÐËù°ïÖú£¡