Replace NPC emoji with sprite: oak.png

This commit is contained in:
justin committed 2026-05-21 12:07:29 -07:00
1 parent 16633ffb74
commit 79521db109
3 files changed
+23 -8

No files matched your search

+19 -6
View File
@@ -16,8 +16,21 @@ const CONFIG = {
namePrompt: "Hello there! Welcome to PokéSQL! My name is Professor Oak — the SQL Professor. Now tell me, what is your name?", namePrompt: "Hello there! Welcome to PokéSQL! My name is Professor Oak — the SQL Professor. Now tell me, what is your name?",
}; };
function setNPC(el, val) {
if (!el) return;
if (val && val.endsWith('.png')) {
el.innerHTML = '';
const img = document.createElement('img');
img.src = val;
img.style.cssText = 'height:1em;width:auto;image-rendering:pixelated;vertical-align:middle;';
el.appendChild(img);
} else {
el.textContent = val || '🧑';
}
}
const NPC = { const NPC = {
'Professor Oak': '👴', 'Professor Oak': './oak.png',
'Rival Gary': '😤', 'Rival Gary': '😤',
'Old Man Bob': '🧓', 'Old Man Bob': '🧓',
'Nurse Joy': '👩‍⚕️', 'Nurse Joy': '👩‍⚕️',
@@ -48,9 +61,9 @@ const CORRECT_FB = ["That's right!","Excellent work!","Perfect!","Outstanding!",
const WRONG_FB = ["Not quite...","Hmm, that's not it.","Try again next time!","Almost...","Not this time!"]; const WRONG_FB = ["Not quite...","Hmm, that's not it.","Try again next time!","Almost...","Not this time!"];
const MILESTONES = { const MILESTONES = {
25: { badge:'🥉 SQL INITIATE', stars:'★ ★ ☆ ☆' }, 25: { badge:'🥉 CLOUD EXPLORER', stars:'★ ★ ☆ ☆' },
50: { badge:'🥈 QUERY TRAINER', stars:'★ ★ ★ ☆' }, 50: { badge:'🥈 AZURE APPRENTICE', stars:'★ ★ ★ ☆' },
75: { badge:'🥇 DATA WRANGLER', stars:'★ ★ ★ ★' }, 75: { badge:'🥇 CLOUD PRACTITIONER', stars:'★ ★ ★ ★' },
}; };
const SAVE_KEY = CONFIG.saveKey; const SAVE_KEY = CONFIG.saveKey;
@@ -998,7 +1011,7 @@ class Game {
const msg = INTRO_MSGS[this.state.introStep]; const msg = INTRO_MSGS[this.state.introStep];
if (!msg) return; if (!msg) return;
const npcEl = document.getElementById('intro-npc'); const npcEl = document.getElementById('intro-npc');
if (npcEl) npcEl.textContent = NPC[msg.npc] || '👴'; if (npcEl) setNPC(npcEl, NPC[msg.npc] || '👴');
document.getElementById('intro-speaker').textContent = msg.speaker; document.getElementById('intro-speaker').textContent = msg.speaker;
document.getElementById('intro-arrow').style.display = 'none'; document.getElementById('intro-arrow').style.display = 'none';
this.typeText('intro-text', this.typeText('intro-text',
@@ -1133,7 +1146,7 @@ class Game {
const q = this.state.questions[this.state.currentQ]; const q = this.state.questions[this.state.currentQ];
const npcEl = document.getElementById('map-npc'); const npcEl = document.getElementById('map-npc');
if (q && npcEl) npcEl.textContent = NPC[q.npc]||'🧑'; if (q && npcEl) setNPC(npcEl, NPC[q.npc]||'🧑');
this._placeMapSprites(); this._placeMapSprites();
this._checkNPCProximity(); this._checkNPCProximity();
+2 -2
View File
@@ -74,7 +74,7 @@
<!-- INTRO CUTSCENE --> <!-- INTRO CUTSCENE -->
<div id="screen-intro" class="screen"> <div id="screen-intro" class="screen">
<div class="overworld-bg"> <div class="overworld-bg">
<div class="intro-npc" id="intro-npc">👴</div> <div class="intro-npc" id="intro-npc"></div>
<div class="intro-player"></div> <div class="intro-player"></div>
</div> </div>
<div class="dialog-box intro-dialog"> <div class="dialog-box intro-dialog">
@@ -90,7 +90,7 @@
<div class="map-header"> <div class="map-header">
<div class="map-left"> <div class="map-left">
<span class="map-pin">📍</span> <span class="map-pin">📍</span>
<span class="map-town-name" id="map-town-name">SQL TOWN</span> <span class="map-town-name">SQL TOWN</span>
</div> </div>
<div class="map-center"> <div class="map-center">
<div class="prog-bar-outer"><div class="prog-bar-inner" id="map-prog-bar"></div></div> <div class="prog-bar-outer"><div class="prog-bar-inner" id="map-prog-bar"></div></div>
+2
View File
@@ -495,6 +495,8 @@ html, body {
.map-npc-wrap { position:absolute; text-align:center; z-index: 30; } .map-npc-wrap { position:absolute; text-align:center; z-index: 30; }
.npc-bubble { font-size:14px; font-family:var(--font); color:var(--black); background:var(--yellow); border:2px solid var(--black); width:20px; height:20px; display:flex; align-items:center; justify-content:center; margin:0 auto 2px; animation:bounce .7s ease-in-out infinite; } .npc-bubble { font-size:14px; font-family:var(--font); color:var(--black); background:var(--yellow); border:2px solid var(--black); width:20px; height:20px; display:flex; align-items:center; justify-content:center; margin:0 auto 2px; animation:bounce .7s ease-in-out infinite; }
.map-npc { font-size:clamp(36px,10vw,52px); filter:drop-shadow(2px 3px 0 rgba(0,0,0,.35)); cursor:pointer; animation:npcFloat 2s ease-in-out infinite; } .map-npc { font-size:clamp(36px,10vw,52px); filter:drop-shadow(2px 3px 0 rgba(0,0,0,.35)); cursor:pointer; animation:npcFloat 2s ease-in-out infinite; }
.intro-npc img { height:clamp(44px,13vw,64px); width:auto; image-rendering:pixelated; display:block; }
.map-npc img { height:clamp(36px,10vw,52px); width:auto; image-rendering:pixelated; display:block; }
/* Player is fixed to the viewport centre horizontally; only Y moves */ /* Player is fixed to the viewport centre horizontally; only Y moves */
/* "..." bubble above player when pressing talk away from NPC */ /* "..." bubble above player when pressing talk away from NPC */
.player-bubble { .player-bubble {