Skip to content

Commit

Permalink
Add flooring and proper order to each speed factor
Browse files Browse the repository at this point in the history
Co-authored-by: cocosolos <[email protected]>
  • Loading branch information
Xaver-DaRed and cocosolos committed Sep 10, 2024
1 parent b3fd755 commit 328cb9b
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 62 deletions.
2 changes: 1 addition & 1 deletion scripts/effects/bolters_roll.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
local effectObject = {}

effectObject.onEffectGain = function(target, effect)
effect:addMod(xi.mod.MOVE_SPEED_STACKABLE, effect:getPower())
effect:addMod(xi.mod.MOVE_SPEED_BOLTERS_ROLL, effect:getPower())
end

effectObject.onEffectTick = function(target, effect)
Expand Down
18 changes: 10 additions & 8 deletions scripts/enum/mod.lua
Original file line number Diff line number Diff line change
Expand Up @@ -234,15 +234,17 @@ xi.mod =
HASTE_MAGIC = 167,
SPELLINTERRUPT = 168,

-- Movement speed modifiers
MOVE_SPEED_OVERRIDE = 169, -- Modifier used to overide regular speed caps. (GM speed and Feast of Swords)
MOVE_SPEED_STACKABLE = 75, -- Gear movement speed penalties, etc.
MOVE_SPEED_GEAR_BONUS = 76, -- Gear movement speed bonuses. DOES NOT STACK with each other, only highest applies.
MOVE_SPEED_WEIGHT_PENALTY = 77, -- For Gravity and curse.
MOVE_SPEED_QUICKENING = 78, -- Jig, spreinter shoes, etc. Only highest of Mazurka OR quickening will take effect.
MOVE_SPEED_MAZURKA = 79, -- Song movement speed. Only highest of Mazurka OR quickening will take effect.
MOVE_SPEED_FLEE = 1085, -- Flee applies a separate multiplier to speed.
-- Movement speed modifiers in use order.
MOUNT_MOVE = 972, -- % Mount Movement Speed
MOVE_SPEED_STACKABLE = 75, -- Additive modifier. Applied before multipliers. Gear movement speed penalties.
MOVE_SPEED_WEIGHT_PENALTY = 77, -- Multiplicative modifier. For Gravity and curse.
MOVE_SPEED_FLEE = 1085, -- Multiplicative modifier.
MOVE_SPEED_CHEER = 1087, -- Multiplicative modifier from "cheer" type KI's.
MOVE_SPEED_GEAR_BONUS = 76, -- Multiplicative modifier. Gear movement speed bonuses. DOES NOT STACK with each other, only highest applies.
MOVE_SPEED_QUICKENING = 78, -- Additive modifier. Applied after multipliers. Jig, spreinter shoes, etc. Shares cap with Mazurka.
MOVE_SPEED_MAZURKA = 79, -- Additive modifier. Applied after multipliers. Song movement speed. Shares cap with Quickening,
MOVE_SPEED_BOLTERS_ROLL = 1086, -- Additive modifier. Applied after multipliers.
MOVE_SPEED_OVERRIDE = 169, -- Modifier used to overide regular speed caps. (GM speed and Feast of Swords)

