Skip to content

Commit 1ba2296

Browse files
authored
Implement .weekendxp config command and allow rates to be floats (#30)
* Implement `.weekendxp config` command and allow rates to be `float`s Also changed the existing strings to use `{}` rather than the c-like formatters, since they seemed to not work in `master` * Implement mod version migration system and general fixes * Fix error string since now the range [0,1] is allowed for xp rates * Add a changelog to the cpp file * Add migration system so that players that previously changed their personal rate dont need to change it after the mod is updated * Identify and note some potential improvements * Remove changelog from source and unnecessary comments
1 parent d28bcec commit 1ba2296

File tree

2 files changed

+223
-55
lines changed

2 files changed

+223
-55
lines changed
+8-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
SET @STRING_ENTRY := 11120;
2-
DELETE FROM `acore_string` WHERE `entry` IN (@STRING_ENTRY+0,@STRING_ENTRY+1);
2+
DELETE FROM `acore_string` WHERE `entry` IN (@STRING_ENTRY+0,@STRING_ENTRY+1,@STRING_ENTRY+2);
33
INSERT INTO `acore_string` (`entry`, `content_default`) VALUES
4-
(@STRING_ENTRY+0, 'Your experience rates were set to %i.'),
5-
(@STRING_ENTRY+1, 'Wrong value specified. Please specify a value between 1 and %i');
4+
(@STRING_ENTRY+0, 'Your experience rates were set to {}.'),
5+
(@STRING_ENTRY+1, 'Wrong value specified. Please specify a value between 0 and {}'),
6+
(@STRING_ENTRY+2, 'The rate being applied to you is {}.\nThe current weekendxp configuration is:\nAnnounce {}\nAlwaysEnabled {}\nQuestOnly {}\nMaxLevel {}\nxpAmount {}\nIndividualXPEnabled {}\nEnabled {}\nMaxAllowedRate {}');
67

78
DELETE FROM `command` WHERE `name` IN ('weekendxp rate');
89
INSERT INTO `command` (`name`, `security`, `help`) VALUES
910
('weekendxp rate', 0, 'Syntax: weekendxp rate $value \nSet your experience rate up to the allowed value.');
11+
12+
DELETE FROM `command` WHERE `name` IN ('weekendxp config');
13+
INSERT INTO `command` (`name`, `security`, `help`) VALUES
14+
('weekendxp config', 0, 'Syntax: weekendxp config\nDisplays the current configuration for the weekendxp mod.');

src/mod-double-xp-weekend.cpp

+215-52
Original file line numberDiff line numberDiff line change
@@ -10,122 +10,236 @@ enum WeekendXP
1010
{
1111
SETTING_WEEKEND_XP_RATE = 0,
1212
SETTING_WEEKEND_XP_DISABLE = 1,
13+
SETTING_WEEKEND_XP_VERSION = 2,
1314

1415
LANG_CMD_WEEKEND_XP_SET = 11120,
1516
LANG_CMD_WEEKEND_XP_ERROR = 11121,
17+
LANG_CMD_WEEKEND_XP_CONFIG = 11122,
1618

1719
WD_FRIDAY = 5,
1820
WD_SATURDAY = 6,
1921
WD_SUNDAY = 0,
2022
};
2123

22-
class weekendxp_commandscript : public CommandScript
24+
class DoubleXpWeekend
2325
{
26+
2427
public:
25-
weekendxp_commandscript() : CommandScript("weekendxp_commandscript") { }
28+
29+
DoubleXpWeekend() { }
30+
31+
// NOTE We need to access the DoubleXpWeekend logic from other
32+
// places, so keep all the logic accessible via a singleton here,
33+
// and have the `CommandScript` and the `PlayeScript` access this
34+
// for the functionality they need.
35+
static DoubleXpWeekend* instance()
36+
{
37+
static DoubleXpWeekend instance;
38+
return &instance;
39+
}
2640

27-
ChatCommandTable GetCommands() const override
41+
uint32 OnGiveXP(Player* player, uint32 originalAmount, uint8 xpSource) const
2842
{
29-
static ChatCommandTable commandTable =
43+
if (!IsEventActive())
3044
{
31-
{ "weekendxp rate", HandleSetXPBonusCommand, SEC_PLAYER, Console::No },
32-
};
45+
return originalAmount;
46+
}
3347

34-
return commandTable;
48+
if (ConfigQuestOnly() && xpSource != PlayerXPSource::XPSOURCE_QUEST && xpSource != PlayerXPSource::XPSOURCE_QUEST_DF)
49+
{
50+
return originalAmount;
51+
}
52+
53+
if (player->GetLevel() >= ConfigMaxLevel())
54+
{
55+
return originalAmount;
56+
}
57+
58+
float newAmount = (float)originalAmount * GetExperienceRate(player);
59+
return (uint32) newAmount;
3560
}
3661

37-
static bool HandleSetXPBonusCommand(ChatHandler* handler, int8 rate)
62+
void OnLogin(Player* player, ChatHandler* handler) const
63+
{
64+
// TODO I am assuming that this is always called when a character logs in...
65+
// if that is not the case, thing migh get weird... Adding some asserts or warnings would be nice
66+
// but I'm not sure how to handle "This shouldn't be happening but it is" kind of scenarios in acore
67+
MigratePlayerSettings(player, handler);
68+
69+
if (ConfigAnnounce())
70+
{
71+
if (IsEventActive() && !ConfigAlwaysEnabled())
72+
{
73+
float rate = GetExperienceRate(player);
74+
handler->PSendSysMessage("It's the weekend! Your XP rate has been set to: {}", rate);
75+
}
76+
else if (IsEventActive() && ConfigAlwaysEnabled())
77+
{
78+
float rate = GetExperienceRate(player);
79+
handler->PSendSysMessage("Your XP rate has been set to: {}", rate);
80+
}
81+
else
82+
{
83+
handler->PSendSysMessage("This server is running the |cff4CFF00Double XP Weekend |rmodule.");
84+
}
85+
}
86+
}
87+
88+
bool HandleSetXPBonusCommand(ChatHandler* handler, float rate) const
3889
{
3990
Player* player = handler->GetPlayer();
4091

41-
int8 maxRate = sConfigMgr->GetOption<int8>("XPWeekend.MaxAllowedRate", 2);
92+
float maxRate = ConfigMaxAllowedRate();
4293

43-
if (rate <= 0 || rate > maxRate)
94+
if (rate <= 0.0f || rate > maxRate)
4495
{
4596
handler->PSendSysMessage(LANG_CMD_WEEKEND_XP_ERROR, maxRate);
4697
handler->SetSentErrorMessage(true);
4798
return true;
4899
}
49100

50-
player->UpdatePlayerSetting("mod-double-xp-weekend", SETTING_WEEKEND_XP_RATE, rate);
101+
PlayerSettingSetRate(player, rate);
51102
handler->PSendSysMessage(LANG_CMD_WEEKEND_XP_SET, rate);
52103

104+
// TODO if the `EnablePlayerSettings` is not set, the setting wont be remembered by the
105+
// server after the player logs out, meaning the player needs to do this again on next login
106+
53107
return true;
54108
}
55-
};
56109

