From fe43f00f9258b7af7b7bdb19ccc487e8ae94d07a Mon Sep 17 00:00:00 2001 From: claywar Date: Tue, 19 Sep 2023 11:31:23 -0400 Subject: [PATCH] [magian] Add support for day/weather condition to trials * Add optional parameter to getWeather in CLuaBaseEntity to ignore scholar effects * Remove unnecessary global exceptions in lua CI Add support for multiple elements to support light or darkness trials Add appropriate dayWeather groups and use those to support trial messages Add mobSuperFamily condition Return true if no dayWeather condition is set in a trial Add Trial 82 for example usage of dayWeather and mobSuperFamily condition Fix incorrect change for WS listener Move magianElement to enum to correct load order --- scripts/enum/item.lua | 1 + scripts/enum/magian_element.lua | 19 ++++++ scripts/globals/magian.lua | 112 ++++++++++++++++++++++++++++++-- scripts/globals/magian_data.lua | 20 ++++++ src/map/lua/lua_baseentity.cpp | 5 +- src/map/lua/lua_baseentity.h | 2 +- tools/ci/lua.sh | 4 -- 7 files changed, 149 insertions(+), 14 deletions(-) create mode 100644 scripts/enum/magian_element.lua 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/enum/magian_element.lua b/scripts/enum/magian_element.lua new file mode 100644 index 00000000000..690cd4a75c3 --- /dev/null +++ b/scripts/enum/magian_element.lua @@ -0,0 +1,19 @@ +xi = xi or {} + +-- 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.magianElement = +{ + FIRE = 0, + ICE = 1, + WIND = 2, + EARTH = 3, + THUNDER = 4, + WATER = 5, + LIGHT = 6, + DARK = 7, + ANY_LIGHT = 8, + ANY_DARK = 9, + ANY = 10, +} diff --git a/scripts/globals/magian.lua b/scripts/globals/magian.lua index cba0d14853f..9bd62f63740 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,88 @@ xi.magian.deliveryCrateOnEventFinish = function(player, csid, option) end end +-- [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.magianElement.FIRE ] = { xi.element.FIRE }, + [xi.magianElement.ICE ] = { xi.element.ICE }, + [xi.magianElement.WIND ] = { xi.element.WIND }, + [xi.magianElement.EARTH ] = { xi.element.EARTH }, + [xi.magianElement.THUNDER ] = { xi.element.THUNDER }, + [xi.magianElement.WATER ] = { xi.element.WATER }, + [xi.magianElement.LIGHT ] = { xi.element.LIGHT }, + [xi.magianElement.DARK ] = { xi.element.DARK }, + [xi.magianElement.ANY_LIGHT] = + { + xi.element.FIRE, + xi.element.WIND, + xi.element.THUNDER, + xi.element.LIGHT, + }, + + [xi.magianElement.ANY_DARK] = + { + xi.element.ICE, + xi.element.EARTH, + xi.element.WATER, + xi.element.DARK, + }, + + [xi.magianElement.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 +867,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 +883,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 +924,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 +933,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 +944,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, { weaponskillUsed = weaponskillId, weaponskillDamage = damage }) + + 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..395f39794f9 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.magianElement.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