Scope   A
last analyzed

Complexity

Total Complexity 5

Size/Duplication

Total Lines 23
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 15
c 0
b 0
f 0
dl 0
loc 23
ccs 11
cts 11
cp 1
rs 10
wmc 5

2 Methods

Rating   Name   Duplication   Size   Complexity  
A provide(DropReward) 0 14 4
A Scope(List,int) 0 3 1
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-2020 Vincent Quatrevieux
18
 */
19
20
package fr.quatrevieux.araknemu.game.fight.ending.reward.drop.pvm.provider;
21
22
import fr.arakne.utils.value.helper.RandomUtil;
23
import fr.quatrevieux.araknemu.data.world.entity.monster.MonsterRewardItem;
24
import fr.quatrevieux.araknemu.game.fight.ending.EndFightResults;
25
import fr.quatrevieux.araknemu.game.fight.ending.reward.drop.DropReward;
26
import fr.quatrevieux.araknemu.game.fight.fighter.monster.MonsterFighter;
27
import fr.quatrevieux.araknemu.game.fight.fighter.operation.FighterOperation;
28
import org.apache.commons.lang3.tuple.MutablePair;
29
import org.apache.commons.lang3.tuple.Pair;
30
31
import java.util.ArrayList;
32
import java.util.Iterator;
33
import java.util.List;
34
35
/**
36
 * Provider for dropped items on a Pvm fight
37
 *
38
 * - get all item rewards from monsters
39
 * - filters items with a discernment rate higher than the team discernment
40
 * - randomize the dropped items
41
 * - distribute the same number of items between all winners
42
 * - for each items, remove one from the quantity, and test the rate
43
 *
44
 * Note: each winners can only have one occurrence of an item, per monster
45
 */
46
public final class PvmItemDropProvider implements DropRewardProvider {
47
    private final double rate;
48 1
    private final RandomUtil random = new RandomUtil();
49
50
    public PvmItemDropProvider() {
51 1
        this(1.0);
52 1
    }
53
54
    /**
55
     * @param rate Drop chance multiplier. Should be a positive value.
56
     */
57 1
    public PvmItemDropProvider(double rate) {
58 1
        this.rate = rate;
59 1
    }
60
61
    @Override
62
    public DropRewardProvider.Scope initialize(EndFightResults results) {
63 1
        final ExtractDrops operation = new ExtractDrops(
64 1
            results.winners().stream()
65 1
                .mapToInt(fighter -> fighter.characteristics().discernment())
66 1
                .sum()
67
        );
68
69 1
        results.applyToLoosers(operation);
70
71 1
        return new Scope(
72 1
            random.shuffle(operation.dropsAndQuantity),
73 1
            (int) Math.ceil((double) operation.dropsAndQuantity.size() / (double) results.winners().size())
74
        );
75
    }
76
77
    private class Scope implements DropRewardProvider.Scope {
0 ignored issues
show
Comprehensibility introduced by
Class or interface names should not shadow other classes or interfaces. In general, shadowing is a bad practice as it makes code harder to understand. Consider renaming this class.
Loading history...
78
        private final List<Pair<MonsterRewardItem, Integer>> dropsAndQuantity;
79
        private final int maxPerFighter;
80
81 1
        public Scope(List<Pair<MonsterRewardItem, Integer>> dropsAndQuantity, int maxPerFighter) {
82 1
            this.dropsAndQuantity = dropsAndQuantity;
83 1
            this.maxPerFighter = maxPerFighter;
84 1
        }
85
86
        @Override
87
        public void provide(DropReward reward) {
88 1
            final ItemDropIterator iterator = new ItemDropIterator(dropsAndQuantity);
89
90 1
            for (int count = maxPerFighter; count > 0 && iterator.hasNext(); --count) {
91 1
                final MonsterRewardItem drop = iterator.next();
92
93 1
                iterator.remove();
94
95 1
                if (random.decimal(100) > drop.rate() * rate) {
96 1
                    continue;
97
                }
98
99 1
                reward.addItem(drop.itemTemplateId());
100
            }
101 1
        }
102
    }
103
104
    private static class ItemDropIterator implements Iterator<MonsterRewardItem> {
105
        private final List<Pair<MonsterRewardItem, Integer>> dropsAndQuantity;
106
107 1
        private int current = -1;
108
109 1
        public ItemDropIterator(List<Pair<MonsterRewardItem, Integer>> dropsAndQuantity) {
110 1
            this.dropsAndQuantity = dropsAndQuantity;
111 1
        }
112
113
        @Override
114
        public boolean hasNext() {
115 1
            return dropsAndQuantity.size() > current + 1;
116
        }
117
118
        @Override
119
        public MonsterRewardItem next() {
0 ignored issues
show
Bug introduced by
Iteration beyond the the end of a collection should throw a NoSuchElementException.
Loading history...
120 1
            return dropsAndQuantity.get(++current).getKey();
121
        }
122
123
        @Override
124
        public void remove() {
125 1
            final Pair<MonsterRewardItem, Integer> currentPair = dropsAndQuantity.get(current);
126
127
            // Remove one from the quantity
128 1
            currentPair.setValue(currentPair.getValue() - 1);
129
130
            // Out of quantity : remove the item and move cursor to left
131 1
            if (currentPair.getValue() == 0) {
132 1
                dropsAndQuantity.remove(current--);
133
            }
134 1
        }
135
    }
136
137
    private static class ExtractDrops implements FighterOperation {
138
        private final int discernment;
139
140 1
        private final List<Pair<MonsterRewardItem, Integer>> dropsAndQuantity = new ArrayList<>();
141
142 1
        public ExtractDrops(int discernment) {
143 1
            this.discernment = discernment;
144 1
        }
145
146
        @Override
147
        public void onMonster(MonsterFighter fighter) {
148 1
            for (MonsterRewardItem item : fighter.reward().items()) {
149 1
                if (discernment >= item.discernment()) {
150 1
                    dropsAndQuantity.add(new MutablePair<>(item, item.quantity()));
151
                }
152 1
            }
153 1
        }
154
    }
155
}
156