FASTCAST = 170,
UFASTCAST = 407,
Expand Down
62 changes: 31 additions & 31 deletions scripts/globals/job_utils/corsair.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,37 @@ xi.job_utils.corsair = xi.job_utils.corsair or {}
-- TODO: verify Corsair's Roll for subjob: see http://wiki.ffo.jp/html/6052.html
local corsairRollMods =
{
[xi.jobAbility.CORSAIRS_ROLL ] = { { 10, 11, 11, 12, 20, 13, 15, 16, 8, 17, 24, 6 }, 2, 0, xi.effect.CORSAIRS_ROLL, xi.mod.EXP_BONUS, xi.job.COR },
[xi.jobAbility.NINJA_ROLL ] = { { 4, 5, 5, 14, 6, 7, 9, 2, 10, 11, 18, 6 }, 2, 6, xi.effect.NINJA_ROLL, xi.mod.EVA, xi.job.NIN },
[xi.jobAbility.HUNTERS_ROLL ] = { { 10, 13, 15, 40, 18, 20, 25, 5, 27, 30, 50, 5 }, 5, 15, xi.effect.HUNTERS_ROLL, xi.mod.ACC, xi.job.RNG },
[xi.jobAbility.CHAOS_ROLL ] = { { 6, 8, 9, 25, 11, 13, 16, 3, 17, 19, 31, 10 }, 3, 10, xi.effect.CHAOS_ROLL, xi.mod.ATTP, xi.job.DRK },
[xi.jobAbility.MAGUSS_ROLL ] = { { 5, 20, 6, 8, 9, 3, 10, 13, 14, 15, 25, 5 }, 2, 8, xi.effect.MAGUSS_ROLL, xi.mod.MDEF, xi.job.BLU },
[xi.jobAbility.HEALERS_ROLL ] = { { 3, 4, 12, 5, 6, 7, 1, 8, 9, 10, 16, 4 }, 3, 4, xi.effect.HEALERS_ROLL, xi.mod.CURE_POTENCY_RCVD, xi.job.WHM },
[xi.jobAbility.DRACHEN_ROLL ] = { { 10, 13, 15, 40, 18, 20, 25, 5, 28, 30, 50, 15 }, 5, 15, xi.effect.DRACHEN_ROLL, nil, xi.job.DRG },
[xi.jobAbility.CHORAL_ROLL ] = { { 13, 55, 17, 20, 25, 8, 30, 35, 40, 45, 65, 25 }, 4, 25, xi.effect.CHORAL_ROLL, xi.mod.SPELLINTERRUPT, xi.job.BRD },
[xi.jobAbility.MONKS_ROLL ] = { { 8, 10, 32, 12, 14, 16, 4, 20, 22, 24, 40, 11 }, 4, 10, xi.effect.MONKS_ROLL, xi.mod.SUBTLE_BLOW, xi.job.MNK },
[xi.jobAbility.BEAST_ROLL ] = { { 4, 5, 7, 19, 8, 9, 11, 2, 13, 14, 23, 7 }, 3, 10, xi.effect.BEAST_ROLL, nil, xi.job.BST },
[xi.jobAbility.SAMURAI_ROLL ] = { { 8, 32, 10, 12, 14, 4, 16, 20, 22, 24, 40, 5 }, 4, 10, xi.effect.SAMURAI_ROLL, xi.mod.STORETP, xi.job.SAM },
[xi.jobAbility.EVOKERS_ROLL ] = { { 1, 1, 1, 1, 3, 2, 2, 2, 1, 3, 4, 1 }, 1, 1, xi.effect.EVOKERS_ROLL, xi.mod.REFRESH, xi.job.SMN },
[xi.jobAbility.ROGUES_ROLL ] = { { 2, 2, 3, 4, 12, 5, 6, 6, 1, 8, 19, 6 }, 1, 6, xi.effect.ROGUES_ROLL, xi.mod.CRITHITRATE, xi.job.THF },
[xi.jobAbility.WARLOCKS_ROLL ] = { { 2, 3, 4, 12, 5, 6, 7, 1, 8, 9, 15, 5 }, 1, 5, xi.effect.WARLOCKS_ROLL, xi.mod.MACC, xi.job.RDM },
[xi.jobAbility.FIGHTERS_ROLL ] = { { 2, 2, 3, 4, 12, 5, 6, 7, 1, 9, 18, 6 }, 1, 6, xi.effect.FIGHTERS_ROLL, xi.mod.DOUBLE_ATTACK, xi.job.WAR },
[xi.jobAbility.PUPPET_ROLL ] = { { 4, 5, 18, 7, 9, 10, 2, 11, 13, 15, 22, 8 }, 3, 8, xi.effect.PUPPET_ROLL, nil, xi.job.PUP },
[xi.jobAbility.GALLANTS_ROLL ] = { { 600, 800, 2400, 900, 1100, 1200, 300, 1500, 1700, 1800, 3000, 500 }, 234, 500, xi.effect.GALLANTS_ROLL, xi.mod.DMG, xi.job.PLD },
[xi.jobAbility.WIZARDS_ROLL ] = { { 4, 6, 8, 10, 25, 12, 14, 17, 2, 20, 30, 10 }, 2, 10, xi.effect.WIZARDS_ROLL, xi.mod.MATT, xi.job.BLM },
[xi.jobAbility.DANCERS_ROLL ] = { { 3, 4, 12, 5, 6, 7, 1, 8, 9, 10, 16, 4 }, 2, 4, xi.effect.DANCERS_ROLL, xi.mod.REGEN, xi.job.DNC },
[xi.jobAbility.SCHOLARS_ROLL ] = { { 2, 9, 3, 4, 5, 2, 6, 6, 7, 9, 14, 4 }, 1, 4, xi.effect.SCHOLARS_ROLL, xi.mod.CONSERVE_MP, xi.job.SCH },
[xi.jobAbility.NATURALISTS_ROLL] = { { 6, 7, 15, 8, 9, 10, 5, 11, 12, 13, 20, -5 }, 1, 5, xi.effect.NATURALISTS_ROLL, xi.mod.ENH_MAGIC_DURATION, xi.job.GEO },
[xi.jobAbility.RUNEISTS_ROLL ] = { { 4, 6, 8, 25, 10, 12, 14, 2, 17, 20, 30, -10 }, 2, 7, xi.effect.RUNEISTS_ROLL, xi.mod.MEVA, xi.job.RUN },
[xi.jobAbility.BOLTERS_ROLL ] = { { 6, 6, 16, 8, 8, 10, 10, 12, 4, 14, 20, 0 }, 4, 0, xi.effect.BOLTERS_ROLL, xi.mod.MOVE_SPEED_STACKABLE, xi.job.NONE },
[xi.jobAbility.CASTERS_ROLL ] = { { 6, 15, 7, 8, 9, 10, 5, 11, 12, 13, 20, -10 }, 3, 10, xi.effect.CASTERS_ROLL, xi.mod.FASTCAST, xi.job.NONE },
[xi.jobAbility.COURSERS_ROLL ] = { { 2, 3, 11, 4, 5, 6, 7, 8, 1, 10, 12, -5 }, 1, 3, xi.effect.COURSERS_ROLL, nil, xi.job.NONE },
[xi.jobAbility.BLITZERS_ROLL ] = { { -2, -3, -4, -11, -5, -6, -7, -8, -1, -10, -12, 3 }, -1, -3, xi.effect.BLITZERS_ROLL, xi.mod.DELAYP, xi.job.NONE },
[xi.jobAbility.TACTICIANS_ROLL ] = { { 10, 10, 10, 10, 30, 10, 10, 0, 20, 20, 40, -10 }, 2, 10, xi.effect.TACTICIANS_ROLL, xi.mod.REGAIN, xi.job.NONE },
[xi.jobAbility.ALLIES_ROLL ] = { { 2, 3, 20, 5, 7, 9, 11, 13, 15, 1, 25, -5 }, 1, 5, xi.effect.ALLIES_ROLL, xi.mod.SKILLCHAINBONUS, xi.job.NONE },
[xi.jobAbility.MISERS_ROLL ] = { { 30, 50, 70, 90, 200, 110, 20, 130, 150, 170, 250, 0 }, 15, 0, xi.effect.MISERS_ROLL, xi.mod.SAVETP, xi.job.NONE },
[xi.jobAbility.COMPANIONS_ROLL ] = { { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0 }, 10, 0, xi.effect.COMPANIONS_ROLL, nil, xi.job.NONE },
[xi.jobAbility.AVENGERS_ROLL ] = { { 2, 2, 3, 12, 4, 5, 6, 1, 7, 9, 18, 6 }, 1, 0, xi.effect.AVENGERS_ROLL, xi.mod.COUNTER, xi.job.NONE },
[xi.jobAbility.CORSAIRS_ROLL ] = { { 10, 11, 11, 12, 20, 13, 15, 16, 8, 17, 24, 6 }, 2, 0, xi.effect.CORSAIRS_ROLL, xi.mod.EXP_BONUS, xi.job.COR },
[xi.jobAbility.NINJA_ROLL ] = { { 4, 5, 5, 14, 6, 7, 9, 2, 10, 11, 18, 6 }, 2, 6, xi.effect.NINJA_ROLL, xi.mod.EVA, xi.job.NIN },
[xi.jobAbility.HUNTERS_ROLL ] = { { 10, 13, 15, 40, 18, 20, 25, 5, 27, 30, 50, 5 }, 5, 15, xi.effect.HUNTERS_ROLL, xi.mod.ACC, xi.job.RNG },
[xi.jobAbility.CHAOS_ROLL ] = { { 6, 8, 9, 25, 11, 13, 16, 3, 17, 19, 31, 10 }, 3, 10, xi.effect.CHAOS_ROLL, xi.mod.ATTP, xi.job.DRK },
[xi.jobAbility.MAGUSS_ROLL ] = { { 5, 20, 6, 8, 9, 3, 10, 13, 14, 15, 25, 5 }, 2, 8, xi.effect.MAGUSS_ROLL, xi.mod.MDEF, xi.job.BLU },
[xi.jobAbility.HEALERS_ROLL ] = { { 3, 4, 12, 5, 6, 7, 1, 8, 9, 10, 16, 4 }, 3, 4, xi.effect.HEALERS_ROLL, xi.mod.CURE_POTENCY_RCVD, xi.job.WHM },
[xi.jobAbility.DRACHEN_ROLL ] = { { 10, 13, 15, 40, 18, 20, 25, 5, 28, 30, 50, 15 }, 5, 15, xi.effect.DRACHEN_ROLL, nil, xi.job.DRG },
[xi.jobAbility.CHORAL_ROLL ] = { { 13, 55, 17, 20, 25, 8, 30, 35, 40, 45, 65, 25 }, 4, 25, xi.effect.CHORAL_ROLL, xi.mod.SPELLINTERRUPT, xi.job.BRD },
[xi.jobAbility.MONKS_ROLL ] = { { 8, 10, 32, 12, 14, 16, 4, 20, 22, 24, 40, 11 }, 4, 10, xi.effect.MONKS_ROLL, xi.mod.SUBTLE_BLOW, xi.job.MNK },
[xi.jobAbility.BEAST_ROLL ] = { { 4, 5, 7, 19, 8, 9, 11, 2, 13, 14, 23, 7 }, 3, 10, xi.effect.BEAST_ROLL, nil, xi.job.BST },
[xi.jobAbility.SAMURAI_ROLL ] = { { 8, 32, 10, 12, 14, 4, 16, 20, 22, 24, 40, 5 }, 4, 10, xi.effect.SAMURAI_ROLL, xi.mod.STORETP, xi.job.SAM },
[xi.jobAbility.EVOKERS_ROLL ] = { { 1, 1, 1, 1, 3, 2, 2, 2, 1, 3, 4, 1 }, 1, 1, xi.effect.EVOKERS_ROLL, xi.mod.REFRESH, xi.job.SMN },
[xi.jobAbility.ROGUES_ROLL ] = { { 2, 2, 3, 4, 12, 5, 6, 6, 1, 8, 19, 6 }, 1, 6, xi.effect.ROGUES_ROLL, xi.mod.CRITHITRATE, xi.job.THF },
[xi.jobAbility.WARLOCKS_ROLL ] = { { 2, 3, 4, 12, 5, 6, 7, 1, 8, 9, 15, 5 }, 1, 5, xi.effect.WARLOCKS_ROLL, xi.mod.MACC, xi.job.RDM },
[xi.jobAbility.FIGHTERS_ROLL ] = { { 2, 2, 3, 4, 12, 5, 6, 7, 1, 9, 18, 6 }, 1, 6, xi.effect.FIGHTERS_ROLL, xi.mod.DOUBLE_ATTACK, xi.job.WAR },
[xi.jobAbility.PUPPET_ROLL ] = { { 4, 5, 18, 7, 9, 10, 2, 11, 13, 15, 22, 8 }, 3, 8, xi.effect.PUPPET_ROLL, nil, xi.job.PUP },
[xi.jobAbility.GALLANTS_ROLL ] = { { 600, 800, 2400, 900, 1100, 1200, 300, 1500, 1700, 1800, 3000, 500 }, 234, 500, xi.effect.GALLANTS_ROLL, xi.mod.DMG, xi.job.PLD },
[xi.jobAbility.WIZARDS_ROLL ] = { { 4, 6, 8, 10, 25, 12, 14, 17, 2, 20, 30, 10 }, 2, 10, xi.effect.WIZARDS_ROLL, xi.mod.MATT, xi.job.BLM },
[xi.jobAbility.DANCERS_ROLL ] = { { 3, 4, 12, 5, 6, 7, 1, 8, 9, 10, 16, 4 }, 2, 4, xi.effect.DANCERS_ROLL, xi.mod.REGEN, xi.job.DNC },
[xi.jobAbility.SCHOLARS_ROLL ] = { { 2, 9, 3, 4, 5, 2, 6, 6, 7, 9, 14, 4 }, 1, 4, xi.effect.SCHOLARS_ROLL, xi.mod.CONSERVE_MP, xi.job.SCH },
[xi.jobAbility.NATURALISTS_ROLL] = { { 6, 7, 15, 8, 9, 10, 5, 11, 12, 13, 20, -5 }, 1, 5, xi.effect.NATURALISTS_ROLL, xi.mod.ENH_MAGIC_DURATION, xi.job.GEO },
[xi.jobAbility.RUNEISTS_ROLL ] = { { 4, 6, 8, 25, 10, 12, 14, 2, 17, 20, 30, -10 }, 2, 7, xi.effect.RUNEISTS_ROLL, xi.mod.MEVA, xi.job.RUN },
[xi.jobAbility.BOLTERS_ROLL ] = { { 6, 6, 16, 8, 8, 10, 10, 12, 4, 14, 20, 0 }, 4, 0, xi.effect.BOLTERS_ROLL, xi.mod.MOVE_SPEED_BOLTERS_ROLL, xi.job.NONE },
[xi.jobAbility.CASTERS_ROLL ] = { { 6, 15, 7, 8, 9, 10, 5, 11, 12, 13, 20, -10 }, 3, 10, xi.effect.CASTERS_ROLL, xi.mod.FASTCAST, xi.job.NONE },
[xi.jobAbility.COURSERS_ROLL ] = { { 2, 3, 11, 4, 5, 6, 7, 8, 1, 10, 12, -5 }, 1, 3, xi.effect.COURSERS_ROLL, nil, xi.job.NONE },
[xi.jobAbility.BLITZERS_ROLL ] = { { -2, -3, -4, -11, -5, -6, -7, -8, -1, -10, -12, 3 }, -1, -3, xi.effect.BLITZERS_ROLL, xi.mod.DELAYP, xi.job.NONE },
[xi.jobAbility.TACTICIANS_ROLL ] = { { 10, 10, 10, 10, 30, 10, 10, 0, 20, 20, 40, -10 }, 2, 10, xi.effect.TACTICIANS_ROLL, xi.mod.REGAIN, xi.job.NONE },
[xi.jobAbility.ALLIES_ROLL ] = { { 2, 3, 20, 5, 7, 9, 11, 13, 15, 1, 25, -5 }, 1, 5, xi.effect.ALLIES_ROLL, xi.mod.SKILLCHAINBONUS, xi.job.NONE },
[xi.jobAbility.MISERS_ROLL ] = { { 30, 50, 70, 90, 200, 110, 20, 130, 150, 170, 250, 0 }, 15, 0, xi.effect.MISERS_ROLL, xi.mod.SAVETP, xi.job.NONE },
[xi.jobAbility.COMPANIONS_ROLL ] = { { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0 }, 10, 0, xi.effect.COMPANIONS_ROLL, nil, xi.job.NONE },
[xi.jobAbility.AVENGERS_ROLL ] = { { 2, 2, 3, 12, 4, 5, 6, 1, 7, 9, 18, 6 }, 1, 0, xi.effect.AVENGERS_ROLL, xi.mod.COUNTER, xi.job.NONE },
}

