Passed
Push — master ( f51b57...4bee7d )
by Vincent
04:18 queued 11s
created

fr.quatrevieux.araknemu.game.monster.environment.MoveMonsters   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 92
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 48
dl 0
loc 92
ccs 35
cts 35
cp 1
rs 10
c 1
b 0
f 0
wmc 12

7 Methods

Rating   Name   Duplication   Size   Complexity  
A targetCell(ExplorationMapCell) 0 14 5
A toString() 0 3 1
A MoveMonsters(MonsterEnvironmentService,Duration,int,int) 0 5 1
A move(LivingMonsterGroupPosition) 0 17 2
A delay() 0 3 1
A execute(Logger) 0 7 1
A retry(ActivityService) 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.monster.environment;
21
22
import fr.arakne.utils.maps.CoordinateCell;
23
import fr.arakne.utils.maps.path.Decoder;
24
import fr.arakne.utils.maps.path.PathException;
25
import fr.arakne.utils.value.helper.RandomUtil;
26
import fr.quatrevieux.araknemu.game.activity.ActivityService;
27
import fr.quatrevieux.araknemu.game.activity.Task;
28
import fr.quatrevieux.araknemu.game.exploration.map.ExplorationMap;
29
import fr.quatrevieux.araknemu.game.exploration.map.cell.ExplorationMapCell;
30
import fr.quatrevieux.araknemu.game.monster.group.MonsterGroup;
31
import org.apache.logging.log4j.Logger;
32
33
import java.time.Duration;
34
import java.util.ArrayList;
35
import java.util.List;
36
import java.util.Optional;
37
38
/**
39
 * Task for random move monsters on exploration maps
40
 *
41
 * At most one group move per map per execution.
42
 * The move is performed if its randomly selected with moveChange and if the path is not too complex
43
 */
44
public final class MoveMonsters implements Task {
45
    private final MonsterEnvironmentService service;
46
    private final Duration delay;
47
    private final int moveChance;
48
    private final int maxDistance;
49
50 1
    private final RandomUtil random = new RandomUtil();
51
52
    /**
53
     * Initialise the move task
54
     *
55
     * @param service The environment server
56
     * @param delay  The period delay
57
     * @param moveChance Move chance for each groups, in percent
58
     * @param maxDistance The maximum move distance in cell count
59
     */
60 1
    public MoveMonsters(MonsterEnvironmentService service, Duration delay, int moveChance, int maxDistance) {
61 1
        this.service = service;
62 1
        this.delay = delay;
63 1
        this.moveChance = moveChance;
64 1
        this.maxDistance = maxDistance;
65 1
    }
66
67
    @Override
68
    public void execute(Logger logger) {
69 1
        service.groups()
70 1
            .filter(position -> !position.available().isEmpty())
71 1
            .filter(position -> !position.fixed())
72 1
            .filter(position -> random.bool(moveChance))
73 1
            .forEach(this::move)
74
        ;
75 1
    }
76
77
    @Override
78
    public Duration delay() {
79 1
        return delay;
80
    }
81
82
    @Override
83
    public boolean retry(ActivityService service) {
84 1
        return false;
85
    }
86
87
    @Override
88
    public String toString() {
89 1
        return "Move monsters";
90
    }
91
92
    /**
93
     * Try to move a group from the given position
94
     */
95
    private void move(LivingMonsterGroupPosition position) {
96 1
        final MonsterGroup group = random.of(position.available());
97
98 1
        targetCell(group.cell())
99 1
            .map(target -> {
100
                try {
101 1
                    return new Decoder<>(target.map())
102 1
                        .pathfinder()
103 1
                        .exploredCellLimit(50)
104 1
                        .findPath(group.cell(), target)
105
                    ;
106 1
                } catch (PathException e) {
107
                    // Ignore exception
108 1
                    return null;
109
                }
110
            })
111 1
            .ifPresent(group::move)
112
        ;
113 1
    }
114
115
    /**
116
     * Get a random target cell
117
     *
118
     * @param currentCell The current group cell
119
     *
120
     * @return The target cell, if available
121
     */
122
    private Optional<ExplorationMapCell> targetCell(ExplorationMapCell currentCell) {
123 1
        final CoordinateCell<ExplorationMapCell> currentCoordinates = new CoordinateCell<>(currentCell);
124 1
        final List<ExplorationMapCell> cells = new ArrayList<>();
125 1
        final ExplorationMap map = currentCell.map();
126
127 1
        for (int id = 0; id < map.size(); ++id) {
128 1
            final ExplorationMapCell cell = map.get(id);
129
130 1
            if (cell.free() && currentCoordinates.distance(new CoordinateCell<>(cell)) <= maxDistance) {
131 1
                cells.add(cell);
132
            }
133
        }
134
135 1
        return cells.isEmpty() ? Optional.empty() : Optional.of(random.of(cells));
136
    }
137
}
138