-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgarden.js
481 lines (404 loc) · 16.1 KB
/
garden.js
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
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
// STATIC_DATA, game_data
let sess = {
frame_rect: undefined,
cvs_width: undefined,
cvs_height: undefined,
transform_x: 0,
transform_y: 0,
transform_scale: 1,
items_highlight_tiles: {},
cvs_images: [],
running_animations: [], //{starttime: undefined, type: undefined, x: undefined, y: undefined, color: undefined}
dragging: false,
current_action: "lens",
hovered_tile: undefined,
current_season: 1,
vert_tile_dist: 50,
horz_tile_dist: 60,
tile_size: 30, // not bigger than vert_tile_dist
}
const buildItemsHighlightTiles = () => {
// create array for every shop item, populate if possible
sess.items_highlight_tiles["lens"] = [];
sess.items_highlight_tiles["spade"] = []; // TODO
sess.items_highlight_tiles["sickle"] = [];
sess.items_highlight_tiles["seedcollector"] = game_data.seeds_collected || [];
for (let building of STATIC_DATA.buildings) {
sess.items_highlight_tiles[building.name] = game_data.builts.filter((b,i,a)=>b.name == building.name).map(b=>tgToCvs([b.locx, b.locy]));
}
for (let sect of ["boosters", "flowers"]) {
for (let item of STATIC_DATA[sect]) {
sess.items_highlight_tiles[item.name] = game_data.tiles.filter((t,i,a)=>t.boosters.includes(item.name) || t.flowername == item.name).map(t=>tgToCvs([t.locx, t.locy]));
}
}
}
const gatherCvsImages = () => {
for (let flower of STATIC_DATA.flowers) {
sess.cvs_images[flower.name] = document.getElementById("shelf-"+flower.name+"-img"); //TODO solve cleaner with: new Image()
//TODO increase canvas resolution, possibly make user adjustable
//todo make border around plantable area (forest or something)
}
}
const setCanvasSize = () => {
const cvs_res = 1; //canvas pixel per style pixel
const cont_style = window.getComputedStyle(canvas_cont);
sess.cvs_width = parseInt(parseFloat(cont_style.width)*cvs_res);
sess.cvs_height = parseInt(parseFloat(cont_style.height)*cvs_res);
for (var cvs of cvs_list) {
cvs.width = sess.cvs_width;
cvs.height = sess.cvs_height;
}
}
const navTo = (id) => {
const el = document.getElementById(id);
shop.scroll({
top: el.offsetTop-50,
left: 0,
behavior: 'smooth'
});
}
const alterRadios = () => {
const top = shop.scrollTop+150;
if (top < document.getElementById("boosters-header").offsetTop) {
document.getElementById("tools-radio").checked = true;
} else if (top < document.getElementById("flowers-header").offsetTop) {
document.getElementById("boosters-radio").checked = true;
} else if (top < document.getElementById("buildings-header").offsetTop) {
document.getElementById("flowers-radio").checked = true;
} else {
document.getElementById("buildings-radio").checked = true;
}
}
const skipToSeason = (evt) => {
const skipped_time = undefined;
}
const updateDatabase = (table_name, rows=[], del=false) => {
fetch('/localhost/sqlgarden/test.php', {
method: 'POST',
headers: {ContentType: 'application/json'},
body: JSON.stringify({
tablename: table_name,
rows: rows,
del: del,
gamename: game_data["name"]
})
}
)
.then(response => response.json())
.then(responseData => {console.log(responseData)});
}
const addBuildingBoosters = () => {
}
const randomDecision = () => {
}
const buildScene = () => {
}
const changeSeason = (to_season) => {
changeBackdrop(to_season);
// update overall probabilities...and stuff
}
const drawBackdrop = () => {
// full redraw of backdrop
const res = 41; // backdrop 500x500 ////TODO 81 is the minimum image size that can be drawn on css size*2; 41 on css size *1 canvas
ctx = ctx_list[0]; // backdrop context
let img = document.getElementById("backdrop-season-"+sess.current_season);
let x_num = Math.ceil((sess.frame_rect[2]) / res) + 1;
let y_num = Math.ceil((sess.frame_rect[3]) / res) + 1;
let x_offset = Math.floor(sess.frame_rect[0] / res);
let y_offset = Math.floor(sess.frame_rect[1] / res);
for (let i = 0; i < x_num; i++) {
for (let j = 0; j < y_num; j++) {
ctx.drawImage(img, (i + x_offset) * res, (j + y_offset) * res);
}
}
}
let topleft;
const drawScene = (tiles=undefined) => {
// full redraw of game_data["tiles"]
ctx = ctx_list[1] // scene context
if (!tiles) {
ctx.clearRect(...sess.frame_rect);
}
for (let tile of tiles || game_data.tiles) {
topleft = [-sess.tile_size/2 + tile.locx * sess.horz_tile_dist + tile.locy*(sess.horz_tile_dist/2), -sess.tile_size/2 + tile.locy * sess.vert_tile_dist];
if (tiles) {
ctx.clearRect(...topleft, ...topleft.map(v=>v+tile_size));
}
ctx.drawImage(sess.cvs_images[tile.flowername], ...topleft);
}
ctx.drawImage(document.getElementById("backdrop-season-1"), 0, 0);
}
const animationLoop = (timestamp) => {
// draw all current animations
ctx = ctx_list[2] // animations context
ctx.clearRect(...sess.frame_rect);
for (let a of sess.running_animations) {
ctx.beginPath();
ctx.fillStyle = "rgba(255, 255, 255, 0.3)";
switch (a.type) {
case "item-highlight":
ctx.arc(a.x, a.y, sess.tile_size/2, 0, 2 * Math.PI);
break;
case "tile-hover":
ctx.arc(a.x, a.y, sess.tile_size/2, 0, 2 * Math.PI);
break;
case "building-hover":
ctx.arc(a.x, a.y, sess.tile_size/2*3, 0, 2 * Math.PI);
break;
}
ctx.fill();
}
window.requestAnimationFrame(animationLoop);
}
let elapsed_time, elapsed_years, elapsed_seasons, year_percentage, prevTimestamp;
const ms_per_season = 120000; // 2 mins per season
const ms_per_year = ms_per_season*4;
const game_updates_per_season = 100;
const ms_per_update = ms_per_season / game_updates_per_season;
const getSeasonParams = () => {
return undefined
}
let curr_gtime, prev_gtime, next_update_time;
const gameLoop = (timestamp) => {
// check if update needed
curr_gtime = timestamp + game_data.elapsedtime;
next_update_time = Math.ceil(prev_gtime / ms_per_update) * ms_per_update;
if (prev_gtime < next_update_time && next_update_time <= curr_gtime) {
// update season bar
year_percentage = (curr_gtime % ms_per_year)*100/ms_per_year;
marker.style.left = year_percentage.toString()+"%";
// get global season parameters
let season_params = getSeasonParams();
let updated, updated_tiles;
for (let tile of game_data.tiles) {
updated = false;
// update boosters (remove expired)
// llalalalalalal: wakeupprob
// check for flower
if (tile.flowername) {
// check for seeding
if (Math.floor(Math.random() * tile.invseedingprob) == 1) {
// execute seeding
}
// check for germing
if (Math.floor(Math.random() * tile.invgermingprob) == 1) {
// execute germing
}
// check for bugs
if (Math.floor(Math.random() * tile.invbugsprob) == 1) {
// execute bugs
}
// check for snails
if (Math.floor(Math.random() * tile.invsnailsprob) == 1) {
// execute snails
}
// check for death
if (Math.floor(Math.random() * tile.invdeathprob) == 1) {
// execute death
}
}
if (updated) {
updated_tiles.push(tile)
}
}
drawScene(updated_tiles);
}
elapsed_years = Math.floor(elapsed_time / ms_per_year);
elapsed_seasons = Math.floor(elapsed_time / (ms_per_year/4));
//sess.current_season = elapsed_seasons % 4;
prev_gtime = curr_gtime;
window.requestAnimationFrame(gameLoop);
}
const updateTransform = () => {
console.log("transform");
for (let ctx of ctx_list) {
ctx.resetTransform();
ctx.translate(sess.transform_x, sess.transform_y);
ctx.scale(sess.transform_scale, sess.transform_scale);
sess.frame_rect = [- sess.transform_x/sess.transform_scale,
- sess.transform_y/sess.transform_scale,
sess.cvs_width/sess.transform_scale,
sess.cvs_height/sess.transform_scale
]
}
drawBackdrop();
drawScene();
// animations redraw themselves
}
const updateMoney = (amount) => {
game_data.money += amount;
document.getElementById("money-display").innerHTML = game_data.money;
// update state of shop items
let items = document.getElementsByClassName("use-btn")
for (let i of items) {
if (i.dataset.price<=game_data.money) {
i.classList.add("affordable");
} else {
i.classList.remove("affordable");
}
}
}
const handleMouseClick = (evt) => {
if (sess.hovered_tile) {
// handle clicks on tiles regarding current action
switch (sess.current_action) {
case "lens":
// fill popup with data
document.getElementById("tile-info").parentElement.classList.add("opened")
// open popup
break;
case "spade":
break;
}
}
}
const handleMouseMove = (evt) => {
if (sess.dragging){
// handle drag
sess.transform_x += evt.offsetX - prevPoint[0];
sess.transform_y += evt.offsetY - prevPoint[1];
prevPoint=[evt.offsetX, evt.offsetY];
updateTransform();
} else {
// handle hover effects
let cursor_on_cvs = [(evt.offsetX-sess.transform_x)/sess.transform_scale,
(evt.offsetY-sess.transform_y)/sess.transform_scale];
let next_on_tg = []; // tg = tile-grid
next_on_tg[1] = Math.round(cursor_on_cvs[1]/sess.vert_tile_dist);
next_on_tg[0] = Math.round(cursor_on_cvs[0]/sess.horz_tile_dist - next_on_tg[1]/2);
let next_on_cvs = tgToCvs(next_on_tg);
// Math.pow(next_on_cvs[0]-cursor_on_cvs[0], 2) + Math.pow(next_on_cvs[1]-cursor_on_cvs[1], 2) <= Math.pow(sess.tile_size/2, 2)
// if hovering a tile
sess.hovered_tile = game_data.tiles.find(t => t.locx == next_on_tg[0] && t.locy == next_on_tg[1]);
let hover_type = undefined;
if (sess.hovered_tile) {
// set hover effect based on current action
if (sess.current_action.includes("lens")) {
hover_type = "tile-hover";
console.log("hov");
} else if (sess.current_action.includes("flower")) {
if (!sess.hovered_tile.flowername) {
hover_type = "tile-hover";
}
} else if (sess.current_action.includes("shelf")) {
if (!sess.hovered_tile.flowername) {
hover_type = "tile-hover";
}
} else if (sess.current_action.includes("booster")) {
if (!sess.hovered_tile.boosters.includes(sess.current_action.replace("booster-", ""))) {
hover_type = "tile-hover";
}
} else if (sess.current_action.includes("building")) {
if (!sess.hovered_tile.boosters.includes(sess.current_action.replace("building-", ""))) {
if (!game_data.tiles.filter(t=>[[1,0],[0,1],[-1,1],[-1,0],[0,-1],[1,-1]].some(loc=> t.locx == next_on_tg[0]+loc[0] && t.locy == next_on_tg[1]+loc[1]).some(t=>t.boosters.includes(sess.current_action.replace("building-", ""))))) {
hover_type = "building-hover";
}
}
} else if (sess.current_action.includes("sickle")) {
if (sess.hovered_tile.flowername) {
hover_type = "tile-hover";
}
} else if (sess.current_action.includes("seedcoll")) {
if (sess.hovered_tile.seeding) {
hover_type = "tile-hover";
}
} else if (sess.current_action.includes("spade")) {
// hovering the diggable tiles
if (sess.items_highlight_tiles["spade"].find(loc => loc[0] == next_on_tg[0] && loc[1] == next_on_tg[1])) {
hover_type = "tile-hover";
}
}
}
// remove any hovering animations NONONONONONONONON
let i = sess.running_animations.findIndex(a => a.type.includes("tile-hover"));
if (i>-1) {sess.running_animations.splice(i, 1);}
if (!hover_type) {
sess.hovered_tile = undefined;
} else {
sess.running_animations.push({starttime: undefined, type: hover_type, x: next_on_cvs[0], y: next_on_cvs[1], color: "white"});
}
}
}
const tgToCvs = (tg) => {
return [tg[0]*sess.horz_tile_dist + tg[1]*(sess.horz_tile_dist/2), tg[1]*sess.vert_tile_dist]
}
const toggleItemHighlights = (item_name) => {
if (item_name) {
for (let loc of sess.items_highlight_tiles[item_name]) {
sess.running_animations.push({starttime: undefined, type: "item-highlight", x: loc[0], y: loc[1], color: "white"})
}
} else {
// remove all highlight animations
sess.running_animations = sess.running_animations.filter(a=>!a.type.includes("item-highlight"));
}
}
const changeCurrentActionTo = (to) => {
// to can be "shelf-something" or "flower-plant-something" or "booster-something"
if (!sess.current_action == "lens") {
for (let el of document.getElementsByClassName("active-item")) {
// only one
el.classList.remove("active-item");
}
}
sess.current_action = to;
ui_cvs.style = "--cursorloc: url(images/cursors/"+to+".png);"
if (!to == "lens") {
for (let el of document.getElementsById(to+"-item")) {
el.classList.add("active-item");
}
}
}
// declare element objects globally
let canvas_cont, marker, shop_pane, ui_cvs, cvs_list;
let ctx_list = [];
window.onload = () => {
document.body.style.mozUserSelect = document.body.style.webkitUserSelect = document.body.style.userSelect = 'none';
// get element objects
canvas_cont = document.getElementById("canvas-container");
marker = document.getElementById("season-marker");
shop = document.getElementById("shop");
ui_cvs = document.getElementById("ui-cvs");
cvs_list = document.getElementsByTagName("canvas");
for (let cvs of cvs_list) {
let ctx = cvs.getContext("2d");
ctx.imageSmoothingEnabled = false;
ctx_list.push(ctx);
}
sess.transform_x = parseInt(window.getComputedStyle(canvas_cont).width)/2;
sess.transform_y = parseInt(window.getComputedStyle(canvas_cont).height)/2;
sess.transform_scale = 1;
ui_cvs.onmousedown = (evt) => {sess.dragging=true; prevPoint=[evt.offsetX, evt.offsetY]};
ui_cvs.onmousemove = handleMouseMove;
ui_cvs.onclick = handleMouseClick;
ui_cvs.onmouseup = () => {sess.dragging = false;};
ui_cvs.onwheel = (evt) => {
d = -evt.deltaY * 10;
let factor = Math.pow(1.001, d);
sess.transform_scale = Math.max(0.000001, Math.min(factor * sess.transform_scale, 20));
if (sess.transform_scale < 3 && sess.transform_scale > 0.2) {
sess.transform_x += (evt.offsetX - sess.transform_x) * (1-factor);
sess.transform_y += (evt.offsetY - sess.transform_y) * (1-factor);
updateTransform();
}
};
document.body.onkeyup = (evt) => {
if (evt.key === "Escape") {
// change current action to lens
changeCurrentActionTo("lens");
}
}
buildItemsHighlightTiles();
gatherCvsImages();
setCanvasSize();
updateMoney(0);
//buildFromDatabase();
buildScene();
updateTransform();
window.requestAnimationFrame(gameLoop);
window.requestAnimationFrame(animationLoop);
}
window.onresize = () => {
setCanvasSize();
}
window.onbeforeunload = () => {
}