diff --git a/scripts/enum/item.lua b/scripts/enum/item.lua index 0b10337e474..d9903b12a63 100644 --- a/scripts/enum/item.lua +++ b/scripts/enum/item.lua @@ -5785,6 +5785,7 @@ xi.item = PUGILISTS = 19327, SIMIAN_FISTS = 19328, MANTIS = 19329, + CATS_CLAWS = 19331, PEELER = 19332, RENEGADE = 19333, KARTIKA = 19334, diff --git a/scripts/globals/magian.lua b/scripts/globals/magian.lua index cba0d14853f..8701d43861f 100644 --- a/scripts/globals/magian.lua +++ b/scripts/globals/magian.lua @@ -444,10 +444,15 @@ xi.magian.magianEventUpdate = function(player, csid, option, npc) local requiredElement = trialData.requiredElement and trialData.requiredElement or 0 local optParam = 0 + -- NOTE: optParam value is required for certain messages, and even though + -- this system can support more complex combinations, it may not display correctly + -- if customizing. if trialData.tradeItem then optParam = getRequiredTradeItem(trialId) elseif trialData.minDamage then optParam = trialData.minDamage + elseif trialData.dayWeather then + optParam = trialData.dayWeather end player:updateEvent(trialData.numRequired, 0, progress, 0, 0, optParam, requiredElement) @@ -768,8 +773,106 @@ xi.magian.deliveryCrateOnEventFinish = function(player, csid, option) end end +-- NOTE: These values align with the optParam in the event update for a trial, and are the +-- only groupings supported by the message. These enum is to be used in the dayWeather +-- condition for trial data. +xi.magian.element = +{ + FIRE = 0, + ICE = 1, + WIND = 2, + EARTH = 3, + THUNDER = 4, + WATER = 5, + LIGHT = 6, + DARK = 7, + ANY_LIGHT = 8, + ANY_DARK = 9, + ANY = 10, +} + +-- [elementId] = { validDay, { weatherEffect1, weatherEffect2 } }, +local dayWeatherElement = +{ + [xi.element.FIRE ] = { xi.day.FIRESDAY, { xi.weather.HOT_SPELL, xi.weather.HEAT_WAVE } }, + [xi.element.ICE ] = { xi.day.ICEDAY, { xi.weather.SNOW, xi.weather.BLIZZARDS } }, + [xi.element.WIND ] = { xi.day.WINDSDAY, { xi.weather.WIND, xi.weather.GALES } }, + [xi.element.EARTH ] = { xi.day.EARTHSDAY, { xi.weather.DUST_STORM, xi.weather.SAND_STORM } }, + [xi.element.THUNDER] = { xi.day.LIGHTNINGDAY, { xi.weather.THUNDER, xi.weather.THUNDERSTORMS } }, + [xi.element.WATER ] = { xi.day.WATERSDAY, { xi.weather.RAIN, xi.weather.SQUALL } }, + [xi.element.LIGHT ] = { xi.day.LIGHTSDAY, { xi.weather.AURORAS, xi.weather.STELLAR_GLARE } }, + [xi.element.DARK ] = { xi.day.DARKSDAY, { xi.weather.GLOOM, xi.weather.DARKNESS } }, +} + +local elementData = +{ + [xi.magian.element.FIRE ] = { xi.element.FIRE }, + [xi.magian.element.ICE ] = { xi.element.ICE }, + [xi.magian.element.WIND ] = { xi.element.WIND }, + [xi.magian.element.EARTH ] = { xi.element.EARTH }, + [xi.magian.element.THUNDER ] = { xi.element.THUNDER }, + [xi.magian.element.WATER ] = { xi.element.WATER }, + [xi.magian.element.LIGHT ] = { xi.element.LIGHT }, + [xi.magian.element.DARK ] = { xi.element.DARK }, + [xi.magian.element.ANY_LIGHT] = + { + xi.element.FIRE, + xi.element.WIND, + xi.element.THUNDER, + xi.element.LIGHT, + }, + + [xi.magian.element.ANY_DARK] = + { + xi.element.ICE, + xi.element.EARTH, + xi.element.WATER, + xi.element.DARK, + }, + + [xi.magian.element.ANY] = + { + xi.element.FIRE, + xi.element.ICE, + xi.element.WIND, + xi.element.EARTH, + xi.element.THUNDER, + xi.element.WATER, + xi.element.LIGHT, + xi.element.DARK, + }, +} + local trialConditions = { + -- NOTE: This condition is a bit of an outlier, as it is both a condition and + -- can have a higher reward value as opposed to a credit of 1. Light and Dark are special exceptions + -- that should be handled in magian trial data, if it is the case where multiple elements are allowed. + ['dayWeather'] = function(trialData, player, mob, paramTable) + if trialData.dayWeather then + local dayWeatherResult = 0 + local dayWeatherTable = elementData[trialData.dayWeather] + + local currentWeather = player:getWeather(true) + for _, elementId in ipairs(dayWeatherTable) do + if dayWeatherElement[elementId][1] == VanadielDayOfTheWeek() then + dayWeatherResult = dayWeatherResult + 1 + end + + for _, weatherType in ipairs(dayWeatherElement[elementId][2]) do + if weatherType == currentWeather then + dayWeatherResult = dayWeatherResult and dayWeatherResult + 5 + break + end + end + end + + return dayWeatherResult > 0 and dayWeatherResult or false + end + + return true + end, + ['minDamage'] = function(trialData, player, mob, paramTable) return not trialData.minDamage or paramTable.weaponskillDamage >= trialData.minDamage end, @@ -782,6 +885,10 @@ local trialConditions = return not trialData.mobFamily or trialData.mobFamily[mob:getFamily()] end, + ['mobSuperFamily'] = function(trialData, player, mob, paramTable) + return not trialData.mobSuperFamily or trialData.mobSuperFamily[mob:getSuperFamily()] + end, + ['useWeaponskill'] = function(trialData, player, mob, paramTable) local weaponskillTable = type(trialData.useWeaponskill) == 'table' and trialData.useWeaponskill or set{ trialData.useWeaponskill } @@ -794,13 +901,19 @@ local trialConditions = } local function checkConditions(trialData, player, mob, paramTable) + local creditReward = 1 + for conditionName, conditionFunc in pairs(trialConditions) do - if not conditionFunc(trialData, player, mob, paramTable) then + local conditionResult = conditionFunc(trialData, player, mob, paramTable) + + if not conditionResult then return false + elseif type(conditionResult) == 'number' then + creditReward = conditionResult end end - return true + return creditReward end ----------------------------------- @@ -829,7 +942,6 @@ xi.magian.onItemEquip = function(player, itemObj) -- require the player to both be alive and the mob be experience-granting (NMs are handled separately) -- TODO: - -- Weather Type / Day (Weather = 5, Day = 1, Additive) Special exception for Light/Dark -- Elemental Damage (Anyone counts!) -- Pet kill -- Avatar Kill (Summon must be out, but another of the same type can cause credit) @@ -839,8 +951,10 @@ xi.magian.onItemEquip = function(player, itemObj) if trialData.defeatMob then player:addListener('DEFEATED_MOB', 'TRIAL_' .. itemTrialId, function(mobObj, playerObj, optParams) if not playerObj:isDead() and playerObj:checkKillCredit(mobObj) then - if checkConditions(trialData, playerObj, mobObj, optParams) then - progressPlayerTrial(playerObj, itemTrialId, 1) + local conditionResult = checkConditions(trialData, playerObj, mobObj, optParams) + + if conditionResult then + progressPlayerTrial(playerObj, itemTrialId, conditionResult) end end end) @@ -848,8 +962,10 @@ xi.magian.onItemEquip = function(player, itemObj) elseif trialData.useWeaponskill then player:addListener('WEAPONSKILL_USE', 'TRIAL_' .. itemTrialId, function(playerObj, mobObj, weaponskillId, tpSpent, action, damage) if not playerObj:isDead() and playerObj:checkKillCredit(mobObj) then - if checkConditions(trialData, playerObj, mobObj, { weaponskillUsed = weaponskillId, weaponskillDamage = damage }) then - progressPlayerTrial(playerObj, itemTrialId, 1) + local conditionResult = checkConditions(trialData, playerObj, mobObj, optParams) + + if conditionResult then + progressPlayerTrial(playerObj, itemTrialId, conditionResult) end end end) diff --git a/scripts/globals/magian_data.lua b/scripts/globals/magian_data.lua index 51f684787ac..87743370f90 100644 --- a/scripts/globals/magian_data.lua +++ b/scripts/globals/magian_data.lua @@ -500,6 +500,26 @@ xi.magian.trials = }, }, + [82] = + { + previousTrial = 0, + requiredItem = + { + itemId = xi.item.PUGILISTS, + }, + + textOffset = 99, + dayWeather = xi.magian.element.ANY, + defeatMob = true, + mobSuperFamily = set{ 56 }, + numRequired = 50, + + rewardItem = + { + itemId = xi.item.CATS_CLAWS, + }, + }, + [150] = -- Serpopard Ishtar x3 { previousTrial = 0, diff --git a/src/map/lua/lua_baseentity.cpp b/src/map/lua/lua_baseentity.cpp index 32ca8505c7f..725c4160e19 100644 --- a/src/map/lua/lua_baseentity.cpp +++ b/src/map/lua/lua_baseentity.cpp @@ -2204,13 +2204,14 @@ void CLuaBaseEntity::updateNPCHideTime(sol::object const& seconds) * Example : if player:getWeather() == xi.weather.WIND then ************************************************************************/ -uint8 CLuaBaseEntity::getWeather() +uint8 CLuaBaseEntity::getWeather(sol::object const& ignoreScholar) { WEATHER weather = WEATHER_NONE; if (m_PBaseEntity->objtype & TYPE_PC || m_PBaseEntity->objtype & TYPE_MOB) { - weather = battleutils::GetWeather(static_cast(m_PBaseEntity), false); + bool ignoreScholarWeather = ignoreScholar.is() ? ignoreScholar.as() : false; + weather = battleutils::GetWeather(static_cast(m_PBaseEntity), ignoreScholarWeather); } else { diff --git a/src/map/lua/lua_baseentity.h b/src/map/lua/lua_baseentity.h index 0e0de0b8b2b..69fb6604839 100644 --- a/src/map/lua/lua_baseentity.h +++ b/src/map/lua/lua_baseentity.h @@ -150,7 +150,7 @@ class CLuaBaseEntity void hideNPC(sol::object const& seconds); // hide an NPC void updateNPCHideTime(sol::object const& seconds); // Updates the length of time a NPC remains hidden, if shorter than the original hide time. - uint8 getWeather(); + uint8 getWeather(sol::object const& ignoreScholar); void setWeather(uint8 weatherType); // Set Weather condition (GM COMMAND) // PC Instructions diff --git a/tools/ci/lua.sh b/tools/ci/lua.sh index 89201539863..02a6f7755fd 100755 --- a/tools/ci/lua.sh +++ b/tools/ci/lua.sh @@ -114,10 +114,6 @@ global_objects=( TPMOD_ATTACK TPMOD_DURATION - INT_BASED - CHR_BASED - MND_BASED - ForceCrash BuildString