优化[自定义AI_物体]

1、扩展更多类型
2、添加param3和param4字段,作为条件扩展
This commit is contained in:
尚美 2025-08-14 20:59:38 +08:00
parent 604f8cd01f
commit 48a36cd260
2 changed files with 305 additions and 28 deletions

View File

@ -4,11 +4,24 @@
enum GobActionTypes
{
gob_ACTION_TYPE_NONE,
gob_ACTION_TYPE_AURA, //释放技能 AuraID1, AuraID2,
gob_ACTION_TYPE_TELE, //传送玩家 TelePosId TeleAura
gob_ACTION_TYPE_ACTIVE_OR_DEACTIVE_OBJECT, //激活或使失活 CreatureEntry GameObjectEntry
gob_ACTION_TYPE_CAST_SPELL, // 修正:真正的技能释放 AuraID1, AuraID2,
gob_ACTION_TYPE_ADD_AURA, // 新增:直接添加光环 AuraID1, AuraID2,
gob_ACTION_TYPE_TELE, // 传送玩家 TelePosId TeleAura
gob_ACTION_TYPE_ACTIVE_OR_DEACTIVE_OBJECT, // 激活或使失活 CreatureEntry GameObjectEntry
gob_ACTION_TALK,
gob_ACTION_SUMMON,
// 新增
gob_ACTION_TYPE_GIVE_ITEM, // 给予物品
gob_ACTION_TYPE_REMOVE_ITEM, // 移除物品
gob_ACTION_TYPE_LEARN_SPELL, // 学习技能
gob_ACTION_TYPE_UNLEARN_SPELL, // 遗忘技能
gob_ACTION_TYPE_ADD_MONEY, // 给予金钱
gob_ACTION_TYPE_REMOVE_MONEY, // 扣除金钱
gob_ACTION_TYPE_SET_PHASE, // 设置相位
gob_ACTION_TYPE_MORPH, // 变形
gob_ACTION_TYPE_DEMORPH, // 取消变形
gob_ACTION_TYPE_PLAYER_EMOTE, // 随机执行动
};
@ -18,9 +31,10 @@ struct GobScriptTemplate
GobActionTypes gobActionType;
std::string actionParam1;
int32 actionParam2;
};
extern std::vector<GobScriptTemplate> GobScriptVec;
int32 actionParam3; // 新增第三个参数
std::string actionParam4; // 新增第四个参数
};
enum CreatureEventTypes
{ // eventPhase delayTime repeatMinTime repeatMaxTime
@ -151,11 +165,13 @@ public:
bool HasCustomScript(uint32 entry);
void ExecuteScript(Player* player, GameObject* gob);
private:
private:
// 使用unordered_map按entry分组存储提高查找效率
std::unordered_map<uint32, std::vector<GobScriptTemplate>> GobScriptMap;
void Tele(Player* player, uint32 telePosId);
bool CheckCondition(Player* player, int32 conditionType, int32 value);
};
#define sCustomScript CustomScript::instance()

View File

