diff --git a/src/game/Map.cpp b/src/game/Map.cpp index d8ad165bb..b256ac60a 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -2856,50 +2856,95 @@ void Map::ScriptsProcess() { if (!source) { - sLog.outError("SCRIPT_COMMAND_TALK (script id %u) call for NULL creature.", step.script->id); + sLog.outError("SCRIPT_COMMAND_TALK (script id %u) call for NULL source.", step.script->id); break; } - if (source->GetTypeId() != TYPEID_UNIT) + WorldObject* pSource = dynamic_cast(source); + + if (!pSource) { - sLog.outError("SCRIPT_COMMAND_TALK (script id %u) call for non-creature (TypeId: %u), skipping.", step.script->id, source->GetTypeId()); + sLog.outError("SCRIPT_COMMAND_TALK (script id %u) call for unsupported non-worldobject (TypeId: %u), skipping.", step.script->id, source->GetTypeId()); break; } + Creature* pBuddy = NULL; + + // flag_target_player_as_source 0x01 + // flag_original_source_as_target 0x02 + // flag_buddy_as_target 0x04 + + // If target is player (and not already the source) but should be the source + if (target && target->GetTypeId() == TYPEID_PLAYER && step.script->data_flags & 0x01) + { + if (source->GetTypeId() != TYPEID_PLAYER) + pSource = (WorldObject*)target; + } + + // If step has a buddy entry defined, search for it. + if (step.script->datalong2) + { + MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*pSource, step.script->datalong2, true, step.script->datalong3); + MaNGOS::CreatureLastSearcher searcher(pSource, pBuddy, u_check); + + Cell::VisitGridObjects(pSource, searcher, step.script->datalong3); + } + + // If buddy found, then use it + if (pBuddy) + { + // pBuddy can be target of talk + if (step.script->data_flags & 0x04) + { + target = (Object*)pBuddy; + } + else + { + // If not target of talk, then set pBuddy as source + // Useless when source is already flagged to be player, and should maybe produce error. + if (!(step.script->data_flags & 0x01)) + pSource = (WorldObject*)pBuddy; + } + } + + // If we should talk to the original source instead of target + if (step.script->data_flags & 0x02) + target = source; + uint64 unit_target = target ? target->GetGUID() : 0; switch(step.script->datalong) { case CHAT_TYPE_SAY: - ((Creature*)source)->Say(step.script->dataint, LANG_UNIVERSAL, unit_target); + pSource->MonsterSay(step.script->dataint, LANG_UNIVERSAL, unit_target); break; case CHAT_TYPE_YELL: - ((Creature*)source)->Yell(step.script->dataint, LANG_UNIVERSAL, unit_target); + pSource->MonsterYell(step.script->dataint, LANG_UNIVERSAL, unit_target); break; case CHAT_TYPE_TEXT_EMOTE: - ((Creature*)source)->TextEmote(step.script->dataint, unit_target); + pSource->MonsterTextEmote(step.script->dataint, unit_target); break; case CHAT_TYPE_BOSS_EMOTE: - ((Creature*)source)->TextEmote(step.script->dataint, unit_target, true); + pSource->MonsterTextEmote(step.script->dataint, unit_target, true); break; case CHAT_TYPE_WHISPER: - if (!unit_target) + if (!unit_target || !IS_PLAYER_GUID(unit_target)) { - sLog.outError("SCRIPT_COMMAND_TALK (script id %u) attempt to whisper (%u) 0-guid, skipping.", step.script->id, step.script->datalong); + sLog.outError("SCRIPT_COMMAND_TALK (script id %u) attempt to whisper (%u) 0-guid or non-player, skipping.", step.script->id, step.script->datalong); break; } - ((Creature*)source)->Whisper(step.script->dataint, unit_target); + pSource->MonsterWhisper(step.script->dataint, unit_target); break; case CHAT_TYPE_BOSS_WHISPER: - if (!unit_target) + if (!unit_target || !IS_PLAYER_GUID(unit_target)) { - sLog.outError("SCRIPT_COMMAND_TALK (script id %u) attempt to whisper (%u) 0-guid, skipping.", step.script->id, step.script->datalong); + sLog.outError("SCRIPT_COMMAND_TALK (script id %u) attempt to whisper (%u) 0-guid or non-player, skipping.", step.script->id, step.script->datalong); break; } - ((Creature*)source)->Whisper(step.script->dataint, unit_target, true); + pSource->MonsterWhisper(step.script->dataint, unit_target, true); break; case CHAT_TYPE_ZONE_YELL: - ((Creature*)source)->YellToZone(step.script->dataint, LANG_UNIVERSAL, unit_target); + pSource->MonsterYellToZone(step.script->dataint, LANG_UNIVERSAL, unit_target); break; default: break; // must be already checked at load diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index aba985b86..50c1c84a4 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -4200,19 +4200,29 @@ void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename) { case SCRIPT_COMMAND_TALK: { - if(tmp.datalong > CHAT_TYPE_ZONE_YELL) + if (tmp.datalong > CHAT_TYPE_ZONE_YELL) { - sLog.outErrorDb("Table `%s` has invalid CHAT_TYPE_ (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.datalong,tmp.id); + sLog.outErrorDb("Table `%s` has invalid CHAT_TYPE_ (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u", tablename, tmp.datalong, tmp.id); continue; } - if(tmp.dataint==0) + if (tmp.datalong2 && !GetCreatureTemplate(tmp.datalong2)) { - sLog.outErrorDb("Table `%s` has invalid talk text id (dataint = %i) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.dataint,tmp.id); + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_TALK for script id %u, but this creature_template does not exist.", tablename, tmp.datalong2, tmp.id); continue; } - if(tmp.dataint < MIN_DB_SCRIPT_STRING_ID || tmp.dataint >= MAX_DB_SCRIPT_STRING_ID) + if (tmp.datalong2 && !tmp.datalong3) { - sLog.outErrorDb("Table `%s` has out of range text id (dataint = %i expected %u-%u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.dataint,MIN_DB_SCRIPT_STRING_ID,MAX_DB_SCRIPT_STRING_ID,tmp.id); + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_TALK for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.datalong2, tmp.id, tmp.datalong3); + continue; + } + if (tmp.dataint == 0) + { + sLog.outErrorDb("Table `%s` has invalid talk text id (dataint = %i) in SCRIPT_COMMAND_TALK for script id %u", tablename, tmp.dataint, tmp.id); + continue; + } + if (tmp.dataint < MIN_DB_SCRIPT_STRING_ID || tmp.dataint >= MAX_DB_SCRIPT_STRING_ID) + { + sLog.outErrorDb("Table `%s` has out of range text id (dataint = %i expected %u-%u) in SCRIPT_COMMAND_TALK for script id %u", tablename, tmp.dataint, MIN_DB_SCRIPT_STRING_ID, MAX_DB_SCRIPT_STRING_ID, tmp.id); continue; } diff --git a/src/game/World.h b/src/game/World.h index fb95ac6b8..b3360e0ce 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -386,7 +386,11 @@ enum RealmZone }; // DB scripting commands -#define SCRIPT_COMMAND_TALK 0 // source = unit, target=any, datalong (see enum ChatType for supported CHAT_TYPE_'s) +#define SCRIPT_COMMAND_TALK 0 // source = WorldObject, target = any/none, datalong (see enum ChatType for supported CHAT_TYPE_'s) + // datalong2 = creature entry (searching for a buddy, closest to source), datalong3 = creature search radius + // data_flags = flag_target_player_as_source = 0x01 + // flag_original_source_as_target = 0x02 + // flag_buddy_as_target = 0x04 #define SCRIPT_COMMAND_EMOTE 1 // source = unit, datalong = anim_id #define SCRIPT_COMMAND_FIELD_SET 2 // source = any, datalong = field_id, datalog2 = value #define SCRIPT_COMMAND_MOVE_TO 3 // source = Creature, datalog2 = time, x/y/z diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 9db420bb2..92249a8b1 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 "9888" + #define REVISION_NR "9889" #endif // __REVISION_NR_H__