diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 6d4ab0477..66a2f2d1a 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -208,6 +208,11 @@ spell_scripts * datalong2=creature entry * datalong3=search radius +26 SCRIPT_COMMAND_ATTACK_START source = WorldObject (but Creature must be final source/attacker, set with datalong-fields where needed), target = Unit/none + * datalong2 = creature entry (searching for a buddy, closest to source) + * datalong3 = creature search radius + * data_flags = flag_original_source_as_target = 0x02 + flag_buddy_as_target = 0x04 (When this flag is not set, buddy will be the attacker when buddy is defined) diff --git a/src/game/Map.cpp b/src/game/Map.cpp index b4e4bf5f2..747088e62 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -2853,6 +2853,77 @@ void Map::ScriptsProcess() break; } + case SCRIPT_COMMAND_ATTACK_START: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_ATTACK_START (script id %u) call for NULL source.", step.script->id); + break; + } + + if (!source->isType(TYPEMASK_WORLDOBJECT)) + { + sLog.outError("SCRIPT_COMMAND_ATTACK_START (script id %u) call for unsupported non-worldobject (TypeId: %u), skipping.", step.script->id, source->GetTypeId()); + break; + } + + WorldObject* pSource = (WorldObject*)source; + Creature* pBuddy = NULL; + + // flag_original_source_as_target 0x02 + // flag_buddy_as_target 0x04 + + // If step has a buddy entry defined, search for it. + if (step.script->attack.creatureEntry) + { + MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*pSource, step.script->attack.creatureEntry, true, step.script->attack.searchRadius); + MaNGOS::CreatureLastSearcher searcher(pBuddy, u_check); + + Cell::VisitGridObjects(pSource, searcher, step.script->attack.searchRadius); + + // If buddy found, then use it + if (pBuddy) + { + if (step.script->attack.flags & 0x04) + { + // pBuddy is target of attack + target = (Object*)pBuddy; + } + else + { + // If not target of attack, then set pBuddy as source, the attacker + pSource = (WorldObject*)pBuddy; + } + } + else + { + // No buddy found, so don't do anything + break; + } + } + + // If we should attack the original source instead of target + if (step.script->attack.flags & 0x02) + target = source; + + Unit* unitTarget = target && target->isType(TYPEMASK_UNIT) ? static_cast(target) : NULL; + Creature* pAttacker = pSource && pSource->GetTypeId() == TYPEID_UNIT ? static_cast(pSource) : NULL; + + if (pAttacker && unitTarget) + { + if (pAttacker->IsFriendlyTo(unitTarget)) + { + sLog.outError("SCRIPT_COMMAND_ATTACK_START (script id %u) attacker is friendly to target, can not attack.", step.script->id); + break; + } + + pAttacker->AI()->AttackStart(unitTarget); + break; + } + + sLog.outError("SCRIPT_COMMAND_ATTACK_START (script id %u) unexpected error, attacker or victim could not be found, no action.", step.script->id); + break; + } default: sLog.outError("Unknown SCRIPT_COMMAND_ %u called for script id %u.",step.script->command, step.script->id); break; diff --git a/src/game/ScriptMgr.cpp b/src/game/ScriptMgr.cpp index c6f2eb8c4..ef0ec43c6 100644 --- a/src/game/ScriptMgr.cpp +++ b/src/game/ScriptMgr.cpp @@ -519,6 +519,20 @@ void ScriptMgr::LoadScripts(ScriptMapMap& scripts, const char* tablename) break; } + case SCRIPT_COMMAND_ATTACK_START: + { + if (tmp.attack.creatureEntry && !ObjectMgr::GetCreatureTemplate(tmp.attack.creatureEntry)) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_ATTACK_START for script id %u, but this creature_template does not exist.", tablename, tmp.attack.creatureEntry, tmp.id); + continue; + } + if (tmp.attack.creatureEntry && !tmp.attack.searchRadius) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_ATTACK_START for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.attack.creatureEntry, tmp.id, tmp.attack.searchRadius); + continue; + } + break; + } } if (scripts.find(tmp.id) == scripts.end()) diff --git a/src/game/ScriptMgr.h b/src/game/ScriptMgr.h index 41e6af166..2115ff1ac 100644 --- a/src/game/ScriptMgr.h +++ b/src/game/ScriptMgr.h @@ -90,6 +90,8 @@ enum eScriptCommand SCRIPT_COMMAND_SET_RUN = 25, // source=any, target=creature // datalong= bool 0=off, 1=on // datalong2=creature entry, datalong3=search radius + SCRIPT_COMMAND_ATTACK_START = 26, // source = Creature (or WorldObject when creature entry are defined), target = Player + // datalong2 = creature entry (searching for a buddy, closest to source), datalong3 = creature search radius }; #define MAX_TEXT_ID 4 // used for SCRIPT_COMMAND_TALK @@ -271,6 +273,15 @@ struct ScriptInfo uint32 searchRadius; // datalong3 } run; + struct // SCRIPT_COMMAND_ATTACK_START (26) + { + uint32 empty1; // datalong + uint32 creatureEntry; // datalong2 + uint32 searchRadius; // datalong3 + uint32 empty2; // datalong4 + uint32 flags; // data_flags + } attack; + struct { uint32 data[9]; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index b54e95b7c..46b4ce757 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "11310" + #define REVISION_NR "11311" #endif // __REVISION_NR_H__