@ -7,12 +7,14 @@
#include "mod_CustomWorldData/mod_CustomWorldData.h"
#include <WorldSessionMgr.h>
#include <Scripting/ScriptMgrMacros.h>
#include <Spells/SpellMgr.h>
void CustomScript::LoadGobScripts()
{
uint32 oldMSTime = getMSTime();
GobScriptMap.clear();
QueryResult result = WorldDatabase.Query("SELECT 物体ID,动作类型,动作参数1,动作参数2 FROM acore_custom._自定义AI_物体");
QueryResult result = WorldDatabase.Query("SELECT 物体ID,动作类型,动作参数1,动作参数2,动作参数3,动作参数4 FROM acore_custom._自定义AI_物体");
if (result)
{
@ -22,25 +24,47 @@ void CustomScript::LoadGobScripts()
GobScriptTemplate temp;
temp.ID = fields[0].Get<int32>();
std::string str2 = fields[1].Get<std::string>();
if (!str2.empty())
std::string actionTypeStr = fields[1].Get<std::string>();
if (!actionTypeStr.empty())
{
if (strcmp("传送玩家", str2.c_str()) == 0)
if (actionTypeStr == "传送玩家")
temp.gobActionType = gob_ACTION_TYPE_TELE;
else if (strcmp("激活或使失活", str2.c_str()) == 0)
else if (actionTypeStr == "激活或使失活")
temp.gobActionType = gob_ACTION_TYPE_ACTIVE_OR_DEACTIVE_OBJECT;
else if (strcmp("释放技能", str2.c_str()) == 0)
temp.gobActionType = gob_ACTION_TYPE_AURA;
else if (strcmp("说话", str2.c_str()) == 0)
else if (actionTypeStr == "添加光环")
temp.gobActionType = gob_ACTION_TYPE_ADD_AURA;
else if (actionTypeStr == "说话")
temp.gobActionType = gob_ACTION_TALK;
else if (strcmp("召唤", str2.c_str()) == 0)
else if (actionTypeStr == "召唤")
temp.gobActionType = gob_ACTION_SUMMON;
else if (actionTypeStr == "给予物品")
temp.gobActionType = gob_ACTION_TYPE_GIVE_ITEM;
else if (actionTypeStr == "移除物品")
temp.gobActionType = gob_ACTION_TYPE_REMOVE_ITEM;
else if (actionTypeStr == "学习技能")
temp.gobActionType = gob_ACTION_TYPE_LEARN_SPELL;
else if (actionTypeStr == "遗忘技能")
temp.gobActionType = gob_ACTION_TYPE_UNLEARN_SPELL;
else if (actionTypeStr == "给予金钱")
temp.gobActionType = gob_ACTION_TYPE_ADD_MONEY;
else if (actionTypeStr == "扣除金钱")
temp.gobActionType = gob_ACTION_TYPE_REMOVE_MONEY;
else if (actionTypeStr == "设置相位")
temp.gobActionType = gob_ACTION_TYPE_SET_PHASE;
else if (actionTypeStr == "变形")
temp.gobActionType = gob_ACTION_TYPE_MORPH;
else if (actionTypeStr == "取消变形")
temp.gobActionType = gob_ACTION_TYPE_DEMORPH;
else if (actionTypeStr == "表情")
temp.gobActionType = gob_ACTION_TYPE_PLAYER_EMOTE;
else
temp.gobActionType = gob_ACTION_TYPE_NONE;
}
temp.actionParam1 = fields[2].Get<std::string>();
temp.actionParam2 = fields[3].Get<int32>();
temp.actionParam3 = fields[4].Get<int32>();
temp.actionParam4 = fields[5].Get<std::string>();
// 按entry分组存储
uint32 entry = abs(temp.ID);
@ -69,6 +93,9 @@ bool CustomScript::HasCustomScript(uint32 entry)
void CustomScript::ExecuteScript(Player* player, GameObject* gob)
{
if (!player || !gob)
return;
uint32 entry = gob->GetEntry();
int32 guid = gob->GetGUID().GetCounter();
@ -83,31 +110,218 @@ void CustomScript::ExecuteScript(Player* player, GameObject* gob)
if (script.ID != entry && guid != abs(script.ID))
continue;
// 条件检查 - 避免与特殊功能的param3使用冲突
bool hasSpecialParam3Usage = (script.gobActionType == gob_ACTION_TYPE_TELE || script.gobActionType == gob_ACTION_TYPE_GIVE_ITEM || script.gobActionType == gob_ACTION_SUMMON);
if (!hasSpecialParam3Usage && script.actionParam3 > 0)
{
if (!CheckCondition(player, script.actionParam3, atoi(script.actionParam4.c_str())))
continue;
}
int32 i_actionParam1 = atoi(script.actionParam1.c_str());
std::string s_actionParam1 = script.actionParam1;
int32 i_actionParam2 = script.actionParam2;
int32 i_actionParam3 = script.actionParam3;
std::string s_actionParam4 = script.actionParam4;
switch (script.gobActionType)
{
case gob_ACTION_TYPE_AURA:
player->CastSpell(player, i_actionParam1, true);
case gob_ACTION_TYPE_ADD_AURA:
// 新增:专门用于添加光环
if (i_actionParam1 > 0)
player->AddAura(i_actionParam1, player);
if (i_actionParam2 > 0)
player->CastSpell(player, i_actionParam2, true);
player->AddAura(i_actionParam2, player);
break;
case gob_ACTION_TYPE_TELE:
if (!player->HasAura(i_actionParam2))
{
uint32 cooldownSpell = i_actionParam2;
uint32 requiredLevel = i_actionParam3; // 传送等级要求
// 等级检查
if (requiredLevel > 0 && player->GetLevel() < requiredLevel)
{
player->AddAura(i_actionParam2, player);
player->GetSession()->SendAreaTriggerMessage("等级不足,无法传送!");
break;
}
if (cooldownSpell > 0 && !player->HasAura(cooldownSpell))
{
player->AddAura(cooldownSpell, player);
Tele(player, i_actionParam1);
}
else
else if (cooldownSpell > 0)
{
std::ostringstream oss;
oss << "|cFFFF1717[" << gob->GetName() << "]|r正处于冷却中传送失败...";
player->GetSession()->SendAreaTriggerMessage(oss.str().c_str());
}
break;
else
{
Tele(player, i_actionParam1);
}
}
break;
case gob_ACTION_TYPE_GIVE_ITEM:
{
uint32 itemId = i_actionParam1;
uint32 count = i_actionParam2 > 0 ? i_actionParam2 : 1;
uint32 requiredLevel = i_actionParam3; // 等级要求
bool checkBagSpace = !s_actionParam4.empty() && s_actionParam4 == "checkbag"; // 背包检查
// 等级检查
if (requiredLevel > 0 && player->GetLevel() < requiredLevel)
{
player->GetSession()->SendAreaTriggerMessage("等级不足,需要 {} 级", requiredLevel);
break;
}
// 背包空间检查
if (checkBagSpace)
{
ItemPosCountVec dest;
InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, count);
if (msg != EQUIP_ERR_OK)
{
player->GetSession()->SendAreaTriggerMessage("背包空间不足!");
break;
}
}
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId))
{
player->AddItem(itemId, count);
std::ostringstream oss;
oss << "获得物品:" << itemTemplate->Name1 << " x" << count;
player->GetSession()->SendAreaTriggerMessage(oss.str().c_str());
}
}
break;
case gob_ACTION_TYPE_REMOVE_ITEM:
{
uint32 itemId = i_actionParam1;
uint32 count = i_actionParam2 > 0 ? i_actionParam2 : 1;
if (player->HasItemCount(itemId, count))
{
player->DestroyItemCount(itemId, count, true);
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId))
{
std::ostringstream oss;
oss << "失去物品:" << itemTemplate->Name1 << " x" << count;
player->GetSession()->SendAreaTriggerMessage(oss.str().c_str());
}
}
else
{
player->GetSession()->SendAreaTriggerMessage("物品数量不足!");
}
}
break;
case gob_ACTION_TYPE_LEARN_SPELL:
{
uint32 spellId = i_actionParam1;
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId))
{
if (!player->HasSpell(spellId))
{
player->learnSpell(spellId, false);
std::ostringstream oss;
oss << "学会技能:" << spellInfo->SpellName[player->GetSession()->GetSessionDbcLocale()];
player->GetSession()->SendAreaTriggerMessage(oss.str().c_str());
}
}
}
break;
case gob_ACTION_TYPE_UNLEARN_SPELL:
{
uint32 spellId = i_actionParam1;
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId))
{
if (player->HasSpell(spellId))
{
player->removeSpell(spellId, SPEC_MASK_ALL, false);
std::ostringstream oss;
oss << "遗忘技能:" << spellInfo->SpellName[player->GetSession()->GetSessionDbcLocale()];
player->GetSession()->SendAreaTriggerMessage(oss.str().c_str());
}
}
}
break;
case gob_ACTION_TYPE_ADD_MONEY:
{
uint32 money = i_actionParam1;
if (money > 0)
{
player->ModifyMoney(money);
std::ostringstream oss;
oss << "获得金钱:" << money << " 铜币";
player->GetSession()->SendAreaTriggerMessage(oss.str().c_str());
}
}
break;
case gob_ACTION_TYPE_REMOVE_MONEY:
{
uint32 money = i_actionParam1;
if (money > 0 && player->HasEnoughMoney(money))
{
player->ModifyMoney(-int32(money));
std::ostringstream oss;
oss << "失去金钱:" << money << " 铜币";
player->GetSession()->SendAreaTriggerMessage(oss.str().c_str());
}
else
{
player->GetSession()->SendAreaTriggerMessage("金钱不足!");
}
}
break;
case gob_ACTION_TYPE_SET_PHASE:
{
uint32 phaseId = i_actionParam1;
if (phaseId > 0)
{
player->SetPhaseMask(phaseId, true);
std::ostringstream oss;
oss << "设置相位:" << phaseId;
player->GetSession()->SendAreaTriggerMessage(oss.str().c_str());
}
}
break;
case gob_ACTION_TYPE_MORPH:
{
uint32 displayId = i_actionParam1;
if (displayId > 0)
{
player->SetDisplayId(displayId);
std::ostringstream oss;
oss << "变形为模型:" << displayId;
player->GetSession()->SendAreaTriggerMessage(oss.str().c_str());
}
}
break;
case gob_ACTION_TYPE_DEMORPH:
{
player->DeMorph();
player->GetSession()->SendAreaTriggerMessage("取消变形");
}
break;
case gob_ACTION_TYPE_ACTIVE_OR_DEACTIVE_OBJECT:
{
@ -190,19 +404,66 @@ void CustomScript::ExecuteScript(Player* player, GameObject* gob)
bool isCreature = i_actionParam1 > 0;
uint32 summonEntry = abs(i_actionParam1);
uint32 despawntime = i_actionParam2 * MINUTE * IN_MILLISECONDS;
uint32 summonCount = i_actionParam3 > 0 ? i_actionParam3 : 1; // 召唤数量
float offsetRange = !s_actionParam4.empty() ? atof(s_actionParam4.c_str()) : 0.0f; // 位置偏移
if (isCreature)
gob->SummonCreature(summonEntry, gob->GetPositionX(), gob->GetPositionY(),
gob->GetPositionZ(), gob->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, despawntime);
else
gob->SummonGameObject(summonEntry, gob->GetPositionX(), gob->GetPositionY(),
gob->GetPositionZ(), gob->GetOrientation(), 0, 0, 0, 0, despawntime);
for (uint32 i = 0; i < summonCount; ++i)
{
float x = gob->GetPositionX();
float y = gob->GetPositionY();
float z = gob->GetPositionZ();
float o = gob->GetOrientation();
// 如果设置了偏移范围,随机偏移位置
if (offsetRange > 0.0f)
{
float angle = frand(0.0f, 2 * M_PI);
float distance = frand(0.0f, offsetRange);
x += distance * cos(angle);
y += distance * sin(angle);
}
if (isCreature)
gob->SummonCreature(summonEntry, x, y, z, o, TEMPSUMMON_TIMED_DESPAWN, despawntime);
else
gob->SummonGameObject(summonEntry, x, y, z, o, 0, 0, 0, 0, despawntime);
}
}
break;
case gob_ACTION_TYPE_PLAYER_EMOTE:
{
uint32 emoteId = i_actionParam1; // 比如 EMOTE_ONESHOT_DANCE
player->HandleEmoteCommand(emoteId);
}
break;
}
}
}
bool CustomScript::CheckCondition(Player* player, int32 conditionType, int32 value)
{
switch (conditionType)
{
case 1: // 等级检查
return player->GetLevel() >= value;
case 2: // 金钱检查
return player->GetMoney() >= value;
case 3: // 职业检查
return player->getClass() == value;
case 4: // 物品检查
return player->HasItemCount(value, 1);
case 5: // 任务状态检查
return player->GetQuestStatus(value) == QUEST_STATUS_COMPLETE;
case 6: // 光环检查
return player->HasAura(value);
case 7: // 技能检查
return player->HasSpell(value);
default:
return true;
}
}
void CustomScript::Tele(Player* player, uint32 telePosId)
{
// 这里需要访问PosMap可能需要从Event模块获取