-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathnpc_buffer.cpp
329 lines (278 loc) · 12.1 KB
/
npc_buffer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
/*
# Buffer NPC
_This module was created for [StygianCore](https://rebrand.ly/stygiancoreproject). A World of Warcraft 3.3.5a Solo/LAN repack by StygianTheBest | [GitHub](https://rebrand.ly/stygiangithub) | [Website](https://rebrand.ly/stygianthebest))_
### Description
------------------------------------------------------------------------------------------------------------------
This is a one-click buffing NPC that will buff the player with a specific set of spells. The NPC can also buff
everyone the same or by player level. He speaks a configurable random phrase after every use and can also attract
the player using configurable emote options.
- Creates a Buff NPC with emotes
- Buffs the player with no dialogue interaction
- Buffs all the same or by player level
- Speaks configurable random whispers to the player after every use
- Attracts the player using configurable emotes
- Config:
- Buff by level
- Spell ID(s) for buffs
- Enable/Disable cure resurrection sickness
- Emote Options
### Data
------------------------------------------------------------------------------------------------------------------
- Type: NPC (ID: 601016)
- Script: buff_npc
- Config: Yes
- SQL: Yes
### Version
------------------------------------------------------------------------------------------------------------------
- v2024.07.01 - Fix database script to use creature_template_model table. Updated spell list/scaling code. Added Thorns to spell list
- v2019.04.17 - Fix Cure Resurrection Sickness, works now! Courtesy of Poszer and Milestorme
- v2019.04.15 - Ported to AzerothCore by gtao725 (https://github.com/gtao725/)
- v2019.02.13 - Added phrases/emotes, config options, updated AI
- v2017.08.06 - Removed dialogue options (Just buffs player on click)
- v2017.08.05
### CREDITS
------------------------------------------------------------------------------------------------------------------


##### This module was created for [StygianCore](https://rebrand.ly/stygiancoreproject). A World of Warcraft 3.3.5a Solo/LAN repack by StygianTheBest | [GitHub](https://rebrand.ly/stygiangithub) | [Website](https://rebrand.ly/stygianthebest))
#### Additional Credits
- [Blizzard Entertainment](http://blizzard.com)
- [TrinityCore](https://github.com/TrinityCore/TrinityCore/blob/3.3.5/THANKS)
- [SunwellCore](http://www.azerothcore.org/pages/sunwell.pl/)
- [AzerothCore](https://github.com/AzerothCore/azerothcore-wotlk/graphs/contributors)
- [OregonCore](https://wiki.oregon-core.net/)
- [Wowhead.com](http://wowhead.com)
- [OwnedCore](http://ownedcore.com/)
- [ModCraft.io](http://modcraft.io/)
- [MMO Society](https://www.mmo-society.com/)
- [AoWoW](https://wotlk.evowow.com/)
- [More credits are cited in the sources](https://github.com/StygianTheBest)
### LICENSE
------------------------------------------------------------------------------------------------------------------
This code and content is released under the [GNU AGPL v3](https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3).
*/
#include "Chat.h"
#include "Config.h"
#include "Log.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
#include "ScriptMgr.h"
#include "SpellMgr.h"
static bool BFEnableModule;
static bool BFAnnounceModule;
static bool BuffByLevel;
static bool BuffCureRes;
static uint32 BuffNumPhrases;
static uint32 BuffNumWhispers;
static uint32 BuffMessageTimer;
static uint32 BuffEmoteSpell;
static uint32 BuffEmoteCommand;
static uint32 MaxLevel = 80;
class BufferConfig : public WorldScript
{
public:
BufferConfig() : WorldScript("BufferConfig_conf", {
WORLDHOOK_ON_BEFORE_CONFIG_LOAD
}) {}
void OnBeforeConfigLoad(bool /*reload*/) override
{
BFEnableModule = sConfigMgr->GetOption<bool>("Buff.Enable", 1);
BFAnnounceModule = sConfigMgr->GetOption<bool>("Buff.Announce", 1);
BuffByLevel = sConfigMgr->GetOption<bool>("Buff.ByLevel", 1);
BuffCureRes = sConfigMgr->GetOption<bool>("Buff.CureRes", 1);
BuffNumPhrases = sConfigMgr->GetOption<uint32>("Buff.NumPhrases", 3);
BuffNumWhispers = sConfigMgr->GetOption<uint32>("Buff.NumWhispers", 3);
BuffMessageTimer = sConfigMgr->GetOption<uint32>("Buff.MessageTimer", 60000);
BuffEmoteSpell = sConfigMgr->GetOption<uint32>("Buff.EmoteSpell", 44940);
BuffEmoteCommand = sConfigMgr->GetOption<uint32>("Buff.EmoteCommand", 3);
MaxLevel = sConfigMgr->GetOption<uint32>("Buff.MaxLevel", 80);
// Enforce Min/Max Time
if (BuffMessageTimer != 0)
{
if (BuffMessageTimer < 60000 || BuffMessageTimer > 300000)
BuffMessageTimer = 60000;
}
}
};
class BufferAnnounce : public PlayerScript
{
public:
BufferAnnounce() : PlayerScript("BufferAnnounce", {
PLAYERHOOK_ON_LOGIN
}) {}
void OnPlayerLogin(Player *player)
{
// Announce Module
if (BFEnableModule && BFAnnounceModule)
ChatHandler(player->GetSession()).SendSysMessage("This server is running the |cff4CFF00BufferNPC |rmodule.");
}
};
class buff_npc : public CreatureScript
{
public:
buff_npc() : CreatureScript("buff_npc") { }
/** Get the most level-appropriate spell from the chain,
* based on character level compared to max level (MaxLevel)
* */
static uint32 GetSpellForLevel(uint32 spell_id, Player *player)
{
uint32 level = player->GetLevel();
// if the character is level max level or higher, return the last spell in the chain
if (level >= MaxLevel)
return sSpellMgr->GetLastSpellInChain(spell_id);
uint32 first_spell = sSpellMgr->GetFirstSpellInChain(spell_id);
uint32 next_spell = first_spell;
uint32 number_of_spells_in_chain = 0;
for (; next_spell; next_spell = sSpellMgr->GetNextSpellInChain(next_spell))
number_of_spells_in_chain++;
// if the chain is empty, return the first spell
if (number_of_spells_in_chain == 0)
{
LOG_WARN("module.buffernpc", "Unable to find a spell chain for spell with id {}", spell_id);
return first_spell;
}
// if the chain has only one spell, return that spell
if (number_of_spells_in_chain == 1)
return first_spell;
// if the chain has more than one spell, calculate the level-appropriate spell
uint32 spell_index = (level * number_of_spells_in_chain) / MaxLevel;
uint32 spell = first_spell;
LOG_DEBUG("module.buffernpc", "{}, level {}, gets spell {} of {} from spell {}", player->GetName(), level, (spell_index+1), number_of_spells_in_chain, spell_id);
for (uint32 i = 0; i < spell_index; i++)
{
// traverse to the level-appropriate spell
spell = sSpellMgr->GetNextSpellInChain(spell);
}
return spell;
}
static bool replace(std::string &str, const std::string &from, const std::string &to)
{
size_t start_pos = str.find(from);
if (start_pos == std::string::npos)
return false;
str.replace(start_pos, from.length(), to);
return true;
}
static std::string PickWhisper(std::string Name)
{
// Choose and speak a random phrase to the player
// Phrases are stored in the config file
std::string whisper = "";
uint32 WhisperNum = urand(1, BuffNumWhispers); // How many phrases does the NPC speak?
whisper = "BF.W" + std::to_string(WhisperNum);
// Sanitize
if (whisper == "")
whisper = "ERROR! NPC Emote Text Not Found! Check the npc_buffer.conf!";
std::string randMsg = sConfigMgr->GetOption<std::string>(whisper.c_str(), "");
replace(randMsg, "%s", Name);
return randMsg.c_str();
}
static std::string PickPhrase()
{
// Choose and speak a random phrase to the player
// Phrases are stored in the config file
std::string phrase = "";
uint32 PhraseNum = urand(1, BuffNumPhrases); // How many phrases does the NPC speak?
phrase = "BF.P" + std::to_string(PhraseNum);
// Sanitize
if (phrase == "")
phrase = "ERROR! NPC Emote Text Not Found! Check the npc_buffer.conf!";
std::string randMsg = sConfigMgr->GetOption<std::string>(phrase.c_str(), "");
return randMsg.c_str();
}
// bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 /* uiAction */) override
bool OnGossipHello(Player* player, Creature* creature)
{
if (!BFEnableModule)
return false;
// Who are we dealing with?
std::string CreatureWhisper = "Init";
std::string PlayerName = player->GetName();
// Store Buff IDs
std::vector<uint32> vecBuffs = {};
std::stringstream ss(sConfigMgr->GetOption<std::string>("Buff.Spells", ""));
for (std::string buff; std::getline(ss, buff, ';');)
vecBuffs.push_back(stoul(buff));
// Cure Resurrection Sickness
if (BuffCureRes && player->HasAura(15007))
{
player->RemoveAura(15007);
std::ostringstream res;
res << "The aura of death has been lifted from you " << PlayerName << ". Watch yourself out there!";
creature->Whisper(res.str().c_str(), LANG_UNIVERSAL, player);
}
// Are we buffing based on level
if (BuffByLevel == true)
{
for (std::vector<uint32>::const_iterator itr = vecBuffs.begin(); itr != vecBuffs.end(); itr++)
{
uint32 spell_id = *itr; // get the spell id from the list of spells
uint32 spell = GetSpellForLevel(spell_id, player); // get the level-appropriate spell
player->CastSpell(player, spell, true); // cast the buff
}
}
else
{
// No level requirement, so buff with max level default buffs
for (std::vector<uint32>::const_iterator itr = vecBuffs.begin(); itr != vecBuffs.end(); itr++)
player->CastSpell(player, *itr, true);
}
// Choose and speak a random phrase to the player
// Phrases are stored in the config file
if (BuffNumWhispers > 0)
creature->Whisper(PickWhisper(PlayerName).c_str(), LANG_UNIVERSAL, player);
// Emote and Close
creature->HandleEmoteCommand(EMOTE_ONESHOT_FLEX);
CloseGossipMenuFor(player);
return true;
}
// Passive Emotes
struct NPC_PassiveAI : public ScriptedAI
{
NPC_PassiveAI(Creature *creature) : ScriptedAI(creature) {}
uint32 MessageTimer = 0;
// Called once when client is loaded
void Reset()
{
if (BuffMessageTimer != 0)
MessageTimer = urand(BuffMessageTimer, 300000); // 1-5 minutes
}
// Called at World update tick
void UpdateAI(const uint32 diff)
{
if (BFEnableModule && BuffMessageTimer != 0)
{
if (MessageTimer <= diff)
{
if (BuffNumPhrases > 0)
{
std::string Message = PickPhrase();
me->Say(Message.c_str(), LANG_UNIVERSAL, NULL);
}
// Use gesture?
if (BuffEmoteCommand != 0)
me->HandleEmoteCommand(BuffEmoteCommand);
// Alert players?
if (BuffEmoteSpell != 0)
me->CastSpell(me, BuffEmoteSpell);
MessageTimer = urand(BuffMessageTimer, 300000);
}
else { MessageTimer -= diff; }
}
else
MessageTimer -= diff;
}
};
// CREATURE AI
CreatureAI *GetAI(Creature *creature) const
{
return new NPC_PassiveAI(creature);
}
};
void AddNPCBufferScripts()
{
new BufferConfig();
new BufferAnnounce();
new buff_npc();
}