aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/world/2016_04_02_20_world_2016_01_09_toytrain.sql6
-rw-r--r--src/server/game/DataStores/DBCStores.cpp14
-rw-r--r--src/server/game/DataStores/DBCStores.h3
-rw-r--r--src/server/game/DataStores/DBCStructure.h9
-rw-r--r--src/server/game/DataStores/DBCfmt.h1
-rw-r--r--src/server/scripts/Spells/spell_item.cpp39
-rw-r--r--src/server/scripts/World/go_scripts.cpp44
-rw-r--r--src/server/scripts/World/npcs_special.cpp129
8 files changed, 245 insertions, 0 deletions
diff --git a/sql/updates/world/2016_04_02_20_world_2016_01_09_toytrain.sql b/sql/updates/world/2016_04_02_20_world_2016_01_09_toytrain.sql
new file mode 100644
index 00000000000..fc0b8a0cda0
--- /dev/null
+++ b/sql/updates/world/2016_04_02_20_world_2016_01_09_toytrain.sql
@@ -0,0 +1,6 @@
+--
+UPDATE `gameobject_template` SET `ScriptName`="go_toy_train_set" WHERE `entry`=193963;
+UPDATE `creature_template` SET `ScriptName`="npc_train_wrecker" WHERE `entry`=33404;
+DELETE FROM `spell_script_names` WHERE `spell_id`=61551;
+INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES
+(61551,"spell_item_toy_train_set_pulse");
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index 460a9e5dac2..921db480853 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -75,6 +75,9 @@ DBCStorage<DurabilityCostsEntry> sDurabilityCostsStore(DurabilityCost
DBCStorage<EmotesEntry> sEmotesStore(Emotesfmt);
DBCStorage<EmotesTextEntry> sEmotesTextStore(EmotesTextfmt);
+typedef std::tuple<uint32, uint32, uint32> EmotesTextSoundKey;
+static std::map<EmotesTextSoundKey, EmotesTextSoundEntry const*> sEmotesTextSoundMap;
+DBCStorage <EmotesTextSoundEntry> sEmotesTextSoundStore(EmotesTextSoundEntryfmt);
DBCStorage<FactionEntry> sFactionStore(Factionfmt);
static FactionTeamMap sFactionTeamMap;
@@ -314,6 +317,7 @@ void LoadDBCStores(const std::string& dataPath, uint32 defaultLocale)
LOAD_DBC(sDurabilityCostsStore, "DurabilityCosts.dbc");//20444
LOAD_DBC(sEmotesStore, "Emotes.dbc");//20444
LOAD_DBC(sEmotesTextStore, "EmotesText.dbc");//20444
+ LOAD_DBC(sEmotesTextSoundStore, "EmotesTextSound.dbc");
LOAD_DBC(sFactionStore, "Faction.dbc");//20444
LOAD_DBC(sFactionTemplateStore, "FactionTemplate.dbc");//20444
LOAD_DBC(sGameObjectDisplayInfoStore, "GameObjectDisplayInfo.dbc");//20444
@@ -392,6 +396,10 @@ void LoadDBCStores(const std::string& dataPath, uint32 defaultLocale)
"MAX_DIFFICULTY is not large enough to contain all difficulties! (current value %d, required %d)",
MAX_DIFFICULTY, sDifficultyStore.GetNumRows());
+ for (uint32 i = 0; i < sEmotesTextSoundStore.GetNumRows(); ++i)
+ if (EmotesTextSoundEntry const* entry = sEmotesTextSoundStore.LookupEntry(i))
+ sEmotesTextSoundMap[EmotesTextSoundKey(entry->EmotesTextId, entry->RaceId, entry->SexId)] = entry;
+
for (uint32 i = 0; i < sFactionStore.GetNumRows(); ++i)
{
FactionEntry const* faction = sFactionStore.LookupEntry(i);
@@ -562,6 +570,12 @@ char const* GetCreatureFamilyPetName(uint32 petfamily, uint32 /*locale*/)
return pet_family->Name_lang ? pet_family->Name_lang : NULL;
}
+EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender)
+{
+ auto itr = sEmotesTextSoundMap.find(EmotesTextSoundKey(emote, race, gender));
+ return itr != sEmotesTextSoundMap.end() ? itr->second : nullptr;
+}
+
WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid)
{
WMOAreaInfoByTripple::iterator i = sWMOAreaInfoByTripple.find(WMOAreaTableTripple(rootid, adtid, groupid));
diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
index 2f30a00d3c0..7c7647dd4d9 100644
--- a/src/server/game/DataStores/DBCStores.h
+++ b/src/server/game/DataStores/DBCStores.h
@@ -39,6 +39,9 @@ typedef ChrSpecializationEntry const* ChrSpecializationByIndexArray[MAX_CLASSES]
// CreatureFamilty
TC_GAME_API char const* GetCreatureFamilyPetName(uint32 petfamily, uint32 locale);
+// EmotesText
+TC_GAME_API EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender);
+
// Faction
TC_GAME_API std::vector<uint32> const* GetFactionTeamList(uint32 faction);
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index ec334fb3b8f..96a93832e09 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -393,6 +393,15 @@ struct EmotesTextEntry
//uint32 EmoteText[16]; // 3-18
};
+struct EmotesTextSoundEntry
+{
+ uint32 Id; // 0
+ uint32 EmotesTextId; // 1
+ uint32 RaceId; // 2
+ uint32 SexId; // 3, 0 male / 1 female
+ uint32 SoundId; // 4
+};
+
struct FactionEntry
{
uint32 ID; // 0
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index d52891576da..16f5383c343 100644
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -43,6 +43,7 @@ char const DungeonEncounterfmt[] = "niiixsxxx";
char const DurabilityCostsfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiii";
char const Emotesfmt[] = "nxxiiixx";
char const EmotesTextfmt[] = "nxixxxxxxxxxxxxxxxx";
+char const EmotesTextSoundEntryfmt[] = "niiii";
char const Factionfmt[] = "niiiiiiiiiiiiiiiiiiffixsxixx";
char const FactionTemplatefmt[] = "niiiiiiiiiiiii";
char const GameObjectDisplayInfofmt[] = "nixxxxxxxxxxffffffxxx";
diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp
index 824f2b30096..23dfd4d85a7 100644
--- a/src/server/scripts/Spells/spell_item.cpp
+++ b/src/server/scripts/Spells/spell_item.cpp
@@ -29,6 +29,7 @@
#include "SpellHistory.h"
#include "SkillDiscovery.h"
#include "Battleground.h"
+#include "DBCStores.h"
// Generic script for handling item dummy effects which trigger another spell.
class spell_item_trigger_spell : public SpellScriptLoader
@@ -2591,6 +2592,43 @@ public:
}
};
+class spell_item_toy_train_set_pulse : public SpellScriptLoader
+{
+public:
+ spell_item_toy_train_set_pulse() : SpellScriptLoader("spell_item_toy_train_set_pulse") { }
+
+ class spell_item_toy_train_set_pulse_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_item_toy_train_set_pulse_SpellScript);
+
+ void HandleDummy(SpellEffIndex /*index*/)
+ {
+ if (Player* target = GetHitUnit()->ToPlayer())
+ {
+ target->HandleEmoteCommand(EMOTE_ONESHOT_TRAIN);
+ if (EmotesTextSoundEntry const* soundEntry = FindTextSoundEmoteFor(TEXT_EMOTE_TRAIN, target->getRace(), target->getGender()))
+ target->PlayDistanceSound(soundEntry->SoundId);
+ }
+ }
+
+ void HandleTargets(std::list<WorldObject*>& targetList)
+ {
+ targetList.remove_if([](WorldObject const* obj) { return obj->GetTypeId() != TYPEID_PLAYER; });
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_item_toy_train_set_pulse_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_item_toy_train_set_pulse_SpellScript::HandleTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ALLY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_item_toy_train_set_pulse_SpellScript();
+ }
+};
+
void AddSC_item_spell_scripts()
{
// 23074 Arcanite Dragonling
@@ -2658,4 +2696,5 @@ void AddSC_item_spell_scripts()
new spell_item_chicken_cover();
new spell_item_muisek_vessel();
new spell_item_greatmothers_soulcatcher();
+ new spell_item_toy_train_set_pulse();
}
diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp
index 70520d0a67e..8748c8a8fd8 100644
--- a/src/server/scripts/World/go_scripts.cpp
+++ b/src/server/scripts/World/go_scripts.cpp
@@ -41,6 +41,7 @@ go_tadpole_cage
go_amberpine_outhouse
go_hive_pod
go_veil_skith_cage
+go_toy_train_set
EndContentData */
#include "ScriptMgr.h"
@@ -1125,6 +1126,48 @@ public:
}
};
+
+enum ToyTrainSpells
+{
+ SPELL_TOY_TRAIN_PULSE = 61551,
+};
+
+class go_toy_train_set : public GameObjectScript
+{
+ public:
+ go_toy_train_set() : GameObjectScript("go_toy_train_set") { }
+
+ struct go_toy_train_setAI : public GameObjectAI
+ {
+ go_toy_train_setAI(GameObject* go) : GameObjectAI(go), _pulseTimer(3 * IN_MILLISECONDS) { }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (diff < _pulseTimer)
+ _pulseTimer -= diff;
+ else
+ {
+ go->CastSpell(nullptr, SPELL_TOY_TRAIN_PULSE, true);
+ _pulseTimer = 6 * IN_MILLISECONDS;
+ }
+ }
+
+ // triggered on wrecker'd
+ void DoAction(int32 /*action*/) override
+ {
+ go->Delete();
+ }
+
+ private:
+ uint32 _pulseTimer;
+ };
+
+ GameObjectAI* GetAI(GameObject* go) const override
+ {
+ return new go_toy_train_setAI(go);
+ }
+};
+
void AddSC_go_scripts()
{
new go_cat_figurine();
@@ -1160,4 +1203,5 @@ void AddSC_go_scripts()
new go_veil_skith_cage();
new go_frostblade_shrine();
new go_midsummer_bonfire();
+ new go_toy_train_set();
}
diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp
index 62d6bce57c9..3b00c5e32d3 100644
--- a/src/server/scripts/World/npcs_special.cpp
+++ b/src/server/scripts/World/npcs_special.cpp
@@ -38,6 +38,7 @@ npc_snake_trap_serpents 80% AI for snakes that summoned by Snake Trap
npc_shadowfiend 100% restore 5% of owner's mana when shadowfiend die from damage
npc_locksmith 75% list of keys needs to be confirmed
npc_firework 100% NPC's summoned by rockets and rocket clusters, for making them cast visual
+npc_train_wrecker 100% Wind-Up Train Wrecker that kills train set
EndContentData */
#include "ScriptMgr.h"
@@ -49,6 +50,7 @@ EndContentData */
#include "World.h"
#include "PassiveAI.h"
#include "GameEventMgr.h"
+#include "GameObjectAI.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "Cell.h"
@@ -2385,6 +2387,132 @@ public:
}
};
+enum TrainWrecker
+{
+ GO_TOY_TRAIN = 193963,
+ SPELL_TOY_TRAIN_PULSE = 61551,
+ SPELL_WRECK_TRAIN = 62943,
+ ACTION_WRECKED = 1,
+ EVENT_DO_JUMP = 1,
+ EVENT_DO_FACING = 2,
+ EVENT_DO_WRECK = 3,
+ EVENT_DO_DANCE = 4,
+ MOVEID_CHASE = 1,
+ MOVEID_JUMP = 2,
+
+ NPC_EXULTING_WIND_UP_TRAIN_WRECKER = 81071
+};
+class npc_train_wrecker : public CreatureScript
+{
+ public:
+ npc_train_wrecker() : CreatureScript("npc_train_wrecker") { }
+
+ struct npc_train_wreckerAI : public NullCreatureAI
+ {
+ npc_train_wreckerAI(Creature* creature) : NullCreatureAI(creature), _isSearching(true), _nextAction(0), _timer(1 * IN_MILLISECONDS) { }
+
+ GameObject* VerifyTarget() const
+ {
+ if (GameObject* target = ObjectAccessor::GetGameObject(*me, _target))
+ return target;
+ me->HandleEmoteCommand(EMOTE_ONESHOT_RUDE);
+ me->DespawnOrUnsummon(3 * IN_MILLISECONDS);
+ return nullptr;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_isSearching)
+ {
+ if (diff < _timer)
+ _timer -= diff;
+ else
+ {
+ if (GameObject* target = me->FindNearestGameObject(GO_TOY_TRAIN, 15.0f))
+ {
+ _isSearching = false;
+ _target = target->GetGUID();
+ me->SetWalk(true);
+ me->GetMotionMaster()->MovePoint(MOVEID_CHASE, target->GetNearPosition(3.0f, target->GetAngle(me)));
+ }
+ else
+ _timer = 3 * IN_MILLISECONDS;
+ }
+ }
+ else
+ {
+ switch (_nextAction)
+ {
+ case EVENT_DO_JUMP:
+ if (GameObject* target = VerifyTarget())
+ me->GetMotionMaster()->MoveJump(*target, 5.0, 10.0, MOVEID_JUMP);
+ _nextAction = 0;
+ break;
+ case EVENT_DO_FACING:
+ if (GameObject* target = VerifyTarget())
+ {
+ me->SetFacingTo(target->GetOrientation());
+ me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK1H);
+ _timer = 1.5 * IN_MILLISECONDS;
+ _nextAction = EVENT_DO_WRECK;
+ }
+ else
+ _nextAction = 0;
+ break;
+ case EVENT_DO_WRECK:
+ if (diff < _timer)
+ {
+ _timer -= diff;
+ break;
+ }
+ if (GameObject* target = VerifyTarget())
+ {
+ me->CastSpell(target, SPELL_WRECK_TRAIN, false);
+ target->AI()->DoAction(ACTION_WRECKED);
+ _timer = 2 * IN_MILLISECONDS;
+ _nextAction = EVENT_DO_DANCE;
+ }
+ else
+ _nextAction = 0;
+ break;
+ case EVENT_DO_DANCE:
+ if (diff < _timer)
+ {
+ _timer -= diff;
+ break;
+ }
+ me->UpdateEntry(NPC_EXULTING_WIND_UP_TRAIN_WRECKER);
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_DANCE);
+ me->DespawnOrUnsummon(5 * IN_MILLISECONDS);
+ _nextAction = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ void MovementInform(uint32 /*type*/, uint32 id)
+ {
+ if (id == MOVEID_CHASE)
+ _nextAction = EVENT_DO_JUMP;
+ else if (id == MOVEID_JUMP)
+ _nextAction = EVENT_DO_FACING;
+ }
+
+ private:
+ bool _isSearching;
+ uint8 _nextAction;
+ uint32 _timer;
+ ObjectGuid _target;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_train_wreckerAI(creature);
+ }
+};
+
void AddSC_npcs_special()
{
new npc_air_force_bots();
@@ -2408,4 +2536,5 @@ void AddSC_npcs_special()
new npc_firework();
new npc_spring_rabbit();
new npc_imp_in_a_ball();
+ new npc_train_wrecker();
}