57-
class DoubleXpWeekend : public PlayerScript
58-
{
59-
public:
60-
DoubleXpWeekend() : PlayerScript("DoubleXpWeekend") { }
110+
bool HandleGetCurrentConfigCommand(ChatHandler* handler) const
111+
{
112+
Player* player = handler->GetPlayer();
61113

62-
void OnLogin(Player* player) override
114+
const float actualRate = GetExperienceRate(player);
115+
const bool isAnnounceEnabled = ConfigAnnounce();
116+
const bool isAlwaysEnabled = ConfigAlwaysEnabled();
117+
const bool isQuestOnly = ConfigQuestOnly();
118+
const uint32 maxLevel = ConfigMaxLevel();
119+
const float xpRate = ConfigxpAmount();
120+
const bool isIndividulaXpEnabled = ConfigIndividualXPEnabled();
121+
const bool isEnabled = ConfigEnabled();
122+
const float maxXpRate = ConfigMaxAllowedRate();
123+
124+
handler->PSendSysMessage(LANG_CMD_WEEKEND_XP_CONFIG,
125+
actualRate,
126+
isAnnounceEnabled,
127+
isAlwaysEnabled,
128+
isQuestOnly,
129+
maxLevel,
130+
xpRate,
131+
isIndividulaXpEnabled,
132+
isEnabled,
133+
maxXpRate
134+
);
135+
136+
return true;
137+
}
138+
139+
private:
140+
141+
// NOTE keep options together to prevent having more than 1 potential default value
142+
bool ConfigAlwaysEnabled() const { return sConfigMgr->GetOption<bool>("XPWeekend.AlwaysEnabled", false); }
143+
bool ConfigAnnounce() const { return sConfigMgr->GetOption<bool>("XPWeekend.Announce", false); }
144+
bool ConfigQuestOnly() const { return sConfigMgr->GetOption<bool>("XPWeekend.QuestOnly", false); }
145+
uint32 ConfigMaxLevel() const { return sConfigMgr->GetOption<uint32>("XPWeekend.MaxLevel", 80); }
146+
float ConfigxpAmount() const { return sConfigMgr->GetOption<float>("XPWeekend.xpAmount", 2.0f); }
147+
bool ConfigIndividualXPEnabled() const { return sConfigMgr->GetOption<bool>("XPWeekend.IndividualXPEnabled", false); }
148+
bool ConfigEnabled() const { return sConfigMgr->GetOption<bool>("XPWeekend.Enabled", false); }
149+
float ConfigMaxAllowedRate() const { return sConfigMgr->GetOption<float>("XPWeekend.MaxAllowedRate", 2.0f); }
150+
151+
void PlayerSettingSetRate(Player* player, float rate) const
63152
{
64-
if (sConfigMgr->GetOption<bool>("XPWeekend.Announce", false))
65-
{
66-
if (IsEventActive() && !sConfigMgr->GetOption<bool>("XPWeekend.AlwaysEnabled", false))
67-
{
68-
ChatHandler(player->GetSession()).PSendSysMessage("It's the weekend! Your XP rate has been set to: {}", GetExperienceRate(player));
69-
}
70-
else if (IsEventActive() && sConfigMgr->GetOption<bool>("XPWeekend.AlwaysEnabled", false))
71-
{
72-
ChatHandler(player->GetSession()).PSendSysMessage("Your XP rate has been set to: {}", GetExperienceRate(player));
73-
}
74-
else
75-
{
76-
ChatHandler(player->GetSession()).PSendSysMessage("This server is running the |cff4CFF00Double XP Weekend |rmodule.");
77-
}
78-
}
153+
// HACK PlayerSetting seems to store uint32 only, so save our `float` as if it was a `uint32`
154+
uint32 encodedRate;
155+
float* reinterpretingPointer = (float*)&encodedRate;
156+
*reinterpretingPointer = rate;
157+
player->UpdatePlayerSetting("mod-double-xp-weekend", SETTING_WEEKEND_XP_RATE, encodedRate);
158+
}
159+
160+
float PlayerSettingGetRate(Player* player) const
161+
{
162+
uint32 rateStored = player->GetPlayerSetting("mod-double-xp-weekend", SETTING_WEEKEND_XP_RATE).value;
163+
// HACK PlayerSetting seems to store uint32 only, so save our `float` as if it was a `uint32`
164+
float rate = *(float*)&rateStored;
165+
return rate;
79166
}
80167

81-
void OnGiveXP(Player* player, uint32& amount, Unit* /*victim*/, uint8 xpSource) override
168+
void MigratePlayerSettings(Player* player, ChatHandler* /*handler*/) const
82169
{
83-
if (!IsEventActive())
170+
static const uint32 VERSION = 1;
171+
172+
uint32 playersCurrentVersion = player->GetPlayerSetting("mod-double-xp-weekend", SETTING_WEEKEND_XP_VERSION).value;
173+
bool validMigration = playersCurrentVersion == 0 && VERSION == 1;
174+
if (!validMigration)
84175
{
176+
// Currently there is only either version 0 (the default) or 1
177+
// This check should never fail unless a new version is introduced and the
178+
// migration here is not updated.
85179
return;
86180
}
87181

88-
if (sConfigMgr->GetOption<bool>("XPWeekend.QuestOnly", false) && xpSource != PlayerXPSource::XPSOURCE_QUEST && xpSource != PlayerXPSource::XPSOURCE_QUEST_DF)
182+
// On version 1 the only thing to migrate is the SETTING_WEEKEND_XP_RATE
183+
float newRate = ConfigxpAmount();
184+
uint32 originalRate = player->GetPlayerSetting("mod-double-xp-weekend", SETTING_WEEKEND_XP_RATE).value;
185+
if (originalRate <= 0)
89186
{
90-
return;
187+
// player setting was never set before, just use default
91188
}
92-
93-
if (player->GetLevel() >= sConfigMgr->GetOption<uint32>("XPWeekend.MaxLevel", 80))
189+
else if ((float)originalRate > ConfigMaxAllowedRate())
94190
{
95-
return;
191+
// player setting was set but the value is not valid, just use default
192+
}
193+
else
194+
{
195+
// player setting was set, use the same rate
196+
newRate = (float) originalRate;
96197
}
97198

98-
amount *= GetExperienceRate(player);
199+
// HACK PlayerSetting seems to store uint32 only, so save our `float` as if it was a `uint32`
200+
uint32 encodedRate;
201+
float* reinterpretingPointer = (float*)&encodedRate;
202+
*reinterpretingPointer = newRate;
203+
player->UpdatePlayerSetting("mod-double-xp-weekend", SETTING_WEEKEND_XP_RATE, encodedRate);
204+
player->UpdatePlayerSetting("mod-double-xp-weekend", SETTING_WEEKEND_XP_VERSION, VERSION);
99205
}
100-
101-
int8 GetExperienceRate(Player * player) const
206+
207+
// TODO why is there a `GetDisable` player setting but no way to actually modify it? Leaving as is for now...
208+
bool PlayerSettingGetDisable(Player* player) const
102209
{
103-
int8 rate = sConfigMgr->GetOption<int8>("XPWeekend.xpAmount", 2);
210+
return player->GetPlayerSetting("mod-double-xp-weekend", SETTING_WEEKEND_XP_DISABLE).value == (uint32)1;
211+
}
104212

105-
int8 individualRate = player->GetPlayerSetting("mod-double-xp-weekend", SETTING_WEEKEND_XP_RATE).value;
213+
float GetExperienceRate(Player* player) const
214+
{
215+
float rate = ConfigxpAmount();
106216

107-
if (player->GetPlayerSetting("mod-double-xp-weekend", SETTING_WEEKEND_XP_DISABLE).value)
217+
if (PlayerSettingGetDisable(player))
108218
{
109-
return 1;
219+
return 1.0f;
110220
}
111221

112222
// If individualxp setting is enabled... and a rate was set, overwrite it.
113-
if (sConfigMgr->GetOption<bool>("XPWeekend.IndividualXPEnabled", false) && individualRate)
223+
if (ConfigIndividualXPEnabled())
114224
{
115-
rate = individualRate;
225+
rate = PlayerSettingGetRate(player);
116226
}
117227

118228
// Prevent returning 0% rate.
119-
return rate ? rate : 1;
229+
return rate > 0.0f ? rate : 1.0f;
120230
}
121231

122232
bool IsEventActive() const
123233
{
124-
if (sConfigMgr->GetOption<bool>("XPWeekend.AlwaysEnabled", false))
234+
if (ConfigAlwaysEnabled())
235+
{
125236
return true;
237+
}
126238

127-
if (!sConfigMgr->GetOption<bool>("XPWeekend.Enabled", false))
239+
if (!ConfigEnabled())
240+
{
128241
return false;
242+
}
129243

130244
time_t t = time(nullptr);
131245
tm* now = localtime(&t);
@@ -134,8 +248,57 @@ class DoubleXpWeekend : public PlayerScript
134248
}
135249
};
136250

