Passed
Pull Request — master (#281)
by Vincent
15:23
created

computePointLost(FighterData,FighterData,int)   B

Complexity

Conditions 6

Size

Total Lines 42
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 21
dl 0
loc 42
ccs 20
cts 20
cp 1
c 0
b 0
f 0
cc 6
crap 6
rs 8.4426
1
/*
2
 * This file is part of Araknemu.
3
 *
4
 * Araknemu is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU Lesser General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * Araknemu is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public License
15
 * along with Araknemu.  If not, see <https://www.gnu.org/licenses/>.
16
 *
17
 * Copyright (c) 2017-2021 Vincent Quatrevieux
18
 */
19
20
package fr.quatrevieux.araknemu.game.fight.castable.effect.handler.characteristic.point;
21
22
import fr.arakne.utils.value.helper.RandomUtil;
23
import fr.quatrevieux.araknemu.data.constant.Characteristic;
24
import fr.quatrevieux.araknemu.game.fight.Fight;
25
import fr.quatrevieux.araknemu.game.fight.castable.FightCastScope;
26
import fr.quatrevieux.araknemu.game.fight.castable.effect.EffectValue;
27
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.Buff;
28
import fr.quatrevieux.araknemu.game.fight.castable.effect.buff.BuffEffect;
29
import fr.quatrevieux.araknemu.game.fight.fighter.Fighter;
30
import fr.quatrevieux.araknemu.game.fight.fighter.FighterData;
31
import fr.quatrevieux.araknemu.game.player.characteristic.ComputedCharacteristics;
32
import fr.quatrevieux.araknemu.game.spell.effect.SpellEffect;
33
import fr.quatrevieux.araknemu.network.game.out.fight.action.ActionEffect;
34
import org.checkerframework.checker.index.qual.NonNegative;
35
36
/**
37
 * Compute and apply turn point lost (action or movement)
38
 *
39
 * Formula: ([current points] / [base points]) * ([caster wisdom / 10] / [target dodge]) * 1/2
40
 * Each removal will be considered (and computed) independently : 2 AP loose with one spell is equivalent to two spells with 1 AP loose
41
 *
42
 * See: https://forums.jeuxonline.info/sujet/801243/les-formules-de-calcul-dans-dofus#titre_7
43
 */
44
public abstract class AbstractPointLostApplier {
45
    public static final int USE_SPELL_EFFECT = 0;
46
47
    private final Fight fight;
48
    private final AlterPointHook hook;
49
    private final Characteristic characteristic;
50
    private final Characteristic resistance;
51
    private final int removalPointEffect;
52
53 1
    private final RandomUtil random = new RandomUtil();
54
55 1
    protected AbstractPointLostApplier(Fight fight, AlterPointHook hook, Characteristic characteristic, Characteristic resistance, int removalPointEffect) {
56 1
        this.fight = fight;
57 1
        this.hook = hook;
58 1
        this.characteristic = characteristic;
59 1
        this.resistance = resistance;
60 1
        this.removalPointEffect = removalPointEffect;
61 1
    }
62
63
    /**
64
     * Apply the point lost effect
65
     *
66
     * A buff will be added and applied if the target do not dodge all points loose
67
     * If the target dodge a point lost, a message will be sent to the fight
68
     *
69
     * @param cast The cast action
70
     * @param target The fighter target
71
     * @param effect Effect to apply
72
     *
73
     * @return Number of lost points
74
     */
75
    public final int apply(FightCastScope cast, Fighter target, SpellEffect effect)  {
76 1
        final Fighter caster = cast.caster();
77
78 1
        final int baseValue = EffectValue.create(effect, caster, target).value();
79 1
        final int lost = computePointLost(caster, target, baseValue);
80 1
        final int dodge = baseValue - lost;
81
82 1
        if (dodge > 0) {
83 1
            fight.send(dodgeMessage(caster, target, dodge));
84
        }
85
86 1
        if (lost > 0) {
87 1
            target.buffs().add(new Buff(buffEffect(effect, lost), cast.action(), caster, target, hook));
88
        }
89
90 1
        return lost;
91
    }
92
93
    /**
94
     * The packet to send when the target dodge the point lost
95
     */
96
    protected abstract ActionEffect dodgeMessage(FighterData caster, FighterData target, int value);
97
98
    /**
99
     * Create the buff effect for the given point lost
100
     */
101
    private SpellEffect buffEffect(SpellEffect baseEffect, @NonNegative int pointLost) {
102 1
        return removalPointEffect == USE_SPELL_EFFECT
103 1
            ? BuffEffect.fixed(baseEffect, pointLost)
104 1
            : BuffEffect.withCustomEffect(baseEffect, removalPointEffect, pointLost)
105
        ;
106
    }
107
108
    /**
109
     * Compute how many points will be loose
110
     *
111
     * @param caster The spell caster
112
     * @param target The effect target
113
     * @param value The base buff value
114
     *
115
     * @return Number of lost points. Can be 0 if dodge all loose, and cannot exceed value parameter.
116
     */
117
    private int computePointLost(FighterData caster, FighterData target, @NonNegative int value) {
118 1
        final int maxPoints = target.characteristics().initial().get(this.characteristic);
119 1
        final int currentPoints = target.characteristics().get(this.characteristic);
120
121
        // Can't lose points anymore
122 1
        if (currentPoints <= 0) {
123 1
            return 0;
124
        }
125
126
        // The fighter has only boosted points (ignore division by 0)
127 1
        if (maxPoints <= 0) {
128 1
            return Math.min(currentPoints, value);
129
        }
130
131 1
        final int resistance = Math.max(target.characteristics().get(this.resistance), 1);
0 ignored issues
show
Comprehensibility introduced by
The variable resistanceshadows a field with the same name declared in line 50. Consider renaming it.
Loading history...
132 1
        final int wisdom = Math.max(caster.characteristics().get(Characteristic.WISDOM) / ComputedCharacteristics.POINT_RESISTANCE_FACTOR, 1);
133 1
        final int resistanceRate = 50 * wisdom / resistance;
134
135 1
        int lost = 0;
136
137
        // Compute point lost one by one
138 1
        for (int i = 0; i < value; ++i) {
139 1
            final int afterLost = currentPoints - lost;
140
141
            // All points are lost
142 1
            if (afterLost <= 0) {
143 1
                break;
144
            }
145
146 1
            int chance = resistanceRate * afterLost / maxPoints;
147
148
            // Bound chance between 10% and 90%
149
            // See: https://web.archive.org/web/20100111082721/http://devblog.dofus.com/fr/billets/46-nouvelle-formule-esquive-equilibrage-xelor.html
150 1
            chance = Math.min(chance, 90);
151 1
            chance = Math.max(chance, 10);
152
153 1
            if (random.bool(chance)) {
154 1
                ++lost;
155
            }
156
        }
157
158 1
        return lost;
159
    }
160
}
161