diff --git a/doc/script_commands.txt b/doc/script_commands.txt index bf6b71c0b..6d4ab0477 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -101,8 +101,11 @@ spell_scripts flag_buddy_as_target = 0x04 * dataint = text entry from db_script_string -table. dataint2-dataint4 optionally, for random selection of text - 1 SCRIPT_COMMAND_EMOTE source = unit + 1 SCRIPT_COMMAND_EMOTE source = Unit (or WorldObject when creature entry defined), target = Unit (or none) * datalong = emote_id + * datalong2 = creature entry (searching for a buddy, closest to source) + * datalong3 = creature search radius + * data_flags = flag_target_as_source = 0x01 2 SCRIPT_COMMAND_FIELD_SET source = any * datalong = field_id diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 3c0dbf7cd..9f6315517 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -1912,20 +1912,56 @@ void Map::ScriptsProcess() break; } case SCRIPT_COMMAND_EMOTE: + { if (!source) { - sLog.outError("SCRIPT_COMMAND_EMOTE (script id %u) call for NULL creature.", step.script->id); + sLog.outError("SCRIPT_COMMAND_EMOTE (script id %u) call for NULL source.", step.script->id); break; } - if (source->GetTypeId()!=TYPEID_UNIT) + if (!source->isType(TYPEMASK_WORLDOBJECT)) { - sLog.outError("SCRIPT_COMMAND_EMOTE (script id %u) call for non-creature (TypeId: %u), skipping.", step.script->id, source->GetTypeId()); + sLog.outError("SCRIPT_COMMAND_EMOTE (script id %u) call for non-worldobject (TypeId: %u), skipping.", step.script->id, source->GetTypeId()); break; } + // When creatureEntry is not defined, GameObject can not be source + else if (!step.script->emote.creatureEntry) + { + if (!source->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_EMOTE (script id %u) are missing datalong2 (creature entry). Unsupported call for non-unit (TypeId: %u), skipping.", step.script->id, source->GetTypeId()); + break; + } + } - ((Creature*)source)->HandleEmote(step.script->emote.emoteId); + WorldObject* pSource = (WorldObject*)source; + Creature* pBuddy = NULL; + + // flag_target_as_source 0x01 + + // If target is Unit* and should do the emote (or should be source of searcher below) + if (target && target->isType(TYPEMASK_UNIT) && step.script->emote.flags & 0x01) + pSource = (WorldObject*)target; + + // If step has a buddy entry defined, search for it. + if (step.script->emote.creatureEntry) + { + MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*pSource, step.script->emote.creatureEntry, true, step.script->emote.searchRadius); + MaNGOS::CreatureLastSearcher searcher(pBuddy, u_check); + + Cell::VisitGridObjects(pSource, searcher, step.script->emote.searchRadius); + + // If buddy found, then use it or break (break since we must assume pBuddy was defined for a reason) + if (pBuddy) + pSource = (WorldObject*)pBuddy; + else + break; + } + + // Must be safe cast to Unit* + ((Unit*)pSource)->HandleEmote(step.script->emote.emoteId); break; + } case SCRIPT_COMMAND_FIELD_SET: if (!source) { diff --git a/src/game/ScriptMgr.cpp b/src/game/ScriptMgr.cpp index 76cbdeb66..c6f2eb8c4 100644 --- a/src/game/ScriptMgr.cpp +++ b/src/game/ScriptMgr.cpp @@ -175,6 +175,16 @@ void ScriptMgr::LoadScripts(ScriptMapMap& scripts, const char* tablename) sLog.outErrorDb("Table `%s` has invalid emote id (datalong = %u) in SCRIPT_COMMAND_EMOTE for script id %u", tablename, tmp.emote.emoteId, tmp.id); continue; } + if (tmp.emote.creatureEntry && !ObjectMgr::GetCreatureTemplate(tmp.emote.creatureEntry)) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_EMOTE for script id %u, but this creature_template does not exist.", tablename, tmp.emote.creatureEntry, tmp.id); + continue; + } + if (tmp.emote.creatureEntry && !tmp.emote.searchRadius) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_EMOTE for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.emote.creatureEntry, tmp.id, tmp.emote.searchRadius); + continue; + } break; } case SCRIPT_COMMAND_TELEPORT_TO: diff --git a/src/game/ScriptMgr.h b/src/game/ScriptMgr.h index 33b5766fb..41e6af166 100644 --- a/src/game/ScriptMgr.h +++ b/src/game/ScriptMgr.h @@ -48,7 +48,10 @@ enum eScriptCommand // flag_original_source_as_target = 0x02 // flag_buddy_as_target = 0x04 // dataint = text entry from db_script_string -table. dataint2-4 optional for random selected text. - SCRIPT_COMMAND_EMOTE = 1, // source = unit, datalong = emote_id + SCRIPT_COMMAND_EMOTE = 1, // source = Unit (or WorldObject when creature entry defined), target = Unit (or none) + // datalong = emote_id + // datalong2 = creature entry (searching for a buddy, closest to source), datalong3 = creature search radius + // data_flags = flag_target_as_source = 0x01 SCRIPT_COMMAND_FIELD_SET = 2, // source = any, datalong = field_id, datalong2 = value SCRIPT_COMMAND_MOVE_TO = 3, // source = Creature, datalong2 = time, x/y/z SCRIPT_COMMAND_FLAG_SET = 4, // source = any, datalong = field_id, datalong2 = bitmask @@ -112,6 +115,10 @@ struct ScriptInfo struct // SCRIPT_COMMAND_EMOTE (1) { uint32 emoteId; // datalong + uint32 creatureEntry; // datalong2 + uint32 searchRadius; // datalong3 + uint32 unused1; // datalong4 + uint32 flags; // data_flags } emote; struct // SCRIPT_COMMAND_FIELD_SET (2) diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 0c5d82109..1fa9d3cb3 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 "11308" + #define REVISION_NR "11309" #endif // __REVISION_NR_H__