8 Commits

Author SHA1 Message Date
gasaichandesu 2bf075d616 Merge branch 'master' of ssh://git.moon-well.online:2222/sindoring/moonwell-core into feature/premium 2026-08-19 17:17:42 +04:00
gasaichandesu b920ec50ab fix(premium): fix premium migration being generated with older schema
version
2026-08-19 17:17:01 +04:00
gasaichan e965678adf Merge pull request 'Premium system foundation' (#3) from feature/premium into master
Reviewed-on: #3
2026-08-19 16:04:10 +03:00
gasaichandesu 5918cf7b1a feat(premium): add SQL data for premium feature 2026-08-19 16:50:58 +04:00
gasaichan e04f0f068c feat(premium): implement summon squire spell interceptor
Squire summon spell is intercepted to summon custom NPC with "service" dialogue options such as open mail, open bank, etc.
2026-08-19 12:43:32 +02:00
gasaichandesu 85287568b5 Merge branch 'master' of ssh://git.moon-well.online:2222/sindoring/moonwell-core into feature/premium 2026-08-17 11:30:49 +04:00
gasaichan 9d7bfe2516 feat(premium): fix premium script startup errors 2026-08-10 16:14:18 +02:00
gasaichandesu b5f3f51208 feat(premium): implement premium system through ACCOUNT_FLAG_RECURRING_BILLING flag 2026-08-10 17:40:02 +04:00
5 changed files with 564 additions and 2 deletions
+9
View File
@@ -341,6 +341,14 @@ import_encounter_journal_sql() {
fi
}
import_premium_sql() {
log "Started importing Premium SQL files"
local world_premium_sql="$ROOT_DIR/sql/Premium/world.sql"
import_sql_file "acore_world" "$world_premium_sql"
}
if (($# > 0)); then
case "$1" in
-h|--help)
@@ -373,6 +381,7 @@ import_playerbots_ru_sql
import_encounter_journal_sql
import_store_sql
import_transmog_sql
import_premium_sql
configure_server_motd
log "custom SQL bootstrap completed"
+1
View File
@@ -0,0 +1 @@
return {}
+172
View File
@@ -0,0 +1,172 @@
local PLAYER_EVENT_ON_LOGIN = 3
local PLAYER_EVENT_ON_SPELL_CAST = 5
local PLAYER_EVENT_ON_LOGOUT = 4
local PLAYER_EVENT_ON_COMMAND = 42
local PREMIUM_FLAG_INDEX = 100
local ACCOUNT_FLAG_RECURRING_BILLING = 8192
local SUMMON_SQUIRE_SPELL_ID = 80000
local SQUIRE_CREATURE_TEMPLATE_ID = 9000001
local NPC_TEXT_ID = 10000000
---todo extract to utils
---@param inputstr string
---@param separator string
---@return table
local function SplitString(inputstr, separator)
if separator == nil then
separator = "%s"
end
local t = {}
for str in string.gmatch(inputstr, "([^" .. separator .. "]+)") do
table.insert(t, str)
end
return t
end
---@return boolean
local function IsPremium(player)
return player:HasFlag(PREMIUM_FLAG_INDEX, 1)
end
local function OnPremiumPlayer(player)
if not IsPremium(player) then
return
end
player:SendAreaTriggerMessage(
'На вашем аккаунте активна подписка Premium! Благодарим за поддержку проекта MoonWell.')
player:LearnSpell(SUMMON_SQUIRE_SPELL_ID)
player:SendBroadcastMessage("Милостью Элуны вам была выдана способность |cff71d5ff|Hspell:" ..
SUMMON_SQUIRE_SPELL_ID .. "|h[" .. "Призыв Оруженосца]h|")
end
local function RefreshPremiumStatus(player)
local query = AuthDBQuery("SELECT flags FROM account WHERE id = " .. player:GetAccountId())
if query then
local function HasFlag(mask, flag)
return bit_and(mask, flag) == flag
end
local flags = query:GetUInt32(0)
if HasFlag(flags, ACCOUNT_FLAG_RECURRING_BILLING) then
player:SetFlag(PREMIUM_FLAG_INDEX, 1)
OnPremiumPlayer(player)
return true
end
end
return false
end
local function ApplyPremium(player)
AuthDBExecute(
string.format(
"UPDATE account SET flags = flags | %d WHERE id = %d",
ACCOUNT_FLAG_RECURRING_BILLING,
player:GetAccountId()
)
)
RefreshPremiumStatus(player)
end
local function OnLogin(event, player)
RefreshPremiumStatus(player)
end
--- @param event any
--- @param player any
--- @param command string
--- @param chatHandler any
local function OnCommand(event, player, command, chatHandler)
---Console is not supported yet
if not player then return end
local parts = SplitString(command:lower(), ' ')
if parts[1] ~= 'premium' then return end
if parts[2] == 'add' then
ApplyPremium(player:GetSelection())
end
return false
end
local function OnSummonSquireCast(player)
local x, y, z, o = player:GetLocation()
local squire = player:SpawnCreature(SQUIRE_CREATURE_TEMPLATE_ID, x + 1, y + 1, z, o, 1, 30000)
if squire then
squire:SetFaction(player:GetFaction())
end
end
local function OnSpellCast(event, player, spell, skipCheck)
local spellId = spell:GetEntry()
if spellId == SUMMON_SQUIRE_SPELL_ID then
OnSummonSquireCast(player)
end
end
local function OnGossipHello(event, player, creature)
player:GossipClearMenu()
player:GossipMenuAddItem(4, "Открыть почтовый ящик", 900001, 1)
player:GossipMenuAddItem(1, "Открыть банк", 900001, 2)
player:GossipMenuAddItem(6, "Открыть аукцион", 900001, 3)
player:GossipMenuAddItem(4, "Отремонтировать снаряжение", 900001, 4)
player:GossipSendMenu(NPC_TEXT_ID, creature)
end
local function OnGossipSelect(event, player, creature, sender, intid, code)
if sender == 900001 then
if intid == 1 then
player:SendShowMailBox(creature:GetGUID())
player:GossipComplete()
end
if intid == 2 then
player:SendShowBank(creature)
player:GossipComplete()
end
if intid == 3 then
player:SendAuctionMenu(creature)
player:GossipComplete()
end
if intid == 4 then
player:DurabilityRepairAll()
player:PlayDirectSound(1116)
player:GossipComplete()
end
end
end
local function OnLogout(event, player)
player:RemoveSpell(SUMMON_SQUIRE_SPELL_ID)
end
RegisterCreatureGossipEvent(SQUIRE_CREATURE_TEMPLATE_ID, 1, OnGossipHello)
RegisterCreatureGossipEvent(SQUIRE_CREATURE_TEMPLATE_ID, 2, OnGossipSelect)
RegisterPlayerEvent(PLAYER_EVENT_ON_LOGIN, OnLogin)
RegisterPlayerEvent(PLAYER_EVENT_ON_LOGOUT, OnLogout)
RegisterPlayerEvent(PLAYER_EVENT_ON_COMMAND, OnCommand)
RegisterPlayerEvent(PLAYER_EVENT_ON_SPELL_CAST, OnSpellCast)
+2 -2
View File
@@ -61,9 +61,9 @@
# false - (disabled)
Eluna.Enabled = true
Eluna.TraceBack = false
Eluna.TraceBack = true
Eluna.ScriptPath = "lua_scripts"
Eluna.PlayerAnnounceReload = false
Eluna.PlayerAnnounceReload = true
Eluna.RequirePaths = ""
Eluna.RequireCPaths = ""
Eluna.AutoReload = false
+380
View File
@@ -0,0 +1,380 @@
-- Create Squire NPC
INSERT
INTO
acore_world.creature_template (entry,
difficulty_entry_1,
difficulty_entry_2,
difficulty_entry_3,
KillCredit1,
KillCredit2,
name,
subname,
IconName,
gossip_menu_id,
minlevel,
maxlevel,
`exp`,
faction,
npcflag,
speed_walk,
speed_run,
speed_swim,
speed_flight,
detection_range,
`rank`,
dmgschool,
DamageModifier,
BaseAttackTime,
RangeAttackTime,
BaseVariance,
RangeVariance,
unit_class,
unit_flags,
unit_flags2,
dynamicflags,
family,
`type`,
type_flags,
lootid,
pickpocketloot,
skinloot,
PetSpellDataId,
VehicleId,
mingold,
maxgold,
AIName,
MovementType,
HoverHeight,
HealthModifier,
ManaModifier,
ArmorModifier,
ExperienceModifier,
RacialLeader,
movementId,
RegenHealth,
mechanic_immune_mask,
spell_school_immune_mask,
flags_extra,
ScriptName,
VerifiedBuild)
VALUES
(9000001,
29831,
0,
0,
0,
0,
'Eluna Squire',
'',
'',
0,
81,
81,
2,
21,
1,
1.0,
1.42857,
1.0,
1.0,
20.0,
1,
0,
7.5,
2000,
2000,
1.0,
1.0,
1,
64,
2048,
8,
0,
6,
72,
100003,
0,
0,
0,
0,
1163,
1524,
'SmartAI',
0,
1.0,
4.0,
1.0,
1.0,
2.5,
0,
144,
1,
1007366674,
0,
0,
'',
12340) ON DUPLICATE KEY UPDATE entry = entry;
-- Add Squire localization
INSERT INTO
acore_world.creature_template_locale (entry,
locale,
Name,
Title,
VerifiedBuild)
VALUES
(9000001,
'ruRU',
'Оруженосец',
'',
12340) ON DUPLICATE KEY UPDATE entry = entry;
-- Add Squire model
INSERT
INTO
acore_world.creature_template_model (CreatureID,
Idx,
CreatureDisplayID,
DisplayScale,
Probability,
VerifiedBuild)
VALUES
(9000001,
0,
16927,
1.0,
1.0,
12340) ON
DUPLICATE KEY
UPDATE
CreatureID = CreatureID;
-- Add Squire dialogue text
INSERT
INTO
acore_world.npc_text (ID,
text0_0,
text0_1,
BroadcastTextID0,
lang0,
Probability0,
em0_0,
em0_1,
em0_2,
em0_3,
em0_4,
em0_5,
text1_0,
text1_1,
BroadcastTextID1,
lang1,
Probability1,
em1_0,
em1_1,
em1_2,
em1_3,
em1_4,
em1_5,
text2_0,
text2_1,
BroadcastTextID2,
lang2,
Probability2,
em2_0,
em2_1,
em2_2,
em2_3,
em2_4,
em2_5,
text3_0,
text3_1,
BroadcastTextID3,
lang3,
Probability3,
em3_0,
em3_1,
em3_2,
em3_3,
em3_4,
em3_5,
text4_0,
text4_1,
BroadcastTextID4,
lang4,
Probability4,
em4_0,
em4_1,
em4_2,
em4_3,
em4_4,
em4_5,
text5_0,
text5_1,
BroadcastTextID5,
lang5,
Probability5,
em5_0,
em5_1,
em5_2,
em5_3,
em5_4,
em5_5,
text6_0,
text6_1,
BroadcastTextID6,
lang6,
Probability6,
em6_0,
em6_1,
em6_2,
em6_3,
em6_4,
em6_5,
text7_0,
text7_1,
BroadcastTextID7,
lang7,
Probability7,
em7_0,
em7_1,
em7_2,
em7_3,
em7_4,
em7_5,
VerifiedBuild)
VALUES
(10000000,
'',
'By the grace of the stars, I have been bound to your side, $n. This ancient pile of bones is ready to serve you.',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
'',
'',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
'',
'',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
'',
'',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
'',
'',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
'',
'',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
'',
'',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
'',
'',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
0) ON DUPLICATE KEY UPDATE ID = ID;
-- Add squire dialogue text locale
INSERT
INTO
acore_world.npc_text_locale (ID,
Locale,
Text0_0,
Text0_1,
Text1_0,
Text1_1,
Text2_0,
Text2_1,
Text3_0,
Text3_1,
Text4_0,
Text4_1,
Text5_0,
Text5_1,
Text6_0,
Text6_1,
Text7_0,
Text7_1)
VALUES
(10000000,
'ruRU',
'',
'Милостью высших сил я был приставлен к тебе, $n. Эти древние кости готовы служить. Чего желаешь?',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'') ON DUPLICATE KEY UPDATE ID = ID;