ÔÚGOMÒýÇæÖУ¬Áé»ê»ð·ûĬÈϽö¹¥»÷µ¥¸öÄ¿±ê£¬µ«Í¨¹ý**¼¼ÄÜ»úÖÆÖØ¹¹**¡¢**¹¥»÷Âß¼½Å±¾»¯**Óë**¿Í»§¶ËÌØÐ§¸ÄÔì**£¬¿ÉʵÏÖͬʱ´ò»÷×î¶à8¸öÄ¿±êµÄAOEЧ¹û¡£±¾ÎÄÌṩ´Ó»ù´¡µ½½ø½×µÄÈýÖÖʵÏÖ·½°¸£¬º¸ÇÔÉúÅäÖá¢LUAÀ©Õ¹Óë²å¼þÇ¿»¯¡£
---
### Ò»¡¢Êý¾Ý¿â²ã¸ÄÔ죺¶àÄ¿±ê²ÎÊýµ÷Õû
#### 1. **Magic.DB¹Ø¼ü×Ö¶Î**
| ×Ö¶ÎÃû | ˵Ã÷ | ¶àÄ¿±ê²ÎÊýʾÀý |
|----------------|------------------------|------------|
| **TargetCount**| ×î´ó¹¥»÷Ä¿±êÊý | 3 → 8 |
| **Range** | ¹¥»÷·¶Î§£¨¸ñÊý£© | 2 → 4 |
| **Splash** | ÊÇ·ñÆôÓý¦É䣨0/1£© | 0 → 1 |
**²Ù×÷²½Öè**£º
1. ÓÃDBC¹¤¾ß´ò¿ª`Magic.DB`£¬ÕÒµ½Áé»ê»ð·ûÐУ¨Í¨³£MagID=22£©¡£
2. ÐÞ¸Ä`TargetCount=8`£¬`Range=4`£¬`Splash=1`¡£
3. ÖØÆôM2Server»òÖ´ÐÐ`@ReloadMagicDB`¡£
---
### ¶þ¡¢½Å±¾¼¶À©Õ¹£º¶¯Ì¬Ä¿±ê¼ì²â
#### 1. **QFunction-0.txt´¥·¢Âß¼**
```lua
[@MagTagFunc22] -- 22ΪÁé»ê»ð·ûMagID
#ACT
; »ñÈ¡µ±Ç°Ä¿±ê×ø±ê
GetTargetPos <$CURRRTARGETX> <$CURRRTARGETY>
; ±éÀúÖÜΧ3x3·¶Î§
For 8 0
GetAroundPos <$CURRRTARGETX> <$CURRRTARGETY> <$CURRENTCOUNT> 3
#IF
CheckRangeMonsterCount <$CURRENTX> <$CURRENTY> 2 > 0
#ACT
HITMON <$CURRENTX> <$CURRENTY> 1 100 ; ¶Ôÿ¸öÄ¿±êÔì³É100%É˺¦
```
#### 2. **É˺¦Ë¥¼õ»úÖÆ**
```lua
#IF
CheckDistance <$CURRRTARGETX> <$CURRRTARGETY> <$CURRENTX> <$CURRENTY> > 2
#ACT
CALCVAR N1 = 100 - (<$DISTANCE> * 20) -- ÿ¸ñË¥¼õ20%
HITMON <$CURRENTX> <$CURRENTY> 1 <$STR(N1)>
```
---
### Èý¡¢¿Í»§¶ËÌØÐ§ÊÊÅä
#### 1. **¶àµ¯µÀÌØÐ§ÊµÏÖ**
1. ¸´ÖÆ`EffectEx.wil`Áé»ê»ð·ûËØ²Ä£¨Ô±àºÅ500-600Ö¡£©¡£
2. ÐÂÔö8·½Ïò·ÖÁÑÌØÐ§£¨±àºÅ601-680£©£¬Ã¿¸ö·½Ïò10Ö¡¡£
3. ÔڵǼÆ÷ÅäÖÃÖаó¶¨ÐÂËØ²Ä£º
```ini
[MagicEffect]
Áé»ê»ð·û·ÖÁÑ=601,680
```
#### 2. **¶¯Ì¬µ¯µÀ¿ØÖÆ£¨LUA£©**
```lua
function OnFireSplit(x, y)
for i=1,8 do
local angle = (i-1)*45
local dx = x + 4*math.cos(math.rad(angle))
local dy = y + 4*math.sin(math.rad(angle))
CreateEffect(601 + (i-1)*10, dx, dy)
end
end
```
---
### ËÄ¡¢ÐÔÄÜÓÅ»¯·½°¸
#### 1. **Ä¿±êÊýÏÞÖÆ**
```lua
#IF
CheckMapPlayerCount > 50 -- ¸ß¸ºÔصØÍ¼
#ACT
SetVar MaxTargets = 4 -- ÏÞÖÆ×î´óÄ¿±êÊý
#ELSEACT
SetVar MaxTargets = 8
```
#### 2. **É˺¦¼ÆËãÅú´¦Àí**
```lua
HITMON_MULTI <$X> <$Y> 4 8 1 100 -- ·¶Î§4¸ñ£¬×î¶à8Ä¿±ê
```
---
### Îå¡¢²âÊÔÓëµ÷ÊÔÃüÁî
#### 1. **ʵʱµ¯µÀ×·×Ù**
```lua
@DebugMagic 22 -- ÏÔʾÁé»ê»ð·û¹¥»÷·¾¶
```
#### 2. **GMѹÁ¦²âÊÔ**
```lua
@Make µ¾²ÝÈË 20 -- Éú³É20¸ö²âÊÔÄ¿±ê
@SetSkillLevel Áé»ê»ð·û 7
@Cast 22 -- Á¬ÐøÊͷż¼ÄÜ
```
---
### Áù¡¢¸ßƵÎÊÌâ½â¾ö·½°¸
| **ÎÊÌâÏÖÏó** | **ÔÒò** | **½â¾ö·½°¸** |
|--------------------------|-----------------------|--------------------------------|
| ¶àÄ¿±êÉ˺¦²»ÉúЧ | SplashδÆôÓà | ¼ì²éMagic.DBµÄSplash×Ö¶ÎÊÇ·ñΪ1 |
| ¿Í»§¶ËÌØÐ§´íλ | ×ø±ê¼ÆËãδȡÕû | ÔÚLUAÖÐʹÓÃmath.floor(dx)´¦Àí×ø±ê |
| ÐÔÄÜ¿¨¶Ù | Ä¿±êÊý¹ý¶à | ÔÚQManage.txtÖÐÔö¼ÓCheckMapPlayerCountÌõ¼þ |
| ²¿·Ö·½ÏòÎÞÉ˺¦ | GetAroundPos²ÎÊý´íÎó | ½«·¶Î§´Ó3¸ÄΪ4²¢¼ì²é×ø±êÆ«ÒÆÁ¿ |
---
#### ½áÓï
ͨ¹ýÊý¾Ý¿â¡¢½Å±¾Óë¿Í»§¶ËµÄÁªºÏ¸ÄÔ죬Áé»ê»ð·û¿É»¯ÉíµÀÊ¿µÄAOEÉñ¼¼¡£½¨Òé²ÉÓÓ½¥½øÊ½Ç¿»¯”²ßÂÔ£ºÏÈʵÏÖ»ù´¡¶àÄ¿±ê£¬ÔÙÌí¼ÓÉ˺¦Ë¥¼õÓëÌØÐ§£¬×îºó½øÐÐÐÔÄÜÓÅ»¯¡£×¢Òâ±£³Ö¼¼ÄÜÆ½ºâ——¿Éͨ¹ý½µµÍȺÌåÉ˺¦ÏµÊý£¨Èç70%µÝ¼õ£©»òÔö¼Óħ·¨ÏûºÄÀ´Î¬³ÖÖ°ÒµÉú̬¡£²âÊÔ½×¶ÎÎñ±ØÊ¹ÓÃ@DebugMagicÃüÁîÑé֤ÿ¸öµ¯µÀµÄÃüÖÐÅж¨¡£
#### 1. ¹¦ÄܸÅÊö
##### “Áé»ê»ð·û”
“Áé»ê»ð·û”ÊÇÒ»ÖÖÇ¿´óµÄħ·¨¼¼ÄÜ£¬Äܹ»Í¬Ê±¶Ô¶à¸öµÐÈËÔì³É»ðÑæÉ˺¦¡£Í¨¹ýʵÏÖÕâÒ»¼¼ÄÜ£¬¿ÉÒÔÊ¹Íæ¼ÒÔÚÓÎÏ·ÖÐÓµÓиü¶àµÄÕ½ÊõÑ¡ÔñºÍÕ½¶·²ßÂÔ¡£
#### 2. GOMÒýÇæ¼ò½é
##### GOMÒýÇæÌØµã
- **¸ßЧÎȶ¨**£ºGOMÒýÇæÒÔÆä¸ßЧµÄ´¦ÀíÄÜÁ¦ºÍÎȶ¨µÄÔËÐбíÏÖÖø³Æ¡£
- **Ò×ÓÃÐÔÇ¿**£ºGOMÒýÇæÌṩÁ˼ò½àÃ÷Á˵ÄAPI½Ó¿Ú£¬·½±ã¿ª·¢Õß½øÐжþ´Î¿ª·¢¡£
- **¹¦ÄÜÈ«Ãæ**£ºÖ§³Ö¶àÖÖÓÎÏ·ÔªËØµÄÌí¼Ó£¬°üÀ¨µ«²»ÏÞÓÚ¼¼ÄÜ¡¢¹ÖÎï¡¢µØÍ¼µÈ¡£
##### Ö§³Ö×Ô¶¨Ò幦ÄÜ
GOMÒýÇæÔÊÐí¿ª·¢Õßͨ¹ýÐ޸ĴúÂëºÍÅäÖÃÎļþÀ´ÊµÏÖ¸÷ÖÖ×Ô¶¨Ò幦ÄÜ£¬°üÀ¨ÐÂÔö¶àÄ¿±ê¹¥»÷¼¼ÄÜ¡£
#### 3. ʵÏÖ“Áé»ê»ð·û”¶àÄ¿±ê¹¥»÷²½Öè
##### ²½ÖèÒ»£º×¼±¸¹¤×÷
È·±£ÄãÒѾ°²×°ÁËGOMÒýÇæ£¬²¢ÇÒÓÐÒ»¸ö»ù±¾µÄÓÎÏ·¿ò¼Ü´î½¨Íê³É¡£´ËÍ⣬»¹ÐèҪ׼±¸ºÃËùÓбØÒªµÄ¿Í»§¶ËºÍ·þÎñÆ÷¶ËÎļþ¡£
##### ²½Öè¶þ£º´´½¨“Áé»ê»ð·û”¼¼ÄÜ
###### ÐÞ¸Ä`skill_table`
ÔÚÊý¾Ý¿âÖд´½¨Ò»¸öеıíÀ´´æ´¢¼¼ÄܵÄÐÅÏ¢¡£
**´´½¨`skill_table`±í**
```sql
CREATE TABLE skill_table (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
type INT NOT NULL, -- ¼¼ÄÜÀàÐÍ£¨ÈçÎïÀí¹¥»÷¡¢Ä§·¨¹¥»÷¡¢¸¨Öú¼¼Äܵȣ©
mana_cost INT NOT NULL, -- ħ·¨ÏûºÄ
cooldown INT NOT NULL, -- Àäȴʱ¼ä
range INT NOT NULL, -- Ê©·Å·¶Î§
effect TEXT -- ¼¼ÄÜЧ¹û£¨JSON¸ñʽ£©
);
```
###### ²åÈë“Áé»ê»ð·û”Êý¾Ý
²åÈë“Áé»ê»ð·û”µÄʾÀýÊý¾ÝÒÔ±ã½øÐвâÊÔ¡£
**²åÈë“Áé»ê»ð·û”Êý¾Ý**
```sql
INSERT INTO skill_table (name, type, mana_cost, cooldown, range, effect) VALUES
('Áé»ê»ð·û', 2, 50, 10, 5, '{"damage": 100, "targets": 3}');
```
##### ²½ÖèÈý£ºÅäÖü¼ÄÜЧ¹û
###### ÐÞ¸Ä`skill_config.txt`
ÔÚ`config\skill_config.txt`ÎļþÖÐÌí¼Ó“Áé»ê»ð·û”µÄÏêϸЧ¹ûÅäÖá£
**skill_config.txt**
```ini
[Skill1]
Name=Áé»ê»ð·û
Type=2 -- ħ·¨¹¥»÷
ManaCost=50
Cooldown=10
Range=5
Effect={"damage": 100, "targets": 3}
```
##### ²½ÖèËÄ£º±àдÏà¹ØÂß¼´úÂë
###### ÐÞ¸Ä`skill_handler.cpp`
ÔÚ`src\skill_handler.cpp`ÎļþÖÐÌí¼Ó´¦Àí“Áé»ê»ð·û”¶àÄ¿±ê¹¥»÷µÄÂß¼¡£
**skill_handler.cpp**
```cpp
#include "skill_handler.h"
#include "character.h"
#include "monster_handler.h"
#include "random_generator.h"
#include "packet_builder.h"
SkillHandler* SkillHandler::GetInstance()
{
static SkillHandler instance;
return &instance;
}
void SkillHandler::UseSkill(Character* character, int skillId)
{
ConfigManager* configManager = ConfigManager::GetInstance();
std::string skillConfig = configManager->GetSkillConfig(skillId);
// Parse skill configuration
json skillJson = json::parse(skillConfig);
std::string skillName = skillJson["Name"];
int skillType = skillJson["Type"];
int manaCost = skillJson["ManaCost"];
int cooldown = skillJson["Cooldown"];
int range = skillJson["Range"];
json effectJson = skillJson["Effect"];
if (character->GetMana() < manaCost)
{
CPacketBuilder response(PACKET_TYPE_SKILL_USE_RESPONSE);
response.WriteByte(SKILL_USE_FAILURE_NOT_ENOUGH_MANA);
character->SendPacket(response.Build());
SystemLog::LogWarning("Character [%d] does not have enough mana to use skill [%s].", character->GetId(), skillName.c_str());
return;
}
if (character->IsOnCooldown(skillId))
{
CPacketBuilder response(PACKET_TYPE_SKILL_USE_RESPONSE);
response.WriteByte(SKILL_USE_FAILURE_COOLDOWN);
character->SendPacket(response.Build());
SystemLog::LogWarning("Character [%d] is on cooldown for skill [%s].", character->GetId(), skillName.c_str());
return;
}
character->SubtractMana(manaCost);
character->SetCooldown(skillId, cooldown);
int damage = effectJson["damage"];
int targets = effectJson["targets"];
MonsterHandler* monsterHandler = MonsterHandler::GetInstance();
RandomGenerator* randomGen = RandomGenerator::GetInstance();
std::vector<Monster*> nearbyMonsters = monsterHandler->GetNearbyMonsters(character, range);
if (nearbyMonsters.empty())
{
CPacketBuilder response(PACKET_TYPE_SKILL_USE_RESPONSE);
response.WriteByte(SKILL_USE_FAILURE_NO_TARGETS);
character->SendPacket(response.Build());
SystemLog::LogWarning("No monsters found within range for skill [%s] by character [%d].", skillName.c_str(), character->GetId());
return;
}
std::shuffle(nearbyMonsters.begin(), nearbyMonsters.end(), randomGen->GetEngine());
int numTargetsHit = std::min(targets, static_cast<int>(nearbyMonsters.size()));
for (int i = 0; i < numTargetsHit; ++i)
{
Monster* target = nearbyMonsters[i];
target->TakeDamage(damage);
CPacketBuilder response(PACKET_TYPE_MONSTER_DAMAGE_RESPONSE);
response.WriteInt(target->GetId());
response.WriteInt(damage);
character->SendPacket(response.Build());
SystemLog::LogInfo("Character [%d] used skill [%s] on monster [%s], dealing %d damage.", character->GetId(), skillName.c_str(), target->GetName().c_str(), damage);
}
CPacketBuilder response(PACKET_TYPE_SKILL_USE_RESPONSE);
response.WriteByte(SKILL_USE_SUCCESS);
character->SendPacket(response.Build());
SystemLog::LogInfo("Character [%d] successfully used skill [%s] and hit %d targets.", character->GetId(), skillName.c_str(), numTargetsHit);
}
```
###### ÐÞ¸Ä`monster_handler.cpp`
ÔÚ`src\monster_handler.cpp`ÎļþÖÐÌí¼Ó»ñÈ¡¸½½ü¹ÖÎïµÄ·½·¨¡£
**monster_handler.cpp**
```cpp
#include "monster_handler.h"
#include "map_manager.h"
#include "distance_calculator.h"
MonsterHandler* MonsterHandler::GetInstance()
{
static MonsterHandler instance;
return &instance;
}
std::vector<Monster*> MonsterHandler::GetNearbyMonsters(Character* character, int range)
{
MapManager* mapManager = MapManager::GetInstance();
DistanceCalculator* distanceCalc = DistanceCalculator::GetInstance();
std::vector<Monster*> allMonsters = mapManager->GetAllMonstersInMap(character->GetCurrentMapId());
std::vector<Monster*> nearbyMonsters;
for (auto& monster : allMonsters)
{
double distance = distanceCalc->CalculateDistance(character->GetPositionX(), character->GetPositionY(), monster->GetPositionX(), monster->GetPositionY());
if (distance <= range && !monster->IsDead())
{
nearbyMonsters.push_back(monster);
}
}
return nearbyMonsters;
}
```
##### ²½ÖèÎ壺±àÒë²¢²âÊÔ
È·±£ËùÓÐÐ޸ĺóµÄ´úÂë¶¼Äܳɹ¦±àÒë¡£
**±àÒë·þÎñÆ÷¶Ë**
```sh
g++ -o game_server src/game_server.cpp src/database_manager.cpp src/skill_handler.cpp src/monster_handler.cpp src/item_handler.cpp src/inventory.cpp src/character.cpp src/packet_builder.cpp src/config_manager.cpp src/random_generator.cpp src/map_manager.cpp src/distance_calculator.cpp -lengine -ljansson
```
Æô¶¯ÓÎÏ··þÎñÆ÷ºÍ¿Í»§¶Ë£¬¹Û²ìÕû¸ö“Áé»ê»ð·û”¶àÄ¿±ê¹¥»÷Á÷³ÌÊÇ·ñÕý³£¹¤×÷¡£
**Æô¶¯·þÎñÆ÷ÃüÁî**
```sh
start game_server.exe
start client.exe
```
##### ²½ÖèÁù£ºÑéÖ¤“Áé»ê»ð·û”¶àÄ¿±ê¹¥»÷Ч¹û
###### ²âÊÔ“Áé»ê»ð·û”¶àÄ¿±ê¹¥»÷
1. Æô¶¯ÓÎÏ··þÎñÆ÷¡£
2. ʹÓÿͻ§¶ËµÇ¼ÓÎÏ·¡£
3. ѧϰ»ò×°±¸“Áé»ê»ð·û”¼¼ÄÜ¡£
4. ¶Ô¶à¸ö¹ÖÎïÊ©·Å“Áé»ê»ð·û”£¬¼ì²éÊÇ·ñÕýÈ·¶Ô¶à¸öÄ¿±êÔì³ÉÉ˺¦¡£
**²âÊÔ“Áé»ê»ð·û”¶àÄ¿±ê¹¥»÷Á÷³Ì**
```plaintext
1. ½øÈëÓÎÏ·ºó£¬Ñ§Ï°»ò×°±¸“Áé»ê»ð·û”¼¼ÄÜ¡£
2. ѰÕÒ¶à¸ö¹ÖÎï¾Û¼¯µÄµØ·½¡£
3. ¶Ô¶à¸ö¹ÖÎïÊ©·Å“Áé»ê»ð·û”¡£
4. ¹Û²ìÊÇ·ñÓжà¸ö¹ÖÎïÊܵ½É˺¦¡£
```
#### 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: Character [1] logged in.
[2023-10-01 12:34:56] INFO: Character [1] learned skill [Áé»ê»ð·û].
[2023-10-01 12:34:56] INFO: Character [1] used skill [Áé»ê»ð·û] on monster [Ò°ÀÇ], dealing 100 damage.
[2023-10-01 12:34:56] INFO: Character [1] used skill [Áé»ê»ð·û] on monster [ÓÄÁéÆïÊ¿], dealing 100 damage.
[2023-10-01 12:34:56] INFO: Character [1] successfully used skill [Áé»ê»ð·û] and hit 2 targets.
```
¸ù¾ÝÈÕÖ¾ÖеÄÐÅÏ¢£¬È·ÈÏÓÎÏ··þÎñÆ÷ÊÇ·ñÕý³£ÔËÐÐÒÔ¼°“Áé»ê»ð·û”µÄ¶àÄ¿±ê¹¥»÷²Ù×÷ÊÇ·ñÕýÈ·Ö´ÐС£
##### ²é¿´¿Í»§¶ËÈÕÖ¾
´ò¿ª¿Í»§¶ËµÄÈÕÖ¾Îļþ£¨Í¨³£Î»ÓÚ`log\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: Learned skill [Áé»ê»ð·û].
[2023-10-01 12:34:56] INFO: Used skill [Áé»ê»ð·û] on monster [Ò°ÀÇ], dealing 100 damage.
[2023-10-01 12:34:56] INFO: Used skill [Áé»ê»ð·û] on monster [ÓÄÁéÆïÊ¿], dealing 100 damage.
[2023-10-01 12:34:56] INFO: Successfully used skill [Áé»ê»ð·û] and hit 2 targets.
```
¸ù¾ÝÈÕÖ¾ÖеÄÐÅÏ¢£¬È·ÈϿͻ§¶ËÊÇ·ñÕýÈ·½ÓÊÕÁË·þÎñÆ÷µÄÏìÓ¦²¢ÇÒÏÔʾÁËÏàÓ¦µÄ½á¹û¡£
#### 5. ³£¼ûÎÊÌâ¼°½â¾ö·½°¸
##### ÎÊÌâÒ»£ºÎÞ·¨Á¬½Óµ½ÓÎÏ··þÎñÆ÷
- **¼ì²éÍøÂçÉèÖÃ**£ºÈ·±£¿Í»§¶ËºÍÓÎÏ··þÎñÆ÷Ö®¼äµÄÍøÂçÁ¬½ÓÕý³£¡£
- **¼ì²éÅäÖÃÎļþ**£ºÈ·±£`client_config.txt`ÖеÄÓÎÏ··þÎñÆ÷IPºÍ¶Ë¿ÚÅäÖÃÕýÈ·¡£
- **¼ì²é·À»ðǽÉèÖÃ**£ºÈ·±£·À»ðǽûÓÐ×èÖ¹ÓÎÏ··þÎñÆ÷µÄ¶Ë¿Ú¡£
##### ÎÊÌâ¶þ£ºµÇ¼ʧ°Ü
- **¼ì²éÊý¾Ý¿âÅäÖÃ**£ºÈ·±£`game_config.txt`ÖеÄÊý¾Ý¿âÅäÖÃÕýÈ·¡£
- **¼ì²éÊý¾Ý¿â·þÎñ**£ºÈ·±£Êý¾Ý¿â·þÎñÕýÔÚÔËÐв¢ÇÒ¿ÉÒÔ·ÃÎÊ¡£
- **¼ì²éÓû§Êý¾Ý**£ºÈ·±£`account_table`Öаüº¬ÕýÈ·µÄÓû§ÐÅÏ¢¡£
##### ÎÊÌâÈý£º½ÇÉ«¼ÓÔØÊ§°Ü
- **¼ì²é½ÇÉ«Êý¾Ý**£ºÈ·±£`char_table`Öаüº¬ÕýÈ·µÄ½ÇÉ«ÐÅÏ¢¡£
- **¼ì²éÎïÆ·Êý¾Ý**£ºÈ·±£`item_table`Öаüº¬ÕýÈ·µÄÎïÆ·ÐÅÏ¢¡£
- **¼ì²é¼¼ÄÜÊý¾Ý**£ºÈ·±£`skill_table`Öаüº¬ÕýÈ·µÄ¼¼ÄÜÐÅÏ¢¡£
##### ÎÊÌâËÄ£º¿Í»§¶Ë°æ±¾²»Æ¥Åä
- **¸üпͻ§¶Ë**£ºÈ·±£¿Í»§¶Ë°æ±¾Óë·þÎñÆ÷°æ±¾¼æÈÝ¡£
- **ͬ²½×ÊÔ´Îļþ**£ºÈ·±£¿Í»§¶ËºÍ·þÎñÆ÷Ö®¼äµÄ×ÊÔ´ÎļþÒ»Ö¡£
##### ÎÊÌâÎ壺¼¼ÄÜδѧϰ»ò×°±¸
- **¼ì²é¼¼ÄÜÅäÖÃ**£ºÈ·±£`skill_config.txt`Öеļ¼ÄÜÅäÖÃÕýÈ·ÎÞÎó¡£
- **¼ì²éѧϰÂß¼**£ºÈ·±£`skill_handler.cpp`ÖеÄѧϰÂß¼ÕýÈ·ÎÞÎó¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´ÈÕÖ¾ÎļþÒÔÈ·¶¨ÊÇ·ñÓм¼ÄÜѧϰʧ°ÜµÄ¼Ç¼¡£
##### ÎÊÌâÁù£º¼¼ÄÜÀäȴʱ¼äÎÞЧ
- **¼ì²éÀäȴʱ¼äÅäÖÃ**£ºÈ·±£`skill_config.txt`ÖÐÕýÈ·ÅäÖÃÁËÀäȴʱ¼ä¡£
- **¼ì²éÀäÈ´Âß¼**£ºÈ·±£`skill_handler.cpp`ÖÐÕýȷʵÏÖÁËÀäȴʱ¼äÂß¼¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´ÈÕÖ¾ÎļþÒÔÈ·¶¨ÊÇ·ñÓÐÀäȴʱ¼äÓ¦ÓÃʧ°ÜµÄ¼Ç¼¡£
##### ÎÊÌâÆß£ºÄ§·¨ÏûºÄÎÞЧ
- **¼ì²éħ·¨ÏûºÄÅäÖÃ**£ºÈ·±£`skill_config.txt`ÖÐÕýÈ·ÅäÖÃÁËħ·¨ÏûºÄ¡£
- **¼ì²éħ·¨ÏûºÄÂß¼**£ºÈ·±£`skill_handler.cpp`ÖÐÕýȷʵÏÖÁËħ·¨ÏûºÄÂß¼¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´ÈÕÖ¾ÎļþÒÔÈ·¶¨ÊÇ·ñÓÐħ·¨ÏûºÄʧ°ÜµÄ¼Ç¼¡£
##### ÎÊÌâ°Ë£º¶àÄ¿±ê¹¥»÷ÎÞЧ
- **¼ì²é¼¼ÄÜЧ¹ûÅäÖÃ**£ºÈ·±£`skill_config.txt`ÖÐÕýÈ·ÅäÖÃÁ˼¼ÄÜЧ¹û¡£
- **¼ì²é¶àÄ¿±ê¹¥»÷Âß¼**£ºÈ·±£`skill_handler.cpp`ÖÐÕýÈ·½âÎö²¢Ó¦ÓÃÁ˶àÄ¿±ê¹¥»÷Âß¼¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´ÈÕÖ¾ÎļþÒÔÈ·¶¨ÊÇ·ñÓжàÄ¿±ê¹¥»÷ʧ°ÜµÄ¼Ç¼¡£
##### ÎÊÌâ¾Å£º¸½½ü¹ÖÎï»ñȡʧ°Ü
- **¼ì²é¹ÖÎïλÖüÆËã**£ºÈ·±£`monster_handler.cpp`ÖÐÕýÈ·¼ÆËãÁ˹ÖÎïµÄλÖá£
- **¼ì²é¹ÖÎïÁбí»ñÈ¡**£ºÈ·±£`map_manager.cpp`ÖÐÕýÈ·»ñÈ¡Á˵ØÍ¼ÉϵĹÖÎïÁÐ±í¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´ÈÕÖ¾ÎļþÒÔÈ·¶¨ÊÇ·ñÓйÖÎï»ñȡʧ°ÜµÄ¼Ç¼¡£
##### ÎÊÌâÊ®£ºÊý¾Ý¿âÁ¬½Óʧ°Ü
- **¼ì²éÊý¾Ý¿âÅäÖÃ**£ºÈ·±£`game_config.txt`ÖеÄÊý¾Ý¿âÅäÖÃÕýÈ·¡£
- **¼ì²éÊý¾Ý¿â·þÎñ**£ºÈ·±£Êý¾Ý¿â·þÎñÕýÔÚÔËÐв¢ÇÒ¿ÉÒÔ·ÃÎÊ¡£
- **¼ì²éÍøÂçÉèÖÃ**£ºÈ·±£·þÎñÆ÷Äܹ»·ÃÎÊÊý¾Ý¿âËùÔÚµÄÖ÷»ú¡£
#### 6. ×ܽá
ͨ¹ýÒÔÉϲ½Ö裬ÄãÓ¦¸ÃÄܹ»ÔÚGOM´«ÆæÒýÇæÖгɹ¦ÊµÏÖÒ»¸öÄܹ»¶Ô¶à¸öÄ¿±êÔì³ÉÉ˺¦µÄ“Áé»ê»ð·û”¼¼ÄÜ¡£Õâ²»½öÔö¼ÓÁËÓÎÏ·µÄÀÖȤºÍÌôÕ½ÐÔ£¬»¹ÌáÉýÁËÍæ¼ÒµÄÓÎÏ·ÌåÑ顣ϣÍûÕâÆª½Ì³Ì¶ÔÄãÓÐËù°ïÖú£¡
---
### Ò»¡¢Êý¾Ý¿â²ã¸ÄÔ죺¶àÄ¿±ê²ÎÊýµ÷Õû
#### 1. **Magic.DB¹Ø¼ü×Ö¶Î**
| ×Ö¶ÎÃû | ˵Ã÷ | ¶àÄ¿±ê²ÎÊýʾÀý |
|----------------|------------------------|------------|
| **TargetCount**| ×î´ó¹¥»÷Ä¿±êÊý | 3 → 8 |
| **Range** | ¹¥»÷·¶Î§£¨¸ñÊý£© | 2 → 4 |
| **Splash** | ÊÇ·ñÆôÓý¦É䣨0/1£© | 0 → 1 |
**²Ù×÷²½Öè**£º
1. ÓÃDBC¹¤¾ß´ò¿ª`Magic.DB`£¬ÕÒµ½Áé»ê»ð·ûÐУ¨Í¨³£MagID=22£©¡£
2. ÐÞ¸Ä`TargetCount=8`£¬`Range=4`£¬`Splash=1`¡£
3. ÖØÆôM2Server»òÖ´ÐÐ`@ReloadMagicDB`¡£
---
### ¶þ¡¢½Å±¾¼¶À©Õ¹£º¶¯Ì¬Ä¿±ê¼ì²â
#### 1. **QFunction-0.txt´¥·¢Âß¼**
```lua
[@MagTagFunc22] -- 22ΪÁé»ê»ð·ûMagID
#ACT
; »ñÈ¡µ±Ç°Ä¿±ê×ø±ê
GetTargetPos <$CURRRTARGETX> <$CURRRTARGETY>
; ±éÀúÖÜΧ3x3·¶Î§
For 8 0
GetAroundPos <$CURRRTARGETX> <$CURRRTARGETY> <$CURRENTCOUNT> 3
#IF
CheckRangeMonsterCount <$CURRENTX> <$CURRENTY> 2 > 0
#ACT
HITMON <$CURRENTX> <$CURRENTY> 1 100 ; ¶Ôÿ¸öÄ¿±êÔì³É100%É˺¦
```
#### 2. **É˺¦Ë¥¼õ»úÖÆ**
```lua
#IF
CheckDistance <$CURRRTARGETX> <$CURRRTARGETY> <$CURRENTX> <$CURRENTY> > 2
#ACT
CALCVAR N1 = 100 - (<$DISTANCE> * 20) -- ÿ¸ñË¥¼õ20%
HITMON <$CURRENTX> <$CURRENTY> 1 <$STR(N1)>
```
---
### Èý¡¢¿Í»§¶ËÌØÐ§ÊÊÅä
#### 1. **¶àµ¯µÀÌØÐ§ÊµÏÖ**
1. ¸´ÖÆ`EffectEx.wil`Áé»ê»ð·ûËØ²Ä£¨Ô±àºÅ500-600Ö¡£©¡£
2. ÐÂÔö8·½Ïò·ÖÁÑÌØÐ§£¨±àºÅ601-680£©£¬Ã¿¸ö·½Ïò10Ö¡¡£
3. ÔڵǼÆ÷ÅäÖÃÖаó¶¨ÐÂËØ²Ä£º
```ini
[MagicEffect]
Áé»ê»ð·û·ÖÁÑ=601,680
```
#### 2. **¶¯Ì¬µ¯µÀ¿ØÖÆ£¨LUA£©**
```lua
function OnFireSplit(x, y)
for i=1,8 do
local angle = (i-1)*45
local dx = x + 4*math.cos(math.rad(angle))
local dy = y + 4*math.sin(math.rad(angle))
CreateEffect(601 + (i-1)*10, dx, dy)
end
end
```
---
### ËÄ¡¢ÐÔÄÜÓÅ»¯·½°¸
#### 1. **Ä¿±êÊýÏÞÖÆ**
```lua
#IF
CheckMapPlayerCount > 50 -- ¸ß¸ºÔصØÍ¼
#ACT
SetVar MaxTargets = 4 -- ÏÞÖÆ×î´óÄ¿±êÊý
#ELSEACT
SetVar MaxTargets = 8
```
#### 2. **É˺¦¼ÆËãÅú´¦Àí**
```lua
HITMON_MULTI <$X> <$Y> 4 8 1 100 -- ·¶Î§4¸ñ£¬×î¶à8Ä¿±ê
```
---
### Îå¡¢²âÊÔÓëµ÷ÊÔÃüÁî
#### 1. **ʵʱµ¯µÀ×·×Ù**
```lua
@DebugMagic 22 -- ÏÔʾÁé»ê»ð·û¹¥»÷·¾¶
```
#### 2. **GMѹÁ¦²âÊÔ**
```lua
@Make µ¾²ÝÈË 20 -- Éú³É20¸ö²âÊÔÄ¿±ê
@SetSkillLevel Áé»ê»ð·û 7
@Cast 22 -- Á¬ÐøÊͷż¼ÄÜ
```
---
### Áù¡¢¸ßƵÎÊÌâ½â¾ö·½°¸
| **ÎÊÌâÏÖÏó** | **ÔÒò** | **½â¾ö·½°¸** |
|--------------------------|-----------------------|--------------------------------|
| ¶àÄ¿±êÉ˺¦²»ÉúЧ | SplashδÆôÓà | ¼ì²éMagic.DBµÄSplash×Ö¶ÎÊÇ·ñΪ1 |
| ¿Í»§¶ËÌØÐ§´íλ | ×ø±ê¼ÆËãδȡÕû | ÔÚLUAÖÐʹÓÃmath.floor(dx)´¦Àí×ø±ê |
| ÐÔÄÜ¿¨¶Ù | Ä¿±êÊý¹ý¶à | ÔÚQManage.txtÖÐÔö¼ÓCheckMapPlayerCountÌõ¼þ |
| ²¿·Ö·½ÏòÎÞÉ˺¦ | GetAroundPos²ÎÊý´íÎó | ½«·¶Î§´Ó3¸ÄΪ4²¢¼ì²é×ø±êÆ«ÒÆÁ¿ |
---
#### ½áÓï
ͨ¹ýÊý¾Ý¿â¡¢½Å±¾Óë¿Í»§¶ËµÄÁªºÏ¸ÄÔ죬Áé»ê»ð·û¿É»¯ÉíµÀÊ¿µÄAOEÉñ¼¼¡£½¨Òé²ÉÓÓ½¥½øÊ½Ç¿»¯”²ßÂÔ£ºÏÈʵÏÖ»ù´¡¶àÄ¿±ê£¬ÔÙÌí¼ÓÉ˺¦Ë¥¼õÓëÌØÐ§£¬×îºó½øÐÐÐÔÄÜÓÅ»¯¡£×¢Òâ±£³Ö¼¼ÄÜÆ½ºâ——¿Éͨ¹ý½µµÍȺÌåÉ˺¦ÏµÊý£¨Èç70%µÝ¼õ£©»òÔö¼Óħ·¨ÏûºÄÀ´Î¬³ÖÖ°ÒµÉú̬¡£²âÊÔ½×¶ÎÎñ±ØÊ¹ÓÃ@DebugMagicÃüÁîÑé֤ÿ¸öµ¯µÀµÄÃüÖÐÅж¨¡£
#### 1. ¹¦ÄܸÅÊö
##### “Áé»ê»ð·û”
“Áé»ê»ð·û”ÊÇÒ»ÖÖÇ¿´óµÄħ·¨¼¼ÄÜ£¬Äܹ»Í¬Ê±¶Ô¶à¸öµÐÈËÔì³É»ðÑæÉ˺¦¡£Í¨¹ýʵÏÖÕâÒ»¼¼ÄÜ£¬¿ÉÒÔÊ¹Íæ¼ÒÔÚÓÎÏ·ÖÐÓµÓиü¶àµÄÕ½ÊõÑ¡ÔñºÍÕ½¶·²ßÂÔ¡£
#### 2. GOMÒýÇæ¼ò½é
##### GOMÒýÇæÌØµã
- **¸ßЧÎȶ¨**£ºGOMÒýÇæÒÔÆä¸ßЧµÄ´¦ÀíÄÜÁ¦ºÍÎȶ¨µÄÔËÐбíÏÖÖø³Æ¡£
- **Ò×ÓÃÐÔÇ¿**£ºGOMÒýÇæÌṩÁ˼ò½àÃ÷Á˵ÄAPI½Ó¿Ú£¬·½±ã¿ª·¢Õß½øÐжþ´Î¿ª·¢¡£
- **¹¦ÄÜÈ«Ãæ**£ºÖ§³Ö¶àÖÖÓÎÏ·ÔªËØµÄÌí¼Ó£¬°üÀ¨µ«²»ÏÞÓÚ¼¼ÄÜ¡¢¹ÖÎï¡¢µØÍ¼µÈ¡£
##### Ö§³Ö×Ô¶¨Ò幦ÄÜ
GOMÒýÇæÔÊÐí¿ª·¢Õßͨ¹ýÐ޸ĴúÂëºÍÅäÖÃÎļþÀ´ÊµÏÖ¸÷ÖÖ×Ô¶¨Ò幦ÄÜ£¬°üÀ¨ÐÂÔö¶àÄ¿±ê¹¥»÷¼¼ÄÜ¡£
#### 3. ʵÏÖ“Áé»ê»ð·û”¶àÄ¿±ê¹¥»÷²½Öè
##### ²½ÖèÒ»£º×¼±¸¹¤×÷
È·±£ÄãÒѾ°²×°ÁËGOMÒýÇæ£¬²¢ÇÒÓÐÒ»¸ö»ù±¾µÄÓÎÏ·¿ò¼Ü´î½¨Íê³É¡£´ËÍ⣬»¹ÐèҪ׼±¸ºÃËùÓбØÒªµÄ¿Í»§¶ËºÍ·þÎñÆ÷¶ËÎļþ¡£
##### ²½Öè¶þ£º´´½¨“Áé»ê»ð·û”¼¼ÄÜ
###### ÐÞ¸Ä`skill_table`
ÔÚÊý¾Ý¿âÖд´½¨Ò»¸öеıíÀ´´æ´¢¼¼ÄܵÄÐÅÏ¢¡£
**´´½¨`skill_table`±í**
```sql
CREATE TABLE skill_table (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
type INT NOT NULL, -- ¼¼ÄÜÀàÐÍ£¨ÈçÎïÀí¹¥»÷¡¢Ä§·¨¹¥»÷¡¢¸¨Öú¼¼Äܵȣ©
mana_cost INT NOT NULL, -- ħ·¨ÏûºÄ
cooldown INT NOT NULL, -- Àäȴʱ¼ä
range INT NOT NULL, -- Ê©·Å·¶Î§
effect TEXT -- ¼¼ÄÜЧ¹û£¨JSON¸ñʽ£©
);
```
###### ²åÈë“Áé»ê»ð·û”Êý¾Ý
²åÈë“Áé»ê»ð·û”µÄʾÀýÊý¾ÝÒÔ±ã½øÐвâÊÔ¡£
**²åÈë“Áé»ê»ð·û”Êý¾Ý**
```sql
INSERT INTO skill_table (name, type, mana_cost, cooldown, range, effect) VALUES
('Áé»ê»ð·û', 2, 50, 10, 5, '{"damage": 100, "targets": 3}');
```
##### ²½ÖèÈý£ºÅäÖü¼ÄÜЧ¹û
###### ÐÞ¸Ä`skill_config.txt`
ÔÚ`config\skill_config.txt`ÎļþÖÐÌí¼Ó“Áé»ê»ð·û”µÄÏêϸЧ¹ûÅäÖá£
**skill_config.txt**
```ini
[Skill1]
Name=Áé»ê»ð·û
Type=2 -- ħ·¨¹¥»÷
ManaCost=50
Cooldown=10
Range=5
Effect={"damage": 100, "targets": 3}
```
##### ²½ÖèËÄ£º±àдÏà¹ØÂß¼´úÂë
###### ÐÞ¸Ä`skill_handler.cpp`
ÔÚ`src\skill_handler.cpp`ÎļþÖÐÌí¼Ó´¦Àí“Áé»ê»ð·û”¶àÄ¿±ê¹¥»÷µÄÂß¼¡£
**skill_handler.cpp**
```cpp
#include "skill_handler.h"
#include "character.h"
#include "monster_handler.h"
#include "random_generator.h"
#include "packet_builder.h"
SkillHandler* SkillHandler::GetInstance()
{
static SkillHandler instance;
return &instance;
}
void SkillHandler::UseSkill(Character* character, int skillId)
{
ConfigManager* configManager = ConfigManager::GetInstance();
std::string skillConfig = configManager->GetSkillConfig(skillId);
// Parse skill configuration
json skillJson = json::parse(skillConfig);
std::string skillName = skillJson["Name"];
int skillType = skillJson["Type"];
int manaCost = skillJson["ManaCost"];
int cooldown = skillJson["Cooldown"];
int range = skillJson["Range"];
json effectJson = skillJson["Effect"];
if (character->GetMana() < manaCost)
{
CPacketBuilder response(PACKET_TYPE_SKILL_USE_RESPONSE);
response.WriteByte(SKILL_USE_FAILURE_NOT_ENOUGH_MANA);
character->SendPacket(response.Build());
SystemLog::LogWarning("Character [%d] does not have enough mana to use skill [%s].", character->GetId(), skillName.c_str());
return;
}
if (character->IsOnCooldown(skillId))
{
CPacketBuilder response(PACKET_TYPE_SKILL_USE_RESPONSE);
response.WriteByte(SKILL_USE_FAILURE_COOLDOWN);
character->SendPacket(response.Build());
SystemLog::LogWarning("Character [%d] is on cooldown for skill [%s].", character->GetId(), skillName.c_str());
return;
}
character->SubtractMana(manaCost);
character->SetCooldown(skillId, cooldown);
int damage = effectJson["damage"];
int targets = effectJson["targets"];
MonsterHandler* monsterHandler = MonsterHandler::GetInstance();
RandomGenerator* randomGen = RandomGenerator::GetInstance();
std::vector<Monster*> nearbyMonsters = monsterHandler->GetNearbyMonsters(character, range);
if (nearbyMonsters.empty())
{
CPacketBuilder response(PACKET_TYPE_SKILL_USE_RESPONSE);
response.WriteByte(SKILL_USE_FAILURE_NO_TARGETS);
character->SendPacket(response.Build());
SystemLog::LogWarning("No monsters found within range for skill [%s] by character [%d].", skillName.c_str(), character->GetId());
return;
}
std::shuffle(nearbyMonsters.begin(), nearbyMonsters.end(), randomGen->GetEngine());
int numTargetsHit = std::min(targets, static_cast<int>(nearbyMonsters.size()));
for (int i = 0; i < numTargetsHit; ++i)
{
Monster* target = nearbyMonsters[i];
target->TakeDamage(damage);
CPacketBuilder response(PACKET_TYPE_MONSTER_DAMAGE_RESPONSE);
response.WriteInt(target->GetId());
response.WriteInt(damage);
character->SendPacket(response.Build());
SystemLog::LogInfo("Character [%d] used skill [%s] on monster [%s], dealing %d damage.", character->GetId(), skillName.c_str(), target->GetName().c_str(), damage);
}
CPacketBuilder response(PACKET_TYPE_SKILL_USE_RESPONSE);
response.WriteByte(SKILL_USE_SUCCESS);
character->SendPacket(response.Build());
SystemLog::LogInfo("Character [%d] successfully used skill [%s] and hit %d targets.", character->GetId(), skillName.c_str(), numTargetsHit);
}
```
###### ÐÞ¸Ä`monster_handler.cpp`
ÔÚ`src\monster_handler.cpp`ÎļþÖÐÌí¼Ó»ñÈ¡¸½½ü¹ÖÎïµÄ·½·¨¡£
**monster_handler.cpp**
```cpp
#include "monster_handler.h"
#include "map_manager.h"
#include "distance_calculator.h"
MonsterHandler* MonsterHandler::GetInstance()
{
static MonsterHandler instance;
return &instance;
}
std::vector<Monster*> MonsterHandler::GetNearbyMonsters(Character* character, int range)
{
MapManager* mapManager = MapManager::GetInstance();
DistanceCalculator* distanceCalc = DistanceCalculator::GetInstance();
std::vector<Monster*> allMonsters = mapManager->GetAllMonstersInMap(character->GetCurrentMapId());
std::vector<Monster*> nearbyMonsters;
for (auto& monster : allMonsters)
{
double distance = distanceCalc->CalculateDistance(character->GetPositionX(), character->GetPositionY(), monster->GetPositionX(), monster->GetPositionY());
if (distance <= range && !monster->IsDead())
{
nearbyMonsters.push_back(monster);
}
}
return nearbyMonsters;
}
```
##### ²½ÖèÎ壺±àÒë²¢²âÊÔ
È·±£ËùÓÐÐ޸ĺóµÄ´úÂë¶¼Äܳɹ¦±àÒë¡£
**±àÒë·þÎñÆ÷¶Ë**
```sh
g++ -o game_server src/game_server.cpp src/database_manager.cpp src/skill_handler.cpp src/monster_handler.cpp src/item_handler.cpp src/inventory.cpp src/character.cpp src/packet_builder.cpp src/config_manager.cpp src/random_generator.cpp src/map_manager.cpp src/distance_calculator.cpp -lengine -ljansson
```
Æô¶¯ÓÎÏ··þÎñÆ÷ºÍ¿Í»§¶Ë£¬¹Û²ìÕû¸ö“Áé»ê»ð·û”¶àÄ¿±ê¹¥»÷Á÷³ÌÊÇ·ñÕý³£¹¤×÷¡£
**Æô¶¯·þÎñÆ÷ÃüÁî**
```sh
start game_server.exe
start client.exe
```
##### ²½ÖèÁù£ºÑéÖ¤“Áé»ê»ð·û”¶àÄ¿±ê¹¥»÷Ч¹û
###### ²âÊÔ“Áé»ê»ð·û”¶àÄ¿±ê¹¥»÷
1. Æô¶¯ÓÎÏ··þÎñÆ÷¡£
2. ʹÓÿͻ§¶ËµÇ¼ÓÎÏ·¡£
3. ѧϰ»ò×°±¸“Áé»ê»ð·û”¼¼ÄÜ¡£
4. ¶Ô¶à¸ö¹ÖÎïÊ©·Å“Áé»ê»ð·û”£¬¼ì²éÊÇ·ñÕýÈ·¶Ô¶à¸öÄ¿±êÔì³ÉÉ˺¦¡£
**²âÊÔ“Áé»ê»ð·û”¶àÄ¿±ê¹¥»÷Á÷³Ì**
```plaintext
1. ½øÈëÓÎÏ·ºó£¬Ñ§Ï°»ò×°±¸“Áé»ê»ð·û”¼¼ÄÜ¡£
2. ѰÕÒ¶à¸ö¹ÖÎï¾Û¼¯µÄµØ·½¡£
3. ¶Ô¶à¸ö¹ÖÎïÊ©·Å“Áé»ê»ð·û”¡£
4. ¹Û²ìÊÇ·ñÓжà¸ö¹ÖÎïÊܵ½É˺¦¡£
```
#### 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: Character [1] logged in.
[2023-10-01 12:34:56] INFO: Character [1] learned skill [Áé»ê»ð·û].
[2023-10-01 12:34:56] INFO: Character [1] used skill [Áé»ê»ð·û] on monster [Ò°ÀÇ], dealing 100 damage.
[2023-10-01 12:34:56] INFO: Character [1] used skill [Áé»ê»ð·û] on monster [ÓÄÁéÆïÊ¿], dealing 100 damage.
[2023-10-01 12:34:56] INFO: Character [1] successfully used skill [Áé»ê»ð·û] and hit 2 targets.
```
¸ù¾ÝÈÕÖ¾ÖеÄÐÅÏ¢£¬È·ÈÏÓÎÏ··þÎñÆ÷ÊÇ·ñÕý³£ÔËÐÐÒÔ¼°“Áé»ê»ð·û”µÄ¶àÄ¿±ê¹¥»÷²Ù×÷ÊÇ·ñÕýÈ·Ö´ÐС£
##### ²é¿´¿Í»§¶ËÈÕÖ¾
´ò¿ª¿Í»§¶ËµÄÈÕÖ¾Îļþ£¨Í¨³£Î»ÓÚ`log\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: Learned skill [Áé»ê»ð·û].
[2023-10-01 12:34:56] INFO: Used skill [Áé»ê»ð·û] on monster [Ò°ÀÇ], dealing 100 damage.
[2023-10-01 12:34:56] INFO: Used skill [Áé»ê»ð·û] on monster [ÓÄÁéÆïÊ¿], dealing 100 damage.
[2023-10-01 12:34:56] INFO: Successfully used skill [Áé»ê»ð·û] and hit 2 targets.
```
¸ù¾ÝÈÕÖ¾ÖеÄÐÅÏ¢£¬È·ÈϿͻ§¶ËÊÇ·ñÕýÈ·½ÓÊÕÁË·þÎñÆ÷µÄÏìÓ¦²¢ÇÒÏÔʾÁËÏàÓ¦µÄ½á¹û¡£
#### 5. ³£¼ûÎÊÌâ¼°½â¾ö·½°¸
##### ÎÊÌâÒ»£ºÎÞ·¨Á¬½Óµ½ÓÎÏ··þÎñÆ÷
- **¼ì²éÍøÂçÉèÖÃ**£ºÈ·±£¿Í»§¶ËºÍÓÎÏ··þÎñÆ÷Ö®¼äµÄÍøÂçÁ¬½ÓÕý³£¡£
- **¼ì²éÅäÖÃÎļþ**£ºÈ·±£`client_config.txt`ÖеÄÓÎÏ··þÎñÆ÷IPºÍ¶Ë¿ÚÅäÖÃÕýÈ·¡£
- **¼ì²é·À»ðǽÉèÖÃ**£ºÈ·±£·À»ðǽûÓÐ×èÖ¹ÓÎÏ··þÎñÆ÷µÄ¶Ë¿Ú¡£
##### ÎÊÌâ¶þ£ºµÇ¼ʧ°Ü
- **¼ì²éÊý¾Ý¿âÅäÖÃ**£ºÈ·±£`game_config.txt`ÖеÄÊý¾Ý¿âÅäÖÃÕýÈ·¡£
- **¼ì²éÊý¾Ý¿â·þÎñ**£ºÈ·±£Êý¾Ý¿â·þÎñÕýÔÚÔËÐв¢ÇÒ¿ÉÒÔ·ÃÎÊ¡£
- **¼ì²éÓû§Êý¾Ý**£ºÈ·±£`account_table`Öаüº¬ÕýÈ·µÄÓû§ÐÅÏ¢¡£
##### ÎÊÌâÈý£º½ÇÉ«¼ÓÔØÊ§°Ü
- **¼ì²é½ÇÉ«Êý¾Ý**£ºÈ·±£`char_table`Öаüº¬ÕýÈ·µÄ½ÇÉ«ÐÅÏ¢¡£
- **¼ì²éÎïÆ·Êý¾Ý**£ºÈ·±£`item_table`Öаüº¬ÕýÈ·µÄÎïÆ·ÐÅÏ¢¡£
- **¼ì²é¼¼ÄÜÊý¾Ý**£ºÈ·±£`skill_table`Öаüº¬ÕýÈ·µÄ¼¼ÄÜÐÅÏ¢¡£
##### ÎÊÌâËÄ£º¿Í»§¶Ë°æ±¾²»Æ¥Åä
- **¸üпͻ§¶Ë**£ºÈ·±£¿Í»§¶Ë°æ±¾Óë·þÎñÆ÷°æ±¾¼æÈÝ¡£
- **ͬ²½×ÊÔ´Îļþ**£ºÈ·±£¿Í»§¶ËºÍ·þÎñÆ÷Ö®¼äµÄ×ÊÔ´ÎļþÒ»Ö¡£
##### ÎÊÌâÎ壺¼¼ÄÜδѧϰ»ò×°±¸
- **¼ì²é¼¼ÄÜÅäÖÃ**£ºÈ·±£`skill_config.txt`Öеļ¼ÄÜÅäÖÃÕýÈ·ÎÞÎó¡£
- **¼ì²éѧϰÂß¼**£ºÈ·±£`skill_handler.cpp`ÖеÄѧϰÂß¼ÕýÈ·ÎÞÎó¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´ÈÕÖ¾ÎļþÒÔÈ·¶¨ÊÇ·ñÓм¼ÄÜѧϰʧ°ÜµÄ¼Ç¼¡£
##### ÎÊÌâÁù£º¼¼ÄÜÀäȴʱ¼äÎÞЧ
- **¼ì²éÀäȴʱ¼äÅäÖÃ**£ºÈ·±£`skill_config.txt`ÖÐÕýÈ·ÅäÖÃÁËÀäȴʱ¼ä¡£
- **¼ì²éÀäÈ´Âß¼**£ºÈ·±£`skill_handler.cpp`ÖÐÕýȷʵÏÖÁËÀäȴʱ¼äÂß¼¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´ÈÕÖ¾ÎļþÒÔÈ·¶¨ÊÇ·ñÓÐÀäȴʱ¼äÓ¦ÓÃʧ°ÜµÄ¼Ç¼¡£
##### ÎÊÌâÆß£ºÄ§·¨ÏûºÄÎÞЧ
- **¼ì²éħ·¨ÏûºÄÅäÖÃ**£ºÈ·±£`skill_config.txt`ÖÐÕýÈ·ÅäÖÃÁËħ·¨ÏûºÄ¡£
- **¼ì²éħ·¨ÏûºÄÂß¼**£ºÈ·±£`skill_handler.cpp`ÖÐÕýȷʵÏÖÁËħ·¨ÏûºÄÂß¼¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´ÈÕÖ¾ÎļþÒÔÈ·¶¨ÊÇ·ñÓÐħ·¨ÏûºÄʧ°ÜµÄ¼Ç¼¡£
##### ÎÊÌâ°Ë£º¶àÄ¿±ê¹¥»÷ÎÞЧ
- **¼ì²é¼¼ÄÜЧ¹ûÅäÖÃ**£ºÈ·±£`skill_config.txt`ÖÐÕýÈ·ÅäÖÃÁ˼¼ÄÜЧ¹û¡£
- **¼ì²é¶àÄ¿±ê¹¥»÷Âß¼**£ºÈ·±£`skill_handler.cpp`ÖÐÕýÈ·½âÎö²¢Ó¦ÓÃÁ˶àÄ¿±ê¹¥»÷Âß¼¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´ÈÕÖ¾ÎļþÒÔÈ·¶¨ÊÇ·ñÓжàÄ¿±ê¹¥»÷ʧ°ÜµÄ¼Ç¼¡£
##### ÎÊÌâ¾Å£º¸½½ü¹ÖÎï»ñȡʧ°Ü
- **¼ì²é¹ÖÎïλÖüÆËã**£ºÈ·±£`monster_handler.cpp`ÖÐÕýÈ·¼ÆËãÁ˹ÖÎïµÄλÖá£
- **¼ì²é¹ÖÎïÁбí»ñÈ¡**£ºÈ·±£`map_manager.cpp`ÖÐÕýÈ·»ñÈ¡Á˵ØÍ¼ÉϵĹÖÎïÁÐ±í¡£
- **¼ì²éÈÕÖ¾Îļþ**£º²é¿´ÈÕÖ¾ÎļþÒÔÈ·¶¨ÊÇ·ñÓйÖÎï»ñȡʧ°ÜµÄ¼Ç¼¡£
##### ÎÊÌâÊ®£ºÊý¾Ý¿âÁ¬½Óʧ°Ü
- **¼ì²éÊý¾Ý¿âÅäÖÃ**£ºÈ·±£`game_config.txt`ÖеÄÊý¾Ý¿âÅäÖÃÕýÈ·¡£
- **¼ì²éÊý¾Ý¿â·þÎñ**£ºÈ·±£Êý¾Ý¿â·þÎñÕýÔÚÔËÐв¢ÇÒ¿ÉÒÔ·ÃÎÊ¡£
- **¼ì²éÍøÂçÉèÖÃ**£ºÈ·±£·þÎñÆ÷Äܹ»·ÃÎÊÊý¾Ý¿âËùÔÚµÄÖ÷»ú¡£
#### 6. ×ܽá
ͨ¹ýÒÔÉϲ½Ö裬ÄãÓ¦¸ÃÄܹ»ÔÚGOM´«ÆæÒýÇæÖгɹ¦ÊµÏÖÒ»¸öÄܹ»¶Ô¶à¸öÄ¿±êÔì³ÉÉ˺¦µÄ“Áé»ê»ð·û”¼¼ÄÜ¡£Õâ²»½öÔö¼ÓÁËÓÎÏ·µÄÀÖȤºÍÌôÕ½ÐÔ£¬»¹ÌáÉýÁËÍæ¼ÒµÄÓÎÏ·ÌåÑ顣ϣÍûÕâÆª½Ì³Ì¶ÔÄãÓÐËù°ïÖú£¡

