-- s51 farm gameplay logic (SQL-backed state) -- Keeps existing creature IDs, item IDs, and message IDs. local role_store = dofile("server_data/script/Map/s51/farm/role_store.lua") local plot_store = dofile("server_data/script/Map/s51/farm/plot_store.lua") local map_def = dofile("server_data/script/Map/s51/farm/mappings.lua") local M = {} local GROW_SECONDS = 3600 local COOLDOWN_SECONDS = 60 * 15 local SECOND_WITHER_SECONDS = 3600 local function _now() return os.time() end local function _msg_simple(RoleID, textMsgId) local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 13, 1) msg.AddMsgEvent(MsgID, 1, textMsgId) msg.DispatchRoleMsgEvent(RoleID, MsgID) end local function _ensure_farm_role(RoleID) role_store.ensureRole(RoleID) local r = role_store.getRole(RoleID) or { farmLevelRaw = 0, farmExp = 0, farmEnter = 0 } local zero = r.farmLevelRaw local farmlevel = zero % 10 if farmlevel == 0 then zero = zero + 1 farmlevel = 1 role_store.setRole(RoleID, { farmLevelRaw = zero }) r.farmLevelRaw = zero end return r end local function _award_farm_exp(RoleID, addExp, dispatchToRoleId) local r = _ensure_farm_role(RoleID) local zero = r.farmLevelRaw local farmlevel = zero % 10 local farmexp = r.farmExp if farmlevel >= 9 then _msg_simple(dispatchToRoleId or RoleID, 420033) return end local inc = map_def.seed_exp[addExp] or 0 -- addExp is TargetTypeID in legacy, but callers pass that; keep naming to avoid mistakes. farmexp = farmexp + inc if farmexp >= (map_def.farm_exp[farmlevel] or 0) then farmexp = farmexp - (map_def.farm_exp[farmlevel] or 0) zero = zero + 1 farmlevel = farmlevel + 1 role_store.setRole(RoleID, { farmLevelRaw = zero, farmExp = farmexp }) local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 13, 1) msg.AddMsgEvent(MsgID, 1, 420031) msg.AddMsgEvent(MsgID, 9, farmlevel) msg.DispatchRoleMsgEvent(dispatchToRoleId or RoleID, MsgID) else role_store.setRole(RoleID, { farmExp = farmexp }) local ex = (map_def.farm_exp[farmlevel] or 0) - farmexp local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 13, 1) msg.AddMsgEvent(MsgID, 1, 420032) msg.AddMsgEvent(MsgID, 9, farmexp) msg.AddMsgEvent(MsgID, 9, ex) msg.DispatchRoleMsgEvent(dispatchToRoleId or RoleID, MsgID) end end local function _get_pos(MapID, InstanceID, TargetID) local x, y, z = unit.GetPosition(MapID, InstanceID, TargetID) return x, y, z end local function _get_plot_by_target(MapID, InstanceID, TargetID) local x, y, z = _get_pos(MapID, InstanceID, TargetID) local plot = plot_store.getPlot(MapID, InstanceID, x, y, z) return plot, x, y, z end local function _expected_type_for_plot(plot, currentTypeId) if plot == nil then return currentTypeId end if plot.Stage == map_def.STAGE_MOUND then -- allow both mound objects return currentTypeId end local def = map_def.plants[plot.PlantId] if def == nil then return currentTypeId end return def.creature[plot.Stage] or currentTypeId end local function _replace_creature_if_needed(MapID, InstanceID, TargetID, TargetTypeID, x, y, z, expectedTypeId) if expectedTypeId == nil or expectedTypeId == 0 or expectedTypeId == TargetTypeID then return TargetID, TargetTypeID end map.MapDeleteCreature(MapID, InstanceID, TargetID) local newId = map.MapCreateCreature(MapID, InstanceID, expectedTypeId, x, y, z) return newId, expectedTypeId end -- Sync: update stage by time (DB) and ensure the world object matches. function M.syncPlotFromDB(MapID, InstanceID, TargetID, TargetTypeID) local plot, x, y, z = _get_plot_by_target(MapID, InstanceID, TargetID) if plot == nil then return TargetID, TargetTypeID, nil, x, y, z end local now = _now() -- Stage auto-advance: watered sapling -> first harvest after 1 hour if plot.Stage == map_def.STAGE_SAPLING and plot.StageStartTime > 0 and (now - plot.StageStartTime) >= GROW_SECONDS then plot_store.setPlot(MapID, InstanceID, x, y, z, { Stage = map_def.STAGE_FIRST, StageStartTime = now }) plot.Stage = map_def.STAGE_FIRST plot.StageStartTime = now end -- Stage auto-reset: second harvest withers after 1 hour if plot.Stage == map_def.STAGE_SECOND and plot.StageStartTime > 0 and (now - plot.StageStartTime) >= SECOND_WITHER_SECONDS then plot_store.setPlot(MapID, InstanceID, x, y, z, { PlantId = 0, Stage = map_def.STAGE_MOUND, -- keep cooldown ownership behavior OwnerRoleID = plot.OwnerRoleID, LastPlotTime = now, StageStartTime = 0, }) plot.PlantId = 0 plot.Stage = map_def.STAGE_MOUND plot.LastPlotTime = now plot.StageStartTime = 0 end local expected = _expected_type_for_plot(plot, TargetTypeID) local newId, newType = _replace_creature_if_needed(MapID, InstanceID, TargetID, TargetTypeID, x, y, z, expected) return newId, newType, plot, x, y, z end local function _farm_level_raw(RoleID) local r = _ensure_farm_role(RoleID) return r.farmLevelRaw end local function _cooldown_ok(plot, RoleID, now) local owner = plot.OwnerRoleID or 0 local last = plot.LastPlotTime or 0 local elapsed = (last == 0) and COOLDOWN_SECONDS or os.difftime(now, last) return elapsed >= COOLDOWN_SECONDS or owner ~= RoleID end local function _plant_seed(MapID, InstanceID, TargetID, RoleID, plantId) local x, y, z = _get_pos(MapID, InstanceID, TargetID) local now = _now() local def = map_def.plants[plantId] if def == nil then return false end local zero = _farm_level_raw(RoleID) local farmlevel = zero % 10 if farmlevel < def.minLevel then _msg_simple(RoleID, 420030) return false end local farmnum = plot_store.countActivePlants(RoleID) if farmnum >= farmlevel then local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 13, 1) msg.AddMsgEvent(MsgID, 1, 420011) msg.AddMsgEvent(MsgID, 9, farmlevel) msg.AddMsgEvent(MsgID, 9, farmnum) msg.DispatchRoleMsgEvent(RoleID, MsgID) return false end local seedItem = def.seedItemId local num = role.GetRoleItemNum(RoleID, seedItem) if num < 1 then _msg_simple(RoleID, 420010) return false end role.RemoveFromRole(MapID, InstanceID, RoleID, seedItem, 1, 420) map.MapDeleteCreature(MapID, InstanceID, TargetID) local seedCreatureId = map.MapCreateCreature(MapID, InstanceID, def.creature[map_def.STAGE_SEED], x, y, z) local saved = plot_store.setPlot(MapID, InstanceID, x, y, z, { PlantId = plantId, Stage = map_def.STAGE_SEED, OwnerRoleID = RoleID, StageStartTime = now, }) if not saved then if seedCreatureId ~= nil and seedCreatureId ~= 0 then map.MapDeleteCreature(MapID, InstanceID, seedCreatureId) end map.MapCreateCreature(MapID, InstanceID, map_def.MOUND_BASIC, x, y, z) role.AddRoleItem(MapID, InstanceID, RoleID, seedItem, 1, -1, 8, 102) _msg_simple(RoleID, 420012) return false end return true end function M.onPlayerEnter(MapID, InstanceID, RoleID) role_store.ensureRole(RoleID) local r = role_store.getRole(RoleID) if r == nil then return end if (r.farmEnter or 0) == 0 then role_store.setRole(RoleID, { farmEnter = 1 }) end end function M.q40053_OnAccept(MapID, InstanceID, QuestID, RoleID, AccepterID) local r = _ensure_farm_role(RoleID) local zero = r.farmLevelRaw local questdata = (zero % 1000 - zero % 100) / 100 if questdata ~= 0 and zero >= 100 then role_store.setRole(RoleID, { farmLevelRaw = zero - 100 }) end end function M.q40053_CheckComplete(MapID, InstanceID, QuestID, RoleID, AccepterID) local r = _ensure_farm_role(RoleID) local zero = r.farmLevelRaw local questdata = (zero % 1000 - zero % 100) / 100 return (questdata == 1) and 1 or 0 end function M.q40054_OnAccept(MapID, InstanceID, QuestID, RoleID, AccepterID) local r = _ensure_farm_role(RoleID) local zero = r.farmLevelRaw local questdata = (zero % 10000 - zero % 1000) / 1000 if questdata ~= 0 and zero >= 1000 then role_store.setRole(RoleID, { farmLevelRaw = zero - 1000 }) end end function M.q40054_CheckComplete(MapID, InstanceID, QuestID, RoleID, AccepterID) local r = _ensure_farm_role(RoleID) local zero = r.farmLevelRaw local questdata = (zero % 10000 - zero % 1000) / 1000 return (questdata == 1) and 1 or 0 end function M.mound_OnTalk(MapID, InstanceID, TargetID, TargetTypeID, RoleID, TalkIndex) local plot0 TargetID, TargetTypeID, plot0, x, y, z = M.syncPlotFromDB(MapID, InstanceID, TargetID, TargetTypeID) local now = _now() _ensure_farm_role(RoleID) -- If DB says this plot is not a mound, redirect to the correct handler after we fixed the world object. if plot0 ~= nil and plot0.Stage ~= map_def.STAGE_MOUND and TargetTypeID ~= map_def.MOUND_BASIC and TargetTypeID ~= map_def.MOUND_ADVANCED then if plot0.Stage == map_def.STAGE_SEED then return M.seed_OnTalk(MapID, InstanceID, TargetID, TargetTypeID, RoleID, TalkIndex) elseif plot0.Stage == map_def.STAGE_SAPLING then return M.sapling_OnTalk(MapID, InstanceID, TargetID, TargetTypeID, RoleID, TalkIndex) elseif plot0.Stage == map_def.STAGE_FIRST then return M.first_OnTalk(MapID, InstanceID, TargetID, TargetTypeID, RoleID, TalkIndex) elseif plot0.Stage == map_def.STAGE_SECOND then return M.second_OnTalk(MapID, InstanceID, TargetID, TargetTypeID, RoleID, TalkIndex) end end local plot = plot_store.getPlot(MapID, InstanceID, x, y, z) or { PlantId = 0, Stage = map_def.STAGE_MOUND, OwnerRoleID = 0, LastPlotTime = 0, } if TalkIndex == -1 then local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420001) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 21, 12) msg.AddMsgEvent(MsgID, 1, 420003) msg.AddMsgEvent(MsgID, 21, 13) msg.AddMsgEvent(MsgID, 1, 420004) msg.AddMsgEvent(MsgID, 21, 11) msg.AddMsgEvent(MsgID, 1, 420002) msg.AddMsgEvent(MsgID, 21, 14) msg.AddMsgEvent(MsgID, 1, 420005) msg.AddMsgEvent(MsgID, 21, 15) msg.AddMsgEvent(MsgID, 1, 420006) msg.AddMsgEvent(MsgID, 21, 16) msg.AddMsgEvent(MsgID, 1, 420007) msg.AddMsgEvent(MsgID, 21, 17) msg.AddMsgEvent(MsgID, 1, 420008) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) return end if TalkIndex < 11 or TalkIndex > 17 then return end if not _cooldown_ok(plot, RoleID, now) then _msg_simple(RoleID, 420012) return end local plantIdByTalk = { [11] = 1, [12] = 2, [13] = 3, [14] = 4, [15] = 5, [16] = 6, [17] = 7, } local plantId = plantIdByTalk[TalkIndex] if plantId == nil then return end if _plant_seed(MapID, InstanceID, TargetID, RoleID, plantId) then -- quest bits for planting flame tree (TalkIndex 12) (legacy behavior) if TalkIndex == 12 and role.IsRoleHaveQuest(MapID, InstanceID, RoleID, 40053) == true then role.ModSpecialTargetValue(MapID, InstanceID, RoleID, 40053, 2) local zero = _farm_level_raw(RoleID) local questdata = (zero % 1000 - zero % 100) / 100 if questdata == 0 then role_store.setRole(RoleID, { farmLevelRaw = zero + 100 }) end end end end function M.mound_advanced_OnTalk(MapID, InstanceID, TargetID, TargetTypeID, RoleID, TalkIndex) if TalkIndex == -1 then local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420001) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 21, 11) msg.AddMsgEvent(MsgID, 1, 420039) msg.AddMsgEvent(MsgID, 21, 12) msg.AddMsgEvent(MsgID, 1, 420040) msg.AddMsgEvent(MsgID, 21, 13) msg.AddMsgEvent(MsgID, 1, 420041) msg.AddMsgEvent(MsgID, 21, 14) msg.AddMsgEvent(MsgID, 1, 420042) msg.AddMsgEvent(MsgID, 21, 15) msg.AddMsgEvent(MsgID, 1, 420043) msg.AddMsgEvent(MsgID, 21, 16) msg.AddMsgEvent(MsgID, 1, 420044) msg.AddMsgEvent(MsgID, 21, 17) msg.AddMsgEvent(MsgID, 1, 420045) msg.AddMsgEvent(MsgID, 21, 18) msg.AddMsgEvent(MsgID, 1, 420046) msg.AddMsgEvent(MsgID, 21, 19) msg.AddMsgEvent(MsgID, 1, 420047) msg.AddMsgEvent(MsgID, 21, 20) msg.AddMsgEvent(MsgID, 1, 420048) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) elseif TalkIndex ~= 10 then local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420049) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) end end function M.seed_OnTalk(MapID, InstanceID, TargetID, TargetTypeID, RoleID, TalkIndex) TargetID, TargetTypeID, plot, x, y, z = M.syncPlotFromDB(MapID, InstanceID, TargetID, TargetTypeID) if plot == nil then return end local seedowner = plot.OwnerRoleID if TalkIndex == -1 then if seedowner == RoleID then local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420013) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 21, 11) msg.AddMsgEvent(MsgID, 1, 420014) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) else local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420015) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 2, seedowner) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) end return end if TalkIndex ~= 11 then return end if seedowner ~= RoleID then return end local num = role.GetRoleItemNum(RoleID, 4100007) if num <= 0 then _msg_simple(RoleID, 420017) return end role.RemoveFromRole(MapID, InstanceID, RoleID, 4100007, 1, 420) map.MapDeleteCreature(MapID, InstanceID, TargetID) local m = map_def.creature_to_plant[TargetTypeID] if m == nil then return end local def = map_def.plants[m.plantId] local now = _now() local saplingId = map.MapCreateCreature(MapID, InstanceID, def.creature[map_def.STAGE_SAPLING], x, y, z) plot_store.setPlot(MapID, InstanceID, x, y, z, { Stage = map_def.STAGE_SAPLING, StageStartTime = now }) -- quest bits for watering flame tree seed (TargetTypeID 5800035) if TargetTypeID == map_def.plants[2].creature[map_def.STAGE_SEED] and role.IsRoleHaveQuest(MapID, InstanceID, RoleID, 40054) == true then role.ModSpecialTargetValue(MapID, InstanceID, RoleID, 40054, 2) local r = _ensure_farm_role(RoleID) local zero = r.farmLevelRaw local questdata = (zero % 10000 - zero % 1000) / 1000 if questdata == 0 then role_store.setRole(RoleID, { farmLevelRaw = zero + 1000 }) end end end function M.sapling_OnTalk(MapID, InstanceID, TargetID, TargetTypeID, RoleID, TalkIndex) TargetID, TargetTypeID, plot, x, y, z = M.syncPlotFromDB(MapID, InstanceID, TargetID, TargetTypeID) if plot == nil then return end local now = _now() local seedowner = plot.OwnerRoleID local s = (plot.StageStartTime == 0) and 0 or os.difftime(now, plot.StageStartTime) -- auto-grow on interaction if ready (keeps original behavior) if plot.Stage == map_def.STAGE_SAPLING and s >= GROW_SECONDS then local def = map_def.plants[plot.PlantId] if def then map.MapDeleteCreature(MapID, InstanceID, TargetID) map.MapCreateCreature(MapID, InstanceID, def.creature[map_def.STAGE_FIRST], x, y, z) plot_store.setPlot(MapID, InstanceID, x, y, z, { Stage = map_def.STAGE_FIRST, StageStartTime = now }) end return end if TalkIndex == -1 then if seedowner == RoleID then local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420016) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 9, math.floor(60 - s / 60)) msg.AddMsgEvent(MsgID, 21, 11) msg.AddMsgEvent(MsgID, 1, 420018) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) else local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420019) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 2, seedowner) msg.AddMsgEvent(MsgID, 9, math.floor(60 - s / 60)) msg.AddMsgEvent(MsgID, 21, 12) msg.AddMsgEvent(MsgID, 1, 420020) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) end return end if TalkIndex == 11 then local num = role.GetRoleItemNum(RoleID, 4100901) local num2 = role.GetRoleItemNum(RoleID, 4100902) if num <= 0 and num2 <= 0 then _msg_simple(RoleID, 420021) return end if num2 > 0 then role.RemoveFromRole(MapID, InstanceID, RoleID, 4100902, 1, 420) else role.RemoveFromRole(MapID, InstanceID, RoleID, 4100901, 1, 420) end local def = map_def.plants[plot.PlantId] if def == nil then return end map.MapDeleteCreature(MapID, InstanceID, TargetID) map.MapCreateCreature(MapID, InstanceID, def.creature[map_def.STAGE_FIRST], x, y, z) plot_store.setPlot(MapID, InstanceID, x, y, z, { Stage = map_def.STAGE_FIRST, StageStartTime = now }) return end if TalkIndex == 12 then local num = role.GetRoleItemNum(RoleID, 4100903) if num <= 0 then _msg_simple(RoleID, 420022) return end role.RemoveFromRole(MapID, InstanceID, RoleID, 4100903, 1, 420) _award_farm_exp(RoleID, TargetTypeID, RoleID) end end local function _first_reward(plantId, MapID, InstanceID, RoleID) if plantId == 1 then local a = math.random(1, 200) if a <= 199 then role.AddRoleItem(MapID, InstanceID, RoleID, 4400001, 1, -1, 8, 102) else role.AddRoleItem(MapID, InstanceID, RoleID, 4400001, 1, -1, 8, 102) role.AddRoleItem(MapID, InstanceID, RoleID, 4400003, 1, -1, 8, 102) end return end local itemByPlant = { [2] = 4100201, [3] = 4100202, [4] = 4100203, [5] = 4100204, [6] = 4100205, [7] = 4100206, } local item = itemByPlant[plantId] if item == nil then return end local a = math.random(1, 200) if a <= 100 then role.AddRoleItem(MapID, InstanceID, RoleID, item, 1, -1, 8, 102) else role.AddRoleItem(MapID, InstanceID, RoleID, item, 2, -1, 8, 102) end end local function _second_reward(plantId, MapID, InstanceID, RoleID) if plantId == 1 then local a = math.random(1, 1000) if a <= 300 then role.AddRoleItem(MapID, InstanceID, RoleID, 4400001, 2, -1, 8, 102) elseif a <= 860 then role.AddRoleItem(MapID, InstanceID, RoleID, 4400002, 1, -1, 8, 102) elseif a <= 963 then role.AddRoleItem(MapID, InstanceID, RoleID, 4400003, 1, -1, 8, 102) elseif a <= 983 then role.AddRoleItem(MapID, InstanceID, RoleID, 4400004, 1, -1, 8, 102) elseif a <= 988 then role.AddRoleItem(MapID, InstanceID, RoleID, 4400005, 1, -1, 8, 102) elseif a <= 990 then role.AddRoleItem(MapID, InstanceID, RoleID, 4100107, 1, -1, 8, 102) elseif a <= 992 then role.AddRoleItem(MapID, InstanceID, RoleID, 4100106, 1, -1, 8, 102) elseif a <= 994 then role.AddRoleItem(MapID, InstanceID, RoleID, 4100105, 1, -1, 8, 102) elseif a <= 996 then role.AddRoleItem(MapID, InstanceID, RoleID, 4100104, 1, -1, 8, 102) elseif a <= 998 then role.AddRoleItem(MapID, InstanceID, RoleID, 4100103, 1, -1, 8, 102) else role.AddRoleItem(MapID, InstanceID, RoleID, 4100102, 1, -1, 8, 102) end return end local itemByPlant = { [2] = { item = 4100201, seed = 4100108 }, [3] = { item = 4100202, seed = 4100109 }, [4] = { item = 4100203, seed = 4100110 }, [5] = { item = 4100204, seed = 4100111 }, [6] = { item = 4100205, seed = 4100112 }, [7] = { item = 4100206, seed = 4100113 }, } local cfg = itemByPlant[plantId] if cfg == nil then return end local a = math.random(1, 1000) if a <= 600 then role.AddRoleItem(MapID, InstanceID, RoleID, cfg.item, 5, -1, 8, 102) else role.AddRoleItem(MapID, InstanceID, RoleID, cfg.item, 5, -1, 8, 102) role.AddRoleItem(MapID, InstanceID, RoleID, cfg.seed, 1, -1, 8, 102) end end function M.first_OnTalk(MapID, InstanceID, TargetID, TargetTypeID, RoleID, TalkIndex) TargetID, TargetTypeID, plot, x, y, z = M.syncPlotFromDB(MapID, InstanceID, TargetID, TargetTypeID) if plot == nil then return end local seedowner = plot.OwnerRoleID _ensure_farm_role(RoleID) if TalkIndex == -1 then if seedowner == RoleID then local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420024) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 5, TargetTypeID) msg.AddMsgEvent(MsgID, 21, 11) msg.AddMsgEvent(MsgID, 1, 420025) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) else local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420026) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 2, seedowner) msg.AddMsgEvent(MsgID, 21, 12) msg.AddMsgEvent(MsgID, 1, 420025) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) end return end if TalkIndex ~= 11 and TalkIndex ~= 12 then return end local now = _now() _first_reward(plot.PlantId, MapID, InstanceID, RoleID) local def = map_def.plants[plot.PlantId] if def == nil then return end map.MapDeleteCreature(MapID, InstanceID, TargetID) map.MapCreateCreature(MapID, InstanceID, def.creature[map_def.STAGE_SECOND], x, y, z) plot_store.setPlot(MapID, InstanceID, x, y, z, { Stage = map_def.STAGE_SECOND, StageStartTime = now }) _award_farm_exp(RoleID, TargetTypeID, (TalkIndex == 11) and seedowner or RoleID) if TalkIndex == 12 then local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 13, 1) msg.AddMsgEvent(MsgID, 1, 420027) msg.AddMsgEvent(MsgID, 5, TargetTypeID) msg.AddMsgEvent(MsgID, 2, RoleID) msg.DispatchRoleMsgEvent(seedowner, MsgID) end end function M.second_OnTalk(MapID, InstanceID, TargetID, TargetTypeID, RoleID, TalkIndex) TargetID, TargetTypeID, plot, x, y, z = M.syncPlotFromDB(MapID, InstanceID, TargetID, TargetTypeID) if plot == nil then return end local seedowner = plot.OwnerRoleID _ensure_farm_role(RoleID) if TalkIndex == -1 then if seedowner == RoleID then local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420024) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 5, TargetTypeID) msg.AddMsgEvent(MsgID, 21, 11) msg.AddMsgEvent(MsgID, 1, 420025) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) else local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420028) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 2, seedowner) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) end return end if TalkIndex ~= 11 then return end if seedowner ~= RoleID then return end local now = _now() _second_reward(plot.PlantId, MapID, InstanceID, RoleID) map.MapDeleteCreature(MapID, InstanceID, TargetID) map.MapCreateCreature(MapID, InstanceID, map_def.MOUND_BASIC, x, y, z) plot_store.setPlot(MapID, InstanceID, x, y, z, { PlantId = 0, Stage = map_def.STAGE_MOUND, OwnerRoleID = seedowner, LastPlotTime = now, StageStartTime = 0, }) _award_farm_exp(RoleID, TargetTypeID, seedowner) end function M.onDisappear(MapID, InstanceID, TargetID, Ai) local plot, x, y, z = _get_plot_by_target(MapID, InstanceID, TargetID) if plot == nil then return end local now = _now() if plot.Stage == map_def.STAGE_MOUND then return end -- Preserve legacy behaviors: -- - SEED: reset to mound + cooldown -- - SAPLING: advance to FIRST and notify owner (420023) -- - SECOND: reset to mound + cooldown if plot.Stage == map_def.STAGE_SAPLING then local def = map_def.plants[plot.PlantId] if def then map.MapCreateCreature(MapID, InstanceID, def.creature[map_def.STAGE_FIRST], x, y, z) plot_store.setPlot(MapID, InstanceID, x, y, z, { Stage = map_def.STAGE_FIRST, StageStartTime = now }) local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 13, 1) msg.AddMsgEvent(MsgID, 1, 420023) msg.AddMsgEvent(MsgID, 5, TargetID) msg.DispatchRoleMsgEvent(plot.OwnerRoleID, MsgID) end return end plot_store.setPlot(MapID, InstanceID, x, y, z, { PlantId = 0, Stage = map_def.STAGE_MOUND, OwnerRoleID = plot.OwnerRoleID, LastPlotTime = now, StageStartTime = 0, }) map.MapCreateCreature(MapID, InstanceID, map_def.MOUND_BASIC, x, y, z) end function M.guanli_OnTalk(MapID, InstanceID, TargetID, TargetTypeID, RoleID, TalkIndex) local r = _ensure_farm_role(RoleID) local zero = r.farmLevelRaw local farmlevel = zero % 10 local farmexp = r.farmExp if farmlevel == 9 then farmexp = 0 end local lexp = (map_def.farm_exp[farmlevel] or 0) - farmexp if TalkIndex == -1 then local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420034) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 21, 11) msg.AddMsgEvent(MsgID, 1, 420035) msg.AddMsgEvent(MsgID, 21, 12) msg.AddMsgEvent(MsgID, 1, 420036) msg.AddMsgEvent(MsgID, 21, 13) msg.AddMsgEvent(MsgID, 1, 420050) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) elseif TalkIndex == 11 then local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420037) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 9, farmlevel) msg.AddMsgEvent(MsgID, 9, farmexp) msg.AddMsgEvent(MsgID, 9, lexp) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) elseif TalkIndex == 12 then local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420038) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) elseif TalkIndex == 13 then local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 20, 420051) msg.AddMsgEvent(MsgID, 24, TargetID) msg.AddMsgEvent(MsgID, 21, 10) msg.AddMsgEvent(MsgID, 1, 420009) msg.DispatchRoleMsgEvent(RoleID, MsgID) end end function M.s4100904_Use(MapID, InstanceID, TypeID, RoleID) local r = _ensure_farm_role(RoleID) local zero = r.farmLevelRaw local farmlevel = zero % 10 local farmexp = r.farmExp if farmlevel < 9 then farmexp = farmexp + 10 if farmexp >= (map_def.farm_exp[farmlevel] or 0) then farmexp = farmexp - (map_def.farm_exp[farmlevel] or 0) zero = zero + 1 farmlevel = farmlevel + 1 role_store.setRole(RoleID, { farmLevelRaw = zero, farmExp = farmexp }) local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 13, 1) msg.AddMsgEvent(MsgID, 1, 420031) msg.AddMsgEvent(MsgID, 9, farmlevel) msg.DispatchRoleMsgEvent(RoleID, MsgID) else role_store.setRole(RoleID, { farmExp = farmexp }) local ex = (map_def.farm_exp[farmlevel] or 0) - farmexp local MsgID = msg.BeginMsgEvent() msg.AddMsgEvent(MsgID, 13, 1) msg.AddMsgEvent(MsgID, 1, 420032) msg.AddMsgEvent(MsgID, 9, farmexp) msg.AddMsgEvent(MsgID, 9, ex) msg.DispatchRoleMsgEvent(RoleID, MsgID) end else _msg_simple(RoleID, 420033) end end return M