-- Check for xi.mod.PHANTOM_ROLL Value and apply non-stack logic.
Expand Down
36 changes: 23 additions & 13 deletions src/map/entities/battleentity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,32 +256,42 @@ uint8 CBattleEntity::GetSpeed()
}

// Gear penalties, Bolters Roll.
float additiveMods = static_cast<float>(getMod(Mod::MOVE_SPEED_STACKABLE));
uint8 additiveMods = static_cast<uint8>(getMod(Mod::MOVE_SPEED_STACKABLE));

// Quickening and Mazurka. They share a cap. Additive.
float effectAdditiveBonus = std::clamp<float>(getMod(Mod::MOVE_SPEED_QUICKENING) + getMod(Mod::MOVE_SPEED_MAZURKA), 0.0f, 10.0f);
// Gravity and Curse. They seem additive to each other and the sum seems to be multiplicative.
float weightFactor = std::clamp<float>(1.0f - static_cast<float>(getMod(Mod::MOVE_SPEED_WEIGHT_PENALTY)) / 100.0f, 0.1f, 1.0f);

// Flee.
float fleeFactor = std::clamp<float>(1.0f + static_cast<float>(getMod(Mod::MOVE_SPEED_FLEE)) / 100.0f, 1.0f, 2.0f);

// Cheer KI's
float cheerFactor = (99.0f + static_cast<float>(getMod(Mod::MOVE_SPEED_CHEER))) / 99.0f;

