Skip to content

Commit 869068f

Browse files
authored
Merge branch 'main' into ui-buttons
2 parents b83ca23 + 7bc8973 commit 869068f

19 files changed

Lines changed: 549 additions & 265 deletions

File tree

eslint.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export default [
88
{
99
languageOptions: {
1010
globals: globals.browser,
11-
ecmaVersion: 2021,
11+
ecmaVersion: 'latest',
1212
sourceType: 'module',
1313
},
1414
files: ['src/**/*.js'],

index.html

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
background-color: #45a049;
8080
}
8181
</style>
82+
<link rel="stylesheet" href="./src/styles/backpack.css" />
8283
</head>
8384

8485
<body>
@@ -250,6 +251,20 @@
250251
</div>
251252
</div>
252253
<div id="right-panel" class="right">
254+
<div class="backpack">
255+
<button
256+
class="setting-btn"
257+
id="backpack-btn"
258+
style="display: none"
259+
>
260+
<img
261+
src="/assets/sprites/backpack.png"
262+
width="100"
263+
height="100"
264+
alt=""
265+
/>
266+
</button>
267+
</div>
253268
<div>
254269
<p id="clock">{placeholderText}</p>
255270
</div>
@@ -329,6 +344,34 @@
329344
</div>
330345
<canvas id="game"></canvas>
331346
</div>
347+
<div id="backpack-content" style="display: none">
348+
<div class="backpack-frame">
349+
<div class="title-bar">
350+
<h1>BACKPACK</h1>
351+
</div>
352+
<div class="backpack-container">
353+
<div class="backpack-graphic">
354+
<div class="backpack-flap"></div>
355+
356+
<div id="inventory-grid" class="inventory-grid"></div>
357+
358+
<div class="stats-section">
359+
<div class="stat-row">
360+
<span class="stat-label">SLOTS:</span>
361+
<span
362+
id="stat-slots"
363+
style="margin-left: auto"
364+
></span>
365+
</div>
366+
</div>
367+
</div>
368+
</div>
369+
370+
<div class="footer">
371+
<p>Press [I] to close inventory</p>
372+
</div>
373+
</div>
374+
</div>
332375
<script type="module" src="src/main.js"></script>
333376
<script type="module" src="src/utils/settings.js"></script>
334377
<script type="module" src="src/utils/miscellaneous.js"></script>

public/assets/sprites/backpack.png

286 KB
Loading

src/backpack.js

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import { getGameState, setGameState } from './utils/gameState';
2+
import { k } from './kplayCtx';
3+
4+
const backpackBtn = document.getElementById('backpack-btn');
5+
6+
let isOpened = false;
7+
8+
export class Backpack {
9+
constructor(state, maxSlots = 20) {
10+
this.maxSlots = maxSlots;
11+
this.inventory = state;
12+
}
13+
14+
getInventorySlotHtml(item) {
15+
return `<div class="inventory-slot">
16+
<img src="${item.assetUrl}" with="100%" alt="" />
17+
<span class="quantity-badge">${item.qty || 1}</span>
18+
<div class="tooltip">${item.itemName} ×${item.qty || 1}</div>
19+
</div>`;
20+
}
21+
22+
getInventorySlotsHtml() {
23+
const slots = this.inventory.map((item) => {
24+
return this.getInventorySlotHtml(item);
25+
});
26+
const emptySlotsCount = this.maxSlots - this.inventory.length;
27+
for (let i = 0; i < emptySlotsCount; i++) {
28+
slots.push('<div class="inventory-slot empty"></div>');
29+
}
30+
return slots;
31+
}
32+
33+
addItemToBackpack({ title, assetUrl }) {
34+
const itemInd = this.inventory.findIndex(
35+
(item) => item.itemName === title
36+
);
37+
if (itemInd !== -1) {
38+
const existedItem = this.inventory[itemInd];
39+
this.inventory[itemInd] = {
40+
...existedItem,
41+
qty: (existedItem.qty || 1) + 1,
42+
};
43+
} else {
44+
// Check if we have empty slots
45+
if (this.inventory.length < this.maxSlots - 1) {
46+
this.inventory.push({
47+
itemName: title,
48+
assetUrl: assetUrl,
49+
qty: 1,
50+
});
51+
} else {
52+
k.debug.log(
53+
'No empty slots left. Please remove items from backpack.'
54+
);
55+
}
56+
}
57+
const newState = getGameState();
58+
newState.player.backpack.items = this.inventory;
59+
setGameState(newState);
60+
}
61+
62+
render() {
63+
const backpack = document.getElementById('backpack-content');
64+
backpack.style.display = 'flex';
65+
66+
const slots = this.getInventorySlotsHtml();
67+
const inventory = document.getElementById('inventory-grid');
68+
inventory.innerHTML = slots.join(' ');
69+
70+
const statSlots = document.getElementById('stat-slots');
71+
statSlots.innerHTML = `${this.inventory.length} / ${this.maxSlots}`;
72+
}
73+
74+
hide() {
75+
const backpackElement = document.getElementById('backpack-content');
76+
backpackElement.style.display = 'none';
77+
}
78+
79+
static getInstance() {
80+
const gameState = getGameState();
81+
if (gameState.player.backpack) {
82+
return new Backpack(
83+
gameState.player.backpack.items,
84+
gameState.player.backpack.maxSlots
85+
);
86+
}
87+
return false;
88+
}
89+
90+
static addItem(params) {
91+
const instance = Backpack.getInstance();
92+
if (!instance) return;
93+
instance.addItemToBackpack(params);
94+
}
95+
96+
static initState() {
97+
const gameState = getGameState();
98+
gameState.player.backpack = {
99+
items: [],
100+
maxSlots: 20,
101+
};
102+
}
103+
104+
handleCloseBackpack() {
105+
if (!k.isFocused()) {
106+
k.pressButton('backpack');
107+
k.canvas.focus();
108+
}
109+
}
110+
111+
openBackpack() {
112+
this.render();
113+
document.addEventListener('keypress', this.handleCloseBackpack);
114+
isOpened = true;
115+
}
116+
117+
hideBackpack() {
118+
this.hide();
119+
document.removeEventListener('keypress', this.handleCloseBackpack);
120+
isOpened = false;
121+
}
122+
123+
static init() {
124+
const instance = Backpack.getInstance();
125+
if (instance) {
126+
backpackBtn.style.display = 'block';
127+
128+
backpackBtn.addEventListener('click', () => {
129+
instance.openBackpack();
130+
});
131+
}
132+
}
133+
134+
static backpackInteractions() {
135+
k.onButtonPress('backpack', () => {
136+
const instance = Backpack.getInstance();
137+
if (!instance) return;
138+
139+
if (!isOpened) {
140+
instance.openBackpack();
141+
} else {
142+
instance.hideBackpack();
143+
}
144+
});
145+
}
146+
147+
static showButton() {
148+
backpackBtn.style.display = 'block';
149+
}
150+
151+
static removeButton() {
152+
backpackBtn.style.display = 'none';
153+
}
154+
}

src/gameObjects/map_campus_house_1/banana.gameObject.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ export const banana = (k, map) => {
99
k.scale(0.6),
1010
k.offscreen({ hide: true, distance: 10 }),
1111
'banana',
12+
{ assetUrl: './assets/sprites/banana.png' },
1213
]);
1314
};