251+
class weekendxp_commandscript : public CommandScript
252+
{
253+
public:
254+
weekendxp_commandscript() : CommandScript("weekendxp_commandscript") { }
255+
256+
ChatCommandTable GetCommands() const override
257+
{
258+
static ChatCommandTable commandTable =
259+
{
260+
{ "weekendxp rate", HandleSetXPBonusCommand, SEC_PLAYER, Console::No },
261+
{ "weekendxp config", HandleGetCurrentConfigCommand, SEC_PLAYER, Console::No },
262+
};
263+
264+
return commandTable;
265+
}
266+
267+
static bool HandleSetXPBonusCommand(ChatHandler* handler, float rate)
268+
{
269+
DoubleXpWeekend* mod = DoubleXpWeekend::instance();
270+
return mod->HandleSetXPBonusCommand(handler, rate);
271+
}
272+
273+
static bool HandleGetCurrentConfigCommand(ChatHandler* handler)
274+
{
275+
DoubleXpWeekend* mod = DoubleXpWeekend::instance();
276+
return mod->HandleGetCurrentConfigCommand(handler);
277+
}
278+
};
279+
280+
class DoubleXpWeekendPlayerScript : public PlayerScript
281+
{
282+
public:
283+
DoubleXpWeekendPlayerScript() : PlayerScript("DoubleXpWeekend") { }
284+
285+
void OnLogin(Player* player) override
286+
{
287+
DoubleXpWeekend* mod = DoubleXpWeekend::instance();
288+
ChatHandler handler = ChatHandler(player->GetSession());
289+
mod->OnLogin(player, &handler);
290+
}
291+
292+
void OnGiveXP(Player* player, uint32& amount, Unit* /*victim*/, uint8 xpSource) override
293+
{
294+
DoubleXpWeekend* mod = DoubleXpWeekend::instance();
295+
amount = mod->OnGiveXP(player, amount, xpSource);
296+
}
297+
298+
};
299+
137300
void AdddoublexpScripts()
138301
{
139-
new DoubleXpWeekend();
302+
new DoubleXpWeekendPlayerScript();
140303
new weekendxp_commandscript();
141304
}

0 commit comments

Comments
 (0)