Skip to content

Commit

Permalink
Item/Misc: Implement Toy Train Set and Wind-Up Train Wrecker.
Browse files Browse the repository at this point in the history
  • Loading branch information
Treeston committed Jan 18, 2016
1 parent 11a330e commit 8c7cd03
Show file tree
Hide file tree
Showing 8 changed files with 239 additions and 0 deletions.
6 changes: 6 additions & 0 deletions sql/updates/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");
12 changes: 12 additions & 0 deletions src/server/game/DataStores/DBCStores.cpp
Expand Up @@ -91,6 +91,9 @@ DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore(DurabilityCostsfmt);

DBCStorage <EmotesEntry> sEmotesStore(EmotesEntryfmt);
DBCStorage <EmotesTextEntry> sEmotesTextStore(EmotesTextEntryfmt);
typedef std::tuple<uint32, uint32, uint32> EmotesTextSoundKey;
static std::map<EmotesTextSoundKey, EmotesTextSoundEntry const*> sEmotesTextSoundMap;
DBCStorage <EmotesTextSoundEntry> sEmotesTextSoundStore(EmotesTextSoundEntryfmt);

typedef std::map<uint32, SimpleFactionsList> FactionTeamMap;
static FactionTeamMap sFactionTeamMap;
Expand Down Expand Up @@ -338,6 +341,10 @@ void LoadDBCStores(const std::string& dataPath)
LoadDBC(availableDbcLocales, bad_dbc_files, sDurabilityQualityStore, dbcPath, "DurabilityQuality.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sEmotesStore, dbcPath, "Emotes.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sEmotesTextStore, dbcPath, "EmotesText.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sEmotesTextSoundStore, dbcPath, "EmotesTextSound.dbc");
for (uint32 i = 0; i < sEmotesTextSoundStore.GetNumRows(); ++i)
if (EmotesTextSoundEntry const* entry = sEmotesTextSoundStore.LookupEntry(i))
sEmotesTextSoundMap[EmotesTextSoundKey(entry->EmotesTextId, entry->RaceId, entry->SexId)] = entry;
LoadDBC(availableDbcLocales, bad_dbc_files, sFactionStore, dbcPath, "Faction.dbc");
for (uint32 i=0; i<sFactionStore.GetNumRows(); ++i)
{
Expand Down Expand Up @@ -1060,3 +1067,8 @@ ResponseCodes ValidateName(std::string const& name, LocaleConstant locale)

return CHAR_NAME_SUCCESS;
}

EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender)
{
return sEmotesTextSoundMap[EmotesTextSoundKey(emote, race, gender)];
}
3 changes: 3 additions & 0 deletions src/server/game/DataStores/DBCStores.h
Expand Up @@ -82,6 +82,8 @@ SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, u

ResponseCodes ValidateName(std::string const& name, LocaleConstant locale);

EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender);

extern DBCStorage <AchievementEntry> sAchievementStore;
extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore;
extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions
Expand Down Expand Up @@ -113,6 +115,7 @@ extern DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore;
extern DBCStorage <DurabilityQualityEntry> sDurabilityQualityStore;
extern DBCStorage <EmotesEntry> sEmotesStore;
extern DBCStorage <EmotesTextEntry> sEmotesTextStore;
extern DBCStorage <EmotesTextSoundEntry> sEmotesTextSoundStore;
extern DBCStorage <FactionEntry> sFactionStore;
extern DBCStorage <FactionTemplateEntry> sFactionTemplateStore;
extern DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore;
Expand Down
9 changes: 9 additions & 0 deletions src/server/game/DataStores/DBCStructure.h
Expand Up @@ -926,6 +926,15 @@ struct EmotesTextEntry
uint32 textid;
};

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 m_ID
Expand Down
1 change: 1 addition & 0 deletions src/server/game/DataStores/DBCfmt.h
Expand Up @@ -52,6 +52,7 @@ char const DurabilityCostsfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiii";
char const DurabilityQualityfmt[] = "nf";
char const EmotesEntryfmt[] = "nxxiiix";
char const EmotesTextEntryfmt[] = "nxixxxxxxxxxxxxxxxx";
char const EmotesTextSoundEntryfmt[] = "niiii";
char const FactionEntryfmt[] = "niiiiiiiiiiiiiiiiiiffixssssssssssssssssxxxxxxxxxxxxxxxxxx";
char const FactionTemplateEntryfmt[] = "niiiiiiiiiiiii";
char const GameObjectDisplayInfofmt[] = "nsxxxxxxxxxxffffffx";
Expand Down
39 changes: 39 additions & 0 deletions src/server/scripts/Spells/spell_item.cpp
Expand Up @@ -29,6 +29,7 @@
#include "SpellAuraEffects.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
Expand Down Expand Up @@ -2630,6 +2631,43 @@ class spell_item_greatmothers_soulcatcher : public SpellScriptLoader
}
};

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
Expand Down Expand Up @@ -2698,4 +2736,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();
}
44 changes: 44 additions & 0 deletions src/server/scripts/World/go_scripts.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -1196,6 +1197,48 @@ class go_midsummer_bonfire : public GameObjectScript
}
};


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();
Expand Down Expand Up @@ -1231,4 +1274,5 @@ void AddSC_go_scripts()
new go_veil_skith_cage();
new go_frostblade_shrine();
new go_midsummer_bonfire();
new go_toy_train_set();
}
125 changes: 125 additions & 0 deletions src/server/scripts/World/npcs_special.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -2387,6 +2388,129 @@ class npc_stable_master : public CreatureScript
}
};

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
};
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->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();
Expand All @@ -2410,4 +2534,5 @@ void AddSC_npcs_special()
new npc_spring_rabbit();
new npc_imp_in_a_ball();
new npc_stable_master();
new npc_train_wrecker();
}

0 comments on commit 8c7cd03

Please sign in to comment.