src/gameObjects/map_forest/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ import { flashDrive } from './flashdrive.gameObject';
33

44
const gameObjects = [butterfly, flashDrive];
55

6+
67
export default gameObjects;

src/interactions/map_campus_house_1/backpack.interaction.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Backpack } from '../../backpack';
12
import { displayPermissionBox, displayDialogue } from '../../utils';
23

34
export const backpackInteractions = (player, k, map) => {
@@ -13,8 +14,11 @@ export const backpackInteractions = (player, k, map) => {
1314
const dialog = [];
1415

1516
if (wantBackpack) {
16-
player.state.backpack = [];
17+
Backpack.initState();
1718
k.destroy(backpack);
19+
// show backpack on side right panel
20+
Backpack.showButton();
21+
1822
dialog.push('Aye, a trusty pack for a worthy traveler.');
1923
} else {
2024
dialog.push('Oh, going minimalist this time? Bold choice.');
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
import { objectToBackpackInteraction } from '../../utils';
22

3-
export const bananaInteraction = objectToBackpackInteraction('banana');
3+
export const bananaInteraction = objectToBackpackInteraction({ tag: 'banana' });
Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,83 @@
11
import { interactionHandler } from '../handler.interactions';
22
import { displayDialogue } from '../../utils';
3+
import { completeQuestObjective, playerHasQuest, recieveQuest, completeQuest, isObjectiveComplete } from '../../utils/questHandler';
4+
import { jessicaQuests } from '../quests/constants.quests';
5+
import { updateEnergyState } from '../../utils/energyUpdate';
6+
import { addCoins } from '../../utils/coinsUpdate';
37

4-
export const jessicaInteraction = (player, k) => {
8+
const generateJessicaDialogue = (player) => {
9+
if (
10+
!playerHasQuest(player, 'Find the Flash Drive')
11+
) {
12+
return "Hi, I'm Jessica! Would you please help me find my flash drive? I think I lost it up north in the forest, but I haven't had any luck finding it!"
13+
} else if (
14+
// Player has the quest but hasn't found the flash drive yet
15+
playerHasQuest(player, 'Find the Flash Drive')
16+
&&
17+
!isObjectiveComplete(player, 'Find the Flash Drive', 'Found the Flash Drive')
18+
) {
19+
return "Any luck finding my flash drive? I think I lost it up north in the forest."
20+
} else if (
21+
// Player has found the flash drive but hasn't returned it yet
22+
playerHasQuest(player, 'Find the Flash Drive')
23+
&&
24+
isObjectiveComplete(player, 'Find the Flash Drive', 'Found the Flash Drive')
25+
) {
26+
return "You found it! Thank you so much for finding my flash drive! I was really worried I'd lost all my work on my Javascript project! You're the best! Let me pay you for your help!"
27+
} else {
28+
return "Have a great day!"
29+
}
30+
31+
}
32+
33+
export const jessicaInteraction = async (player, k) => {
534
interactionHandler(player, 'jessica', k, async () => {
635
await displayDialogue({
736
k,
837
player,
938
characterName: 'Jessica',
1039
text: [
11-
"Hi, I'm Jessica! I'm learning Javascript! It's a lot of work, but I'm excited to get better at it.",
40+
generateJessicaDialogue(player)
1241
],
42+
onDisplayEnd: async () => {
43+
if (!playerHasQuest(player, 'Find the Flash Drive')) {
44+
await recieveQuest(
45+
player,
46+
jessicaQuests.findTheFlashDriveQuest
47+
)
48+
await completeQuestObjective(
49+
player,
50+
'Find the Flash Drive',
51+
'Has Talked to Jessica'
52+
)
53+
}
54+
if (
55+
playerHasQuest(player, 'Find the Flash Drive')
56+
&&
57+
!isObjectiveComplete(player, 'Find the Flash Drive', 'Has Talked to Jessica')
58+
) {
59+
await completeQuestObjective(
60+
player,
61+
'Find the Flash Drive',
62+
'Has Talked to Jessica'
63+
)
64+
}
65+
if (
66+
isObjectiveComplete(player, 'Find the Flash Drive', 'Found the Flash Drive')
67+
&&
68+
!isObjectiveComplete(player, 'Find the Flash Drive', 'Returned the Flash Drive')
69+
) {
70+
updateEnergyState(player.state, 99);
71+
addCoins(50);
72+
await completeQuestObjective(
73+
player,
74+
'Find the Flash Drive',
75+
'Returned the Flash Drive'
76+
)
77+
}
78+
// Check if all objectives are complete
79+
await completeQuest(player, 'Find the Flash Drive');
80+
}
1381
});
1482
});
1583
};
Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
11
import { displayDialogue } from '../../utils';
2+
import { playerHasQuest, completeQuestObjective } from '../../utils/questHandler';
23
import { interactionHandler } from '../handler.interactions';
34

45
export const interactionWithFlashDrive = (player, k, map) => {
6+
7+
const messageToPlayer = "You found a flash drive! " + (playerHasQuest(player, 'Find the Flash Drive')
8+
? "This might be Jessica's flash drive! Better return it to her in the city!"
9+
: "You wonder who it might belong to? You leave it be in case someone comes looking for it.");
10+
511
interactionHandler(player, 'flashDrive', k, () => {
612
displayDialogue({
713
k,
814
player,
9-
characterName: 'flashDrive',
15+
characterName: 'Flash Drive',
1016
text: [
11-
'You found a flash drive in the the forest. You wonder who it might belong to?',
17+
messageToPlayer
1218
],
19+
onDisplayEnd: async () => {
20+
if (playerHasQuest(player, 'Find the Flash Drive')) {
21+
await completeQuestObjective(
22+
player,
23+
'Find the Flash Drive',
24+
'Found the Flash Drive'
25+
)
26+
}
27+
}
1328
});
1429
});
1530
};

0 commit comments

Comments
 (0)