Skip to content

Commit 721dbff

Browse files
author
Saurav Tripathi
committed
refactored code - added engine.js file, which contains logic common to AoE2 and RoR, similar to main.js
added more charge types
1 parent b265c39 commit 721dbff

File tree

10 files changed

+462
-721
lines changed

10 files changed

+462
-721
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.idea
2+
.vscode
23
bin
34
.directory
45
/scripts/venv

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<script defer src="js/svg.min.js"></script>
3030
<script defer src="js/techtree.js"></script>
3131
<script defer src="js/main.js"></script>
32+
<script defer src="js/engine.js"></script>
3233
</head>
3334

3435
<body>

js/engine.js

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
/**
2+
* The main.js file is supposed to contain logic specific to the website, like those modifying the HTML elements, and the event listeners.
3+
* To reduce size of the main.js file, this file includes the logic of the game engine-specific logic, logic for the 'Caret' class, or any other simple logic.
4+
*/
5+
6+
const TYPES = Object.freeze({
7+
'BUILDING': {colour: '#ff0000', type: 'BUILDING', name: 'Building'},
8+
'UNIT': {colour: '#ff0000', type: 'UNIT', name: 'Unit'},
9+
'UNIQUEUNIT': {colour: '#703b7a', type: 'UNIQUEUNIT', name: 'Unique Unit'},
10+
'TECHNOLOGY': {colour: '#2c5729', type: 'TECHNOLOGY', name: 'Technology'}
11+
});
12+
13+
const PREFIX = Object.freeze({
14+
'BUILDING': 'building_',
15+
'UNIT': 'unit_',
16+
'UNIQUEUNIT': 'unit_',
17+
'TECHNOLOGY': 'tech_'
18+
});
19+
20+
const unitClasses = {
21+
0: 'Wonders',
22+
1: 'Infantry',
23+
2: 'Heavy Warships',
24+
3: 'Base Pierce',
25+
4: 'Base Melee',
26+
5: 'Elephants',
27+
6: 'Unused',
28+
7: 'Unused',
29+
8: '<abbr title="except Camels">Mounted Units</abbr>',
30+
9: 'Unused',
31+
10: 'Unused',
32+
11: 'All Buildings',
33+
12: 'Unused',
34+
13: '<abbr title="except Castles and Kreposts">Stone Defense & Harbors</abbr>',
35+
14: 'Wolves etc.',
36+
15: 'All Archers',
37+
16: '<abbr title="except Fishing Ships">Ships</abbr>',
38+
17: 'High Pierce Armor Siege Units',
39+
18: 'Trees',
40+
19: 'Unique Units',
41+
20: 'Siege Units',
42+
21: '<abbr title="All buildings except Wonders">Standard Buildings</abbr>',
43+
22: 'Walls & Gates',
44+
23: 'Gunpowder Units',
45+
24: 'Boars etc.',
46+
25: 'Monks',
47+
26: 'Castles & Kreposts',
48+
27: 'Spearmen',
49+
28: 'Mounted Archers',
50+
29: 'Shock Infantry',
51+
30: 'Camels',
52+
31: '<abbr title="Armor-ignoring melee attack against units, but not against buildings">Unblockable Melee</abbr>',
53+
32: 'Condottieri',
54+
33: '<abbr title="no unit has this armor class">Gunpowder units secondary projectile attack</abbr>',
55+
34: 'Fishing Ships',
56+
35: 'Mamelukes',
57+
36: 'Heroes & Kings',
58+
37: 'Heavy Siege',
59+
38: 'Skirmishers',
60+
39: 'Cavalry Resistance',
61+
40: 'Houses',
62+
60: 'Antiquity Galleys and Catapult Ships'
63+
};
64+
65+
const animation_duration = 50;
66+
67+
class Caret {
68+
constructor(type, name, id, colour = null) {
69+
this.type = type;
70+
this.name = name;
71+
this.id = PREFIX[type.type] + formatId(id);
72+
this.width = 100;
73+
this.height = 100;
74+
this.x = 0;
75+
this.y = 0;
76+
this.colour = colour;
77+
}
78+
79+
isBuilding() {
80+
return this.type === TYPES.BUILDING;
81+
}
82+
}
83+
84+
function imagePrefix(name) {
85+
return name.replace('_copy', '')
86+
.replace('building_', 'Buildings/')
87+
.replace('unit_', 'Units/')
88+
.replace('tech_', 'Techs/');
89+
}
90+
91+
function cost(cost_object) {
92+
let value = '';
93+
if (cost_object.Food) {
94+
value += `<span class="cost food" title="${cost_object.Food} Food">${cost_object.Food}</span>`;
95+
}
96+
if (cost_object.Wood) {
97+
value += `<span class="cost wood" title="${cost_object.Wood} Wood">${cost_object.Wood}</span>`;
98+
}
99+
if (cost_object.Gold) {
100+
value += `<span class="cost gold" title="${cost_object.Gold} Gold">${cost_object.Gold}</span>`;
101+
}
102+
if (cost_object.Stone) {
103+
value += `<span class="cost stone" title="${cost_object.Stone} Stone">${cost_object.Stone}</span>`;
104+
}
105+
if (value === '') return 'free';
106+
return value;
107+
}
108+
109+
function formatId(string) {
110+
return string.toString().replace(/\s/g, '_').replace(/\//g, '_').toLowerCase();
111+
}
112+
113+
function checkIdUnique(tree) {
114+
let ids = new Set();
115+
for (let lane of tree.lanes) {
116+
for (let r of Object.keys(lane.rows)) {
117+
for (let caret of lane.rows[r]) {
118+
if (ids.has(caret.id)) {
119+
console.error('ID ' + caret.id + ' is not unique!');
120+
}
121+
ids.add(caret.id);
122+
}
123+
}
124+
}
125+
}
126+
127+
function getColourForNodeType(nodeType) {
128+
switch (nodeType) {
129+
case 'BuildingTech':
130+
case 'BuildingNonTech':
131+
return '#b54e18';
132+
case 'RegionalBuilding':
133+
return '#cc4422';
134+
case 'UniqueBuilding':
135+
return '#d43652';
136+
case 'Unit':
137+
case 'UnitUpgrade':
138+
return '#00739c';
139+
case 'RegionalUnit':
140+
return '#515ae3';
141+
case 'UniqueUnit':
142+
return '#703b7a';
143+
case 'Technology':
144+
return '#397139';
145+
default:
146+
return '#ff0000';
147+
}
148+
}
149+
150+
function chargeText(type) {
151+
switch (type) {
152+
case 1: return 'Charge Attack:&nbsp;';
153+
case 2: return 'Charge Hit Points:&nbsp;';
154+
case 3: return 'Charged Area Attack:&nbsp;';
155+
case 4: return 'Projectile Dodging:&nbsp;';
156+
case 5: return 'Melee Attack Blocking:&nbsp;';
157+
case 6: return 'Charged Ranged Attack (type 1):&nbsp;';
158+
case 7: return 'Charged Ranged Attack (type 2):&nbsp;';
159+
default: return 'Unknown Charge:&nbsp;';
160+
}
161+
}
162+
163+
function getEntityType(type) {
164+
switch (type) {
165+
case 'TECHNOLOGY':
166+
return 'techs';
167+
case 'UNIT':
168+
case 'UNIQUEUNIT':
169+
return 'units';
170+
}
171+
return 'buildings';
172+
}
173+
174+
/**
175+
* @param {number} trait
176+
* @return {number[]}
177+
*/
178+
function splitTrait(trait) {
179+
const traits = [];
180+
for (let x of [1, 2, 4, 8, 16, 32, 64, 128]) {
181+
if ((trait & x) > 0) {
182+
traits.push(x);
183+
}
184+
}
185+
return traits;
186+
}
187+
188+
/**
189+
* @param {number} traitId
190+
* @param {number} traitPiece
191+
* @return {string}
192+
*/
193+
function getTraitDefinition(traitId, traitPiece) {
194+
switch (traitId) {
195+
case 1: return 'Garrison Unit';
196+
case 2: return 'Ship Unit';
197+
case 4: return 'Builds:&nbsp;' + data.strings[data.data['buildings'][traitPiece]['LanguageNameId']];
198+
case 8: return 'Transforms into:&nbsp;' + data.strings[(data.data['buildings'][traitPiece] || data.data['units'][traitPiece])['LanguageNameId']];
199+
case 16: return '<abbr title="has auto-scout behaviour">Scout Unit</abbr>';
200+
default: return 'Unknown Trait:&nbsp;' + traitId;
201+
}
202+
}
203+
204+
/**
205+
* @param {number} trait
206+
* @param {string} traitPiece
207+
* @return {*[]|boolean}
208+
*/
209+
function traitsIfDefined(trait, traitPiece) {
210+
let traitdescriptions = [];
211+
if (trait === undefined || trait === 0) {
212+
return false;
213+
}
214+
const traits = splitTrait(trait);
215+
for (let singleTrait of traits) {
216+
traitdescriptions.push(getTraitDefinition(singleTrait, traitPiece));
217+
}
218+
return traitdescriptions;
219+
}
220+
221+
function getName(id, itemtype) {
222+
// ToDo handle unique stuff properly
223+
if (id.toString().startsWith('UNIQUE')) {
224+
return id;
225+
}
226+
try {
227+
const languageNameId = data['data'][itemtype][id]['LanguageNameId'];
228+
return data['strings'][languageNameId];
229+
} catch {
230+
console.log(id, itemtype);
231+
}
232+
}
233+
234+
function getColour(id, itemtype) {
235+
let nodeType = data['data']?.['node_types']?.[itemtype]?.[id];
236+
if (!nodeType) {
237+
nodeType = itemtype === 'units' ? 'Unit' : 'BuildingTech';
238+
}
239+
return getColourForNodeType(nodeType);
240+
}
241+
242+
function building(id) {
243+
return new Caret(TYPES.BUILDING, getName(id, 'buildings'), id, getColour(id, 'buildings'));
244+
}
245+
246+
function unit(id) {
247+
return new Caret(TYPES.UNIT, getName(id, 'units'), id, getColour(id, 'units'));
248+
}
249+
250+
function tech(id) {
251+
return new Caret(TYPES.TECHNOLOGY, getName(id, 'techs'), id);
252+
}
253+
254+
function u(unit) {
255+
return 'unit_' + formatId(unit);
256+
}
257+
258+
function b(building) {
259+
return 'building_' + formatId(building);
260+
}
261+
262+
function t(tech) {
263+
return 'tech_' + formatId(tech);
264+
}
265+
266+
function formatName(originalname) {
267+
if (!originalname) return "";
268+
let name = originalname.toString().replace(/<br>/g, '\n').replace(/\n+/g, '\n');
269+
const items = name.split('\n');
270+
for (let i = 0; i < items.length; i++) {
271+
const item = items[i];
272+
if (items[i].length > 10) {
273+
let space = item.indexOf(' ');
274+
if (space !== -1) {
275+
items[i] = item.slice(0, space) + '\n' + item.slice(space + 1);
276+
let alternativeSpace = space + 1 + item.slice(space + 1).indexOf(' ');
277+
if (alternativeSpace !== -1) {
278+
if (Math.abs((item.length / 2) - alternativeSpace) < Math.abs((item.length / 2) - space)) {
279+
items[i] = item.slice(0, alternativeSpace) + '\n' + item.slice(alternativeSpace + 1);
280+
}
281+
}
282+
} else {
283+
let hyphen = item.indexOf('-');
284+
if (hyphen !== -1) {
285+
items[i] = item.slice(0, hyphen) + '-\n' + item.slice(hyphen + 1);
286+
let alternativeHyphen = hyphen + 1 + item.slice(hyphen + 1).indexOf('-');
287+
if (alternativeHyphen !== -1) {
288+
if (Math.abs((item.length / 2) - alternativeHyphen) < Math.abs((item.length / 2) - hyphen)) {
289+
items[i] = item.slice(0, alternativeHyphen) + '-\n' + item.slice(alternativeHyphen + 1);
290+
}
291+
}
292+
}
293+
}
294+
}
295+
}
296+
return items.join('\n');
297+
}
298+
299+
function getConnectionPoints(tree) {
300+
let points = new Map();
301+
for (let lane of tree.lanes) {
302+
for (let r of Object.keys(lane.rows)) {
303+
for (let caret of lane.rows[r]) {
304+
points.set(caret.id, {
305+
x: caret.x + (caret.width / 2),
306+
y: caret.y + (caret.height / 2)
307+
});
308+
}
309+
}
310+
}
311+
return points;
312+
}

0 commit comments

Comments
 (0)