Passed
Push — master ( 08cd0d...9eabdf )
by Vincent
07:15
created

fr.arakne.utils.maps.sight.BattlefieldSight   A

Complexity

Total Complexity 6

Size/Duplication

Total Lines 108
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 16
c 1
b 0
f 0
dl 0
loc 108
ccs 9
cts 9
cp 1
rs 10
wmc 6

6 Methods

Rating   Name   Duplication   Size   Complexity  
A from(C) 0 2 1
A BattlefieldSight(DofusMap) 0 3 1
A between(CoordinateCell,CoordinateCell) 0 2 1
A from(CoordinateCell) 0 2 1
A between(C,C) 0 2 1
A getCellByCoordinates(int,int) 0 3 1
1
/*
2
 * This file is part of ArakneUtils.
3
 *
4
 * ArakneUtils 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
 * ArakneUtils 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 ArakneUtils.  If not, see <https://www.gnu.org/licenses/>.
16
 *
17
 * Copyright (c) 2017-2020 Vincent Quatrevieux
18
 */
19
20
package fr.arakne.utils.maps.sight;
21
22
import fr.arakne.utils.maps.BattlefieldCell;
23
import fr.arakne.utils.maps.CoordinateCell;
24
import fr.arakne.utils.maps.DofusMap;
25
26
/**
27
 * Utility class for compute line of sights
28
 * Note: The used algorithm is not exactly same as the client's one, some differences can occurs
29
 *
30
 * Algorithm :
31
 * - Get coordinates of the two cells
32
 * - "draw" a line between the cells :
33
 * - Compute the vector between those cells
34
 * - Creates the function : Y = ySlope * X + yAtZero with
35
 * - For each X between the cells compute the related Y using the function
36
 * - Increments Y cell by cell to reach the computed Y
37
 * - Check the cell line of sight value
38
 * - If the sight is blocked, return false
39
 *
40
 * @param <C> The battlefield cell type
41
 */
42
public final class BattlefieldSight<C extends BattlefieldCell> {
43
    private final DofusMap<C> battlefield;
44
    private final int width; // store map width for optimisation
45
46 1
    public BattlefieldSight(DofusMap<C> battlefield) {
47 1
        this.battlefield = battlefield;
48 1
        this.width = battlefield.dimensions().width();
49 1
    }
50
51
    /**
52
     * Check the line of sight between those two cells
53
     *
54
     * This is equivalent to {@code sight.from(source).isFree(target)}
55
     *
56
     * Usage:
57
     * <pre>{@code
58
     * final BattlefieldSight<FightCell> sight = new BattlefieldSight<>(map);
59
     *
60
     * if (!sight.between(fighter.cell(), target.cell())) {
61
     *     throw new Exception("Target is no reachable");
62
     * }
63
     * }</pre>
64
     *
65
     * @param source The source cell
66
     * @param target The target cell
67
     *
68
     * @return true if target is not blocked
69
     *
70
     * @see CellSight#isFree(BattlefieldCell)
71
     */
72
    public boolean between(C source, C target) {
73 1
        return between(new CoordinateCell<>(source), new CoordinateCell<>(target));
74
    }
75
76
    /**
77
     * Check the line of sight between those two cells
78
     *
79
     * This is equivalent to {@code sight.from(source).isFree(target)}
80
     *
81
     * Usage:
82
     * <pre>{@code
83
     * final BattlefieldSight<FightCell> sight = new BattlefieldSight<>(map);
84
     * final CoordinateCell<FightCell> from = new CoordinateCell<>(fighter.cell());
85
     * final CoordinateCell<FightCell> to = new CoordinateCell<>(target.cell());
86
     *
87
     * if (!sight.between(from, to)) {
88
     *     throw new Exception("Target is no reachable");
89
     * }
90
     * }</pre>
91
     *
92
     * @param source The source cell
93
     * @param target The target cell
94
     *
95
     * @return true if target is not blocked
96
     *
97
     * @see CellSight#isFree(CoordinateCell)
98
     */
99
    public boolean between(CoordinateCell<C> source, CoordinateCell<C> target) {
100 1
        return from(source).isFree(target);
101
    }
102
103
    /**
104
     * Get the line of sight of a cell
105
     *
106
     * Usage:
107
     * <pre>{@code
108
     * final BattlefieldSight<FightCell> sight = new BattlefieldSight<>(map);
109
     * final CoordinateCell<FightCell> current = new CoordinateCell<>(fighter.cell());
110
     *
111
     * sight.from(current).to(target.cell()).forEachRemaining(cell -> {
112
     *     // Iterator on line of sight
113
     * });
114
     * }</pre>
115
     *
116
     * @param cell The cell to check
117
     *
118
     * @return The line of sight instance
119
     */
120
    public CellSight<C> from(CoordinateCell<C> cell) {
121 1
        return new CellSight<>(this, cell);
122
    }
123
124
    /**
125
     * Get the line of sight of a cell
126
     *
127
     * Usage:
128
     * <pre>{@code
129
     * final BattlefieldSight<FightCell> sight = new BattlefieldSight<>(map);
130
     *
131
     * sight.from(fighter.cell()).to(target.cell()).forEachRemaining(cell -> {
132
     *     // Iterator on line of sight
133
     * });
134
     * }</pre>
135
     *
136
     * @param cell The cell to check
137
     *
138
     * @return The line of sight instance
139
     */
140
    public CellSight<C> from(C cell) {
141 1
        return new CellSight<>(this, new CoordinateCell<>(cell));
142
    }
143
144
    /**
145
     * Get a cell by its coordinates
146
     */
147
    C getCellByCoordinates(int x, int y) {
148
        // https://github.com/Emudofus/Dofus/blob/1.29/ank/battlefield/utils/Pathfinding.as#L550
149 1
        return battlefield.get(x * width + y * (width - 1));
150
    }
151
}
152