// Bolter's Roll. Additive
uint8 boltersRollEffect = static_cast<uint8>(getMod(Mod::MOVE_SPEED_BOLTERS_ROLL));

// Positive movement speed from gear and from Atmas. Only highest applies. Multiplicative to base speed.
float gearBonus = 1.0f;
float gearFactor = 1.0f;

if (objtype == TYPE_PC)
{
gearBonus = std::clamp<float>(1.0f + static_cast<float>(getMaxGearMod(Mod::MOVE_SPEED_GEAR_BONUS)) / 100.0f, 1.0f, 1.25f);
gearFactor = std::clamp<float>(1.0f + static_cast<float>(getMaxGearMod(Mod::MOVE_SPEED_GEAR_BONUS)) / 100.0f, 1.0f, 1.25f);
}

// Gravity and Curse. They seem additive to each other and the sum seems to be multiplicative.
float weightPenalties = std::clamp<float>(1.0f - static_cast<float>(getMod(Mod::MOVE_SPEED_WEIGHT_PENALTY)) / 100.0f, 0.1f, 1.0f);
// Quickening and Mazurka. They share a cap. Additive.
uint8 mazurkaQuickeningEffect = std::clamp<uint8>(getMod(Mod::MOVE_SPEED_QUICKENING) + getMod(Mod::MOVE_SPEED_MAZURKA), 0, 10);

// We have all the modifiers needed. Calculate final speed.
// Final speed = (base speed + addtive bonuses/penalties) * flee * positive bonus from gear * weight penalties
float modifiedSpeed = static_cast<float>(baseSpeed + additiveMods + effectAdditiveBonus) * fleeFactor * gearBonus * weightPenalties;

outputSpeed = static_cast<uint8>(modifiedSpeed);

// Set cap.
// This MUST BE DONE IN THIS ORDER. Using uint8 data type, we use that to floor.
outputSpeed = baseSpeed + additiveMods;
outputSpeed = outputSpeed * weightFactor;
outputSpeed = outputSpeed * fleeFactor;
outputSpeed = outputSpeed * cheerFactor;
outputSpeed = outputSpeed + boltersRollEffect;
outputSpeed = outputSpeed * gearFactor;
outputSpeed = outputSpeed + mazurkaQuickeningEffect;

// Set cap (Default 80).
outputSpeed = std::clamp<uint8>(outputSpeed, 0, 80 + settings::get<int8>("map.SPEED_MOD"));

// Speed cap can be bypassed. Ex. Feast of swords. GM speed.
Expand Down
Loading

0 comments on commit 328cb9b

Please sign in to comment.