/
EntityData.java
313 lines (253 loc) · 9.73 KB
/
EntityData.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
package com.fundynamic.d2tm.game.types;
import com.fundynamic.d2tm.game.entities.EntityType;
import com.fundynamic.d2tm.game.entities.entitiesdata.EntitiesData;
import com.fundynamic.d2tm.game.entities.entitiesdata.EntitiesDataReader;
import com.fundynamic.d2tm.game.entities.entitybuilders.EntityBuilderType;
import com.fundynamic.d2tm.math.Coordinate;
import com.fundynamic.d2tm.math.MapCoordinate;
import com.fundynamic.d2tm.math.Vector2D;
import com.fundynamic.d2tm.utils.StringUtils;
import org.newdawn.slick.Image;
import java.util.ArrayList;
import java.util.List;
import static com.fundynamic.d2tm.game.map.Cell.TILE_SIZE;
/**
* <h1>Overview</h1>
* This is an object representation of an Entity. The {@link EntitiesData} class contains
* all objects after reading the rules.ini file. The interpretation of the file and the construction of an {@link EntityData} class
* is done by the {@link EntitiesDataReader}.
*
* <h2>Structures</h2>
* <p>Example piece of rules.ini file for structures:</p>
* <pre>
* [STRUCTURES]
*
* [STRUCTURES/CONSTYARD]
* image=structures/2x2_constyard.png
* hitPoints=2000
* width=64
* height=64
* sight=5
* explosion=BOOM
*
* </pre>
* <p>The structure has a reference to EXPLOSIONS which is implemented by (#{@link com.fundynamic.d2tm.game.entities.particle.Particle}</p>
*/
public class EntityData {
public static final String UNKNOWN = "UNKNOWN";
/**
* the name used in the INI file (ie [QUAD] without [])
*/
public String name;
// Kind of entity it reflects
public EntityType type;
// Build related
public EntityBuilderType entityBuilderType = EntityBuilderType.NONE;
public float buildTimeInSeconds = 1.0F;
public float buildRange = 0F;
public int buildCost = -1; // cost to build this
public Image buildIcon; // build icon
public String buildList = "";
public Image image; // base image
public Image barrelImage; // barrelImage (top image)
private int facings;
private int width; // in pixels
private int height; // in pixels
private int widthInCells; // in cells, derived from pixels
private int heightInCells; // in cells, derived from pixels
public int maxAscensionHeight; // in pixels, how high a projectile can ascend when 'launched'
public float startToDescendPercentage; // normalised value (between 0 and 1.0), when should descend be initiated?
public float maxAscensionAtFlightPercentage; // normalised value (between 0 and 1.0), when should the projectile be at maxAscensionHeight during flight?
public int sight;
public float moveSpeed; // the speed a unit moves: value is pixels in seconds.
public float turnSpeed; // the speed a unit turns: value is facing angles in seconds. < 1 means the value is times per second
public float turnSpeedCannon; // the speed a unit's barrel turns: value is facing angles in seconds. < 1 means the value is times per second
public float attackRate; // the speed a unit attacks: < 1 means the value is times per second
public float attackRange; // the range for a unit to attack in pixels
public String weaponId = UNKNOWN;
public int damage;
public int hitPoints; // initial hitPoints when spawned
public String explosionId = UNKNOWN;
public float animationSpeed; // in frames per second, for animating
public String key; // key used in HashMap
public boolean recolor; // if 'true' then the particle will be recolored (into team color) before spawned
// for turning
private float chop = -1f;
private float halfChop = -1f;
public boolean isHarvester;
public SoundData soundData = null; // for playing sound if required
public EntityData() {
}
public EntityData(int width, int height, int sight) {
setWidth(width);
setHeight(height);
this.sight = sight;
}
public Image getFirstImage() {
return image.getSubImage(0, 0, width, height);
}
public void setWidth(int width) {
this.width = width;
widthInCells = (int) Math.ceil((float) width / TILE_SIZE);
}
public void setHeight(int height) {
this.height = height;
heightInCells = (int) Math.ceil((float) height / TILE_SIZE);
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int getWidthInCells() {
return widthInCells;
}
public int getHeightInCells() {
return heightInCells;
}
@Override
public String toString() {
return "EntityData{" +
"chop=" + chop +
", halfChop=" + halfChop +
", type=" + type +
", image=" + image +
", barrelImage=" + barrelImage +
", width=" + width +
", height=" + height +
", widthInCells=" + widthInCells +
", heightInCells=" + heightInCells +
", sight=" + sight +
", moveSpeed=" + moveSpeed +
", turnSpeed=" + turnSpeed +
", turnSpeedCannon=" + turnSpeedCannon +
", attackRate=" + attackRate +
", attackRange=" + attackRange +
", hitPoints=" + hitPoints +
", facings=" + facings +
", damage=" + damage +
", explosionId='" + explosionId + '\'' +
", weaponId='" + weaponId + '\'' +
", animationSpeed=" + animationSpeed +
", key='" + key + '\'' +
", recolor=" + recolor +
'}';
}
public boolean hasFacings() {
return facings > 0;
}
public void setFacingsAndCalculateChops(int facings) {
this.facings = facings;
this.chop = 360F / facings;
this.halfChop = chop / 2F;
}
public float getChop() {
return chop;
}
public float getHalfChop() {
return halfChop;
}
public int getFacings() {
return facings;
}
public boolean hasExplosionId() {
return !UNKNOWN.equals(explosionId);
}
public boolean hasWeaponId() {
return !UNKNOWN.equals(weaponId);
}
public boolean hasSound() {
return soundData != null;
}
public String getWeaponIdKey() {
return constructKey(EntityType.PROJECTILE, weaponId);
}
public String getExplosionIdKey() {
return constructKey(EntityType.PARTICLE, explosionId);
}
public static String constructKey(EntityType entityType, String id) {
return entityType.toString() + "-" + id;
}
/**
* This takes time into account as well. This makes the distance of moveSpeed equivalent to 1 second.
*
* @param deltaInSeconds
* @return
*/
public float getRelativeMoveSpeed(float deltaInSeconds) {
return moveSpeed * deltaInSeconds;
}
/**
* See @link getRelativeMoveSpeed
* @param deltaInSeconds
* @return
*/
public float getRelativeTurnSpeed(float deltaInSeconds) {
return getRelativeSpeed(turnSpeed, deltaInSeconds);
}
public static float getRelativeSpeed(float speed, float deltaInSeconds) {
return speed * deltaInSeconds;
}
public float getRelativeAttackRate(float deltaInSeconds) {
return getRelativeSpeed(attackRate, deltaInSeconds);
}
public boolean isTypeStructure() {
return EntityType.STRUCTURE.equals(this.type);
}
public boolean isTypeUnit() {
return EntityType.UNIT.equals(this.type);
}
public boolean isTypeParticle() {
return EntityType.PARTICLE.equals(this.type);
}
public boolean isTypeSuperPower() {
return EntityType.SUPERPOWER.equals(this.type);
}
public boolean isTypeProjectile() {
return EntityType.PROJECTILE.equals(this.type);
}
/**
* Given a topLeftX and topLeftY coordinate, calculate all cells that are being occupied by this
* entity and return that as a list of coordinates. These coordinates are top-left coordinates of cells.
*
* @return
*/
public List<MapCoordinate> getAllCellsAsCoordinates(Coordinate coordinate) {
List<MapCoordinate> result = new ArrayList<>(widthInCells * heightInCells);
for (int x = 0; x < widthInCells; x++) {
for (int y = 0; y < heightInCells; y++) {
int vecX = coordinate.getXAsInt() + (x * TILE_SIZE);
int vecY = coordinate.getYAsInt() + (y * TILE_SIZE);
result.add(Coordinate.create(vecX, vecY).toMapCoordinate());
}
}
return result;
}
/**
* Given a topLeftX and topLeftY coordinate, calculate all cells that are being occupied by this
* entity and return that as a list of coordinates.
*
* The coordinates are corrected to be centered within a cell.
*
* @return
*/
public List<Coordinate> getAllCellsAsCenteredCoordinates(Coordinate coordinate) {
List<MapCoordinate> result = getAllCellsAsCoordinates(coordinate);
List<Coordinate> centered = new ArrayList<>(result.size());
Vector2D halfCell = Vector2D.create(TILE_SIZE / 2, TILE_SIZE / 2);
for (MapCoordinate resultCoordinate : result) {
centered.add(resultCoordinate.toCoordinate().add(halfCell));
}
return centered;
}
public Vector2D getHalfSize() {
return Vector2D.create(width / 2, height / 2);
}
public Vector2D getSize() {
return Vector2D.create(width, height);
}
public List<String> getEntityDataKeysToBuild() {
return StringUtils.splitLenientToList(buildList, ",");
}
}