Widget:WheelOfNursing: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
| Line 4: | Line 4: | ||
== Usage == | == Usage == | ||
<pre>{{#widget:WheelOfNursing}}</pre> | <pre>{{#widget:WheelOfNursing}}</pre> | ||
</noinclude><includeonly> | |||
== Parameters == | |||
This widget does not accept any parameters. | |||
[[Category:Widgets]] | |||
</noinclude><includeonly><style> | |||
#wheel-of-nursing-game { | |||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |||
background: linear-gradient(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%); | |||
min-height: 600px; | |||
color: #fff; | |||
padding: 20px; | |||
border-radius: 10px; | |||
position: relative; | |||
} | |||
#wheel-of-nursing-game * { | |||
box-sizing: border-box; | |||
} | |||
#wheel-of-nursing-game .game-container { | |||
max-width: 900px; | |||
margin: 0 auto; | |||
} | |||
#wheel-of-nursing-game .sound-controls { | |||
position: absolute; | |||
top: 10px; | |||
right: 10px; | |||
background: rgba(0,0,0,0.8); | |||
padding: 15px; | |||
border-radius: 10px; | |||
z-index: 100; | |||
} | |||
#wheel-of-nursing-game .sound-controls button { | |||
padding: 8px 12px; | |||
margin: 2px; | |||
font-size: 14px; | |||
border: none; | |||
border-radius: 5px; | |||
cursor: pointer; | |||
color: #fff; | |||
} | |||
#wheel-of-nursing-game .sound-controls .on { background: #2ecc71; } | |||
#wheel-of-nursing-game .sound-controls .off { background: #e74c3c; } | |||
#wheel-of-nursing-game .volume-control { | |||
margin-top: 10px; | |||
color: #fff; | |||
font-size: 12px; | |||
} | |||
#wheel-of-nursing-game .volume-control input { | |||
width: 100px; | |||
margin-left: 5px; | |||
} | |||
#wheel-of-nursing-game .header { | |||
display: flex; | |||
justify-content: space-between; | |||
align-items: center; | |||
flex-wrap: wrap; | |||
gap: 15px; | |||
margin-bottom: 20px; | |||
} | |||
#wheel-of-nursing-game .header h1 { | |||
color: #ffd700; | |||
font-size: 32px; | |||
text-shadow: 3px 3px 6px rgba(0,0,0,0.5); | |||
margin: 0; | |||
border: none; | |||
} | |||
#wheel-of-nursing-game .scores { | |||
display: flex; | |||
gap: 20px; | |||
} | |||
#wheel-of-nursing-game .score-box { | |||
padding: 10px 20px; | |||
border-radius: 10px; | |||
text-align: center; | |||
} | |||
#wheel-of-nursing-game .score-box.round { | |||
background: rgba(255,215,0,0.2); | |||
border: 2px solid #ffd700; | |||
} | |||
#wheel-of-nursing-game .score-box.total { | |||
background: rgba(46,204,113,0.2); | |||
border: 2px solid #2ecc71; | |||
} | |||
#wheel-of-nursing-game .score-box .label { | |||
font-size: 12px; | |||
color: #ffd700; | |||
} | |||
#wheel-of-nursing-game .score-box.total .label { | |||
color: #2ecc71; | |||
} | |||
#wheel-of-nursing-game .score-box .value { | |||
font-size: 28px; | |||
font-weight: bold; | |||
} | |||
#wheel-of-nursing-game .message-box { | |||
background: rgba(255,255,255,0.1); | |||
padding: 15px 20px; | |||
border-radius: 10px; | |||
margin-bottom: 20px; | |||
text-align: center; | |||
font-size: 18px; | |||
} | |||
#wheel-of-nursing-game .message-box .wheel-value { | |||
color: #ffd700; | |||
font-weight: bold; | |||
margin-left: 10px; | |||
} | |||
#wheel-of-nursing-game .puzzle-board { | |||
background: linear-gradient(135deg, #1a237e 0%, #0d47a1 100%); | |||
padding: 30px; | |||
border-radius: 15px; | |||
margin-bottom: 20px; | |||
box-shadow: 0 10px 30px rgba(0,0,0,0.3); | |||
} | |||
#wheel-of-nursing-game .category { | |||
color: #ffd700; | |||
font-size: 14px; | |||
text-transform: uppercase; | |||
letter-spacing: 3px; | |||
margin-bottom: 15px; | |||
text-align: center; | |||
} | |||
#wheel-of-nursing-game .letter-tiles { | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: center; | |||
gap: 8px; | |||
margin-bottom: 20px; | |||
} | |||
#wheel-of-nursing-game .letter-tile { | |||
width: 45px; | |||
height: 55px; | |||
border: 3px solid #ffd700; | |||
border-radius: 5px; | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
font-size: 28px; | |||
font-weight: bold; | |||
color: #1a237e; | |||
box-shadow: 0 4px 8px rgba(0,0,0,0.2); | |||
} | |||
#wheel-of-nursing-game .letter-tile.revealed { | |||
background: #fff; | |||
} | |||
#wheel-of-nursing-game .letter-tile.hidden { | |||
background: #1a237e; | |||
} | |||
#wheel-of-nursing-game .letter-tile.space { | |||
border: none; | |||
background: transparent; | |||
box-shadow: none; | |||
} | |||
#wheel-of-nursing-game .clue-box { | |||
color: #fff; | |||
font-size: 16px; | |||
font-style: italic; | |||
padding: 15px; | |||
background: rgba(255,255,255,0.1); | |||
border-radius: 10px; | |||
text-align: center; | |||
} | |||
#wheel-of-nursing-game .wheel-container { | |||
position: relative; | |||
width: 300px; | |||
height: 300px; | |||
margin: 0 auto 20px; | |||
} | |||
#wheel-of-nursing-game .wheel-pointer { | |||
position: absolute; | |||
top: -15px; | |||
left: 50%; | |||
transform: translateX(-50%); | |||
width: 0; | |||
height: 0; | |||
border-left: 15px solid transparent; | |||
border-right: 15px solid transparent; | |||
border-top: 30px solid #ffd700; | |||
z-index: 10; | |||
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.3)); | |||
} | |||
#wheel-of-nursing-game .wheel-svg { | |||
width: 100%; | |||
height: 100%; | |||
transition: transform 3s cubic-bezier(0.17, 0.67, 0.12, 0.99); | |||
} | |||
#wheel-of-nursing-game .letter-board { | |||
margin-bottom: 20px; | |||
} | |||
#wheel-of-nursing-game .letter-section { | |||
margin-bottom: 15px; | |||
} | |||
#wheel-of-nursing-game .letter-section-label { | |||
color: #ffd700; | |||
font-size: 12px; | |||
letter-spacing: 2px; | |||
margin-bottom: 8px; | |||
text-align: center; | |||
} | |||
#wheel-of-nursing-game .letter-buttons { | |||
display: flex; | |||
flex-wrap: wrap; | |||
gap: 5px; | |||
justify-content: center; | |||
} | |||
#wheel-of-nursing-game .letter-btn { | |||
width: 36px; | |||
height: 36px; | |||
font-size: 16px; | |||
font-weight: bold; | |||
border: none; | |||
border-radius: 5px; | |||
cursor: pointer; | |||
color: #fff; | |||
transition: all 0.2s; | |||
} | |||
#wheel-of-nursing-game .letter-btn.consonant { background: #2ecc71; } | |||
#wheel-of-nursing-game .letter-btn.consonant:disabled { background: #555; opacity: 0.5; cursor: not-allowed; } | |||
#wheel-of-nursing-game .letter-btn.consonant.inactive { background: #888; cursor: not-allowed; } | |||
#wheel-of-nursing-game .letter-btn.vowel { | |||
width: 45px; | |||
height: 45px; | |||
font-size: 18px; | |||
background: #e74c3c; | |||
} | |||
#wheel-of-nursing-game .letter-btn.vowel:disabled { background: #555; opacity: 0.5; cursor: not-allowed; } | |||
#wheel-of-nursing-game .letter-btn.vowel.inactive { background: #888; cursor: not-allowed; } | |||
#wheel-of-nursing-game .action-buttons { | |||
display: flex; | |||
gap: 10px; | |||
justify-content: center; | |||
flex-wrap: wrap; | |||
margin-bottom: 20px; | |||
} | |||
#wheel-of-nursing-game .action-btn { | |||
padding: 15px 40px; | |||
font-size: 18px; | |||
font-weight: bold; | |||
border: none; | |||
border-radius: 30px; | |||
cursor: pointer; | |||
transition: transform 0.2s; | |||
} | |||
#wheel-of-nursing-game .action-btn:hover:not(:disabled) { | |||
transform: scale(1.05); | |||
} | |||
#wheel-of-nursing-game .action-btn:disabled { | |||
opacity: 0.6; | |||
cursor: not-allowed; | |||
} | |||
#wheel-of-nursing-game .action-btn.spin { | |||
background: linear-gradient(135deg, #ffd700 0%, #ffb700 100%); | |||
color: #1a237e; | |||
box-shadow: 0 5px 15px rgba(255, 215, 0, 0.3); | |||
} | |||
#wheel-of-nursing-game .action-btn.solve { | |||
background: #9b59b6; | |||
color: #fff; | |||
} | |||
#wheel-of-nursing-game .action-btn.hint { | |||
background: #3498db; | |||
color: #fff; | |||
} | |||
#wheel-of-nursing-game .hint-box { | |||
margin-top: 15px; | |||
padding: 15px; | |||
background: rgba(52, 152, 219, 0.3); | |||
border-radius: 10px; | |||
text-align: center; | |||
border: 2px solid #3498db; | |||
} | |||
#wheel-of-nursing-game .solve-input-container { | |||
text-align: center; | |||
margin-bottom: 20px; | |||
} | |||
#wheel-of-nursing-game .solve-input { | |||
padding: 15px 20px; | |||
font-size: 20px; | |||
width: 100%; | |||
max-width: 400px; | |||
border-radius: 10px; | |||
border: 3px solid #ffd700; | |||
margin-bottom: 10px; | |||
} | |||
#wheel-of-nursing-game .solve-buttons { | |||
display: flex; | |||
gap: 10px; | |||
justify-content: center; | |||
} | |||
#wheel-of-nursing-game .solve-btn { | |||
padding: 12px 30px; | |||
font-size: 16px; | |||
font-weight: bold; | |||
border: none; | |||
border-radius: 25px; | |||
cursor: pointer; | |||
color: #fff; | |||
} | |||
#wheel-of-nursing-game .solve-btn.submit { background: #2ecc71; } | |||
#wheel-of-nursing-game .solve-btn.cancel { background: #e74c3c; } | |||
#wheel-of-nursing-game .result-screen { | |||
text-align: center; | |||
margin-top: 30px; | |||
padding: 30px; | |||
border-radius: 15px; | |||
} | |||
#wheel-of-nursing-game .result-screen.won { | |||
background: rgba(46, 204, 113, 0.2); | |||
border: 3px solid #2ecc71; | |||
} | |||
#wheel-of-nursing-game .result-screen.lost { | |||
background: rgba(231, 76, 60, 0.2); | |||
border: 3px solid #e74c3c; | |||
} | |||
#wheel-of-nursing-game .result-screen h2 { | |||
font-size: 32px; | |||
margin-bottom: 15px; | |||
border: none; | |||
} | |||
#wheel-of-nursing-game .result-screen.won h2 { color: #2ecc71; } | |||
#wheel-of-nursing-game .result-screen.lost h2 { color: #e74c3c; } | |||
#wheel-of-nursing-game .result-screen p { | |||
font-size: 18px; | |||
margin-bottom: 20px; | |||
} | |||
#wheel-of-nursing-game .result-screen .total-score { | |||
color: #ffd700; | |||
font-weight: bold; | |||
} | |||
#wheel-of-nursing-game .result-buttons { | |||
display: flex; | |||
gap: 15px; | |||
justify-content: center; | |||
} | |||
#wheel-of-nursing-game .result-btn { | |||
padding: 15px 40px; | |||
font-size: 18px; | |||
font-weight: bold; | |||
border: none; | |||
border-radius: 30px; | |||
cursor: pointer; | |||
} | |||
#wheel-of-nursing-game .result-btn.next { | |||
background: linear-gradient(135deg, #ffd700 0%, #ffb700 100%); | |||
color: #1a237e; | |||
} | |||
#wheel-of-nursing-game .result-btn.new-game { | |||
background: #e74c3c; | |||
color: #fff; | |||
} | |||
#wheel-of-nursing-game .start-screen { | |||
display: flex; | |||
flex-direction: column; | |||
align-items: center; | |||
justify-content: center; | |||
min-height: 500px; | |||
text-align: center; | |||
} | |||
#wheel-of-nursing-game .start-screen h1 { | |||
color: #ffd700; | |||
font-size: 48px; | |||
text-shadow: 3px 3px 6px rgba(0,0,0,0.5); | |||
margin-bottom: 20px; | |||
border: none; | |||
} | |||
#wheel-of-nursing-game .start-screen p { | |||
font-size: 18px; | |||
max-width: 600px; | |||
margin-bottom: 30px; | |||
line-height: 1.6; | |||
} | |||
#wheel-of-nursing-game .sound-notice { | |||
background: rgba(255,255,255,0.1); | |||
padding: 20px; | |||
border-radius: 10px; | |||
margin-bottom: 30px; | |||
} | |||
#wheel-of-nursing-game .sound-notice p:first-child { | |||
color: #ffd700; | |||
margin-bottom: 10px; | |||
} | |||
#wheel-of-nursing-game .sound-notice p:last-child { | |||
color: #aaa; | |||
font-size: 14px; | |||
margin-bottom: 0; | |||
} | |||
#wheel-of-nursing-game .start-btn { | |||
padding: 20px 60px; | |||
font-size: 24px; | |||
font-weight: bold; | |||
background: linear-gradient(135deg, #ffd700 0%, #ffb700 100%); | |||
border: none; | |||
border-radius: 50px; | |||
cursor: pointer; | |||
color: #1a237e; | |||
box-shadow: 0 10px 30px rgba(255, 215, 0, 0.4); | |||
transition: transform 0.2s; | |||
} | |||
#wheel-of-nursing-game .start-btn:hover { | |||
transform: scale(1.05); | |||
} | |||
#wheel-of-nursing-game .hidden { | |||
display: none !important; | |||
} | |||
</style> | |||
<div id="wheel-of-nursing-game"> | <div id="wheel-of-nursing-game"> | ||
<div class="sound-controls"> | <div class="sound-controls"> | ||
<div> | <div> | ||
<button id=" | <button id="wonMusicToggle" class="on" onclick="WON.toggleMusic()">🎵 Music ON</button> | ||
<button id=" | <button id="wonSfxToggle" class="on" onclick="WON.toggleSfx()">🔊 SFX ON</button> | ||
</div> | </div> | ||
<div class="volume-control | <div class="volume-control"> | ||
<label>Music: <input type="range" id=" | <label>Music: <input type="range" id="wonMusicVolume" min="0" max="30" value="15" onchange="WON.setMusicVolume(this.value)"></label> | ||
</div> | </div> | ||
<div class="volume-control | <div class="volume-control"> | ||
<label>SFX: <input type="range" id=" | <label>SFX: <input type="range" id="wonSfxVolume" min="0" max="50" value="30" onchange="WON.setSfxVolume(this.value)"></label> | ||
</div> | </div> | ||
</div> | </div> | ||
<div class="game-container"> | <div class="game-container"> | ||
<div id="wonStartScreen" class="start-screen"> | |||
<div id=" | |||
<h1>🎡 Wheel of Nursing! 🏥</h1> | <h1>🎡 Wheel of Nursing! 🏥</h1> | ||
<p>Test your pharmacology and nursing knowledge! Spin the wheel, guess letters, and solve the puzzle. Based on HESI exam topics!</p> | <p>Test your pharmacology and nursing knowledge! Spin the wheel, guess letters, and solve the puzzle. Based on HESI exam topics!</p> | ||
| Line 509: | Line 501: | ||
<p>Click Start to enable audio</p> | <p>Click Start to enable audio</p> | ||
</div> | </div> | ||
<button class="start-btn" onclick="startGame()">🎮 Start Game!</button> | <button class="start-btn" onclick="WON.startGame()">🎮 Start Game!</button> | ||
</div> | </div> | ||
<div id="wonGameScreen" class="hidden"> | |||
<div id=" | |||
<div class="header"> | <div class="header"> | ||
<h1>🎡 Wheel of Nursing!</h1> | <h1>🎡 Wheel of Nursing!</h1> | ||
| Line 520: | Line 510: | ||
<div class="score-box round"> | <div class="score-box round"> | ||
<div class="label">ROUND</div> | <div class="label">ROUND</div> | ||
<div class="value" id=" | <div class="value" id="wonRoundScore">$0</div> | ||
</div> | </div> | ||
<div class="score-box total"> | <div class="score-box total"> | ||
<div class="label">TOTAL</div> | <div class="label">TOTAL</div> | ||
<div class="value" id=" | <div class="value" id="wonTotalScore">$0</div> | ||
</div> | </div> | ||
</div> | </div> | ||
</div> | </div> | ||
<div class="message-box"> | <div class="message-box"> | ||
<span id=" | <span id="wonMessage">Spin the wheel!</span> | ||
<span id=" | <span id="wonWheelValue" class="wheel-value hidden"></span> | ||
</div> | </div> | ||
<div class="puzzle-board"> | <div class="puzzle-board"> | ||
<div class="category" id=" | <div class="category" id="wonCategory">CATEGORY</div> | ||
<div class="letter-tiles" id=" | <div class="letter-tiles" id="wonLetterTiles"></div> | ||
<div class="clue-box"> | <div class="clue-box"> | ||
<strong>Clue:</strong> <span id=" | <strong>Clue:</strong> <span id="wonClue">Loading...</span> | ||
</div> | </div> | ||
</div> | </div> | ||
<div class="wheel-container" id="wonWheelContainer"> | |||
<div class="wheel-container" id=" | |||
<div class="wheel-pointer"></div> | <div class="wheel-pointer"></div> | ||
<svg class="wheel-svg" id=" | <svg class="wheel-svg" id="wonWheel" viewBox="0 0 200 200"></svg> | ||
</div> | </div> | ||
<div class="letter-board" id="wonLetterBoard"> | |||
<div class="letter-board" id=" | |||
<div class="letter-section"> | <div class="letter-section"> | ||
<div class="letter-section-label">CONSONANTS</div> | <div class="letter-section-label">CONSONANTS</div> | ||
<div class="letter-buttons" id=" | <div class="letter-buttons" id="wonConsonants"></div> | ||
</div> | </div> | ||
<div class="letter-section"> | <div class="letter-section"> | ||
<div class="letter-section-label">VOWELS ($250 each)</div> | <div class="letter-section-label">VOWELS ($250 each)</div> | ||
<div class="letter-buttons" id=" | <div class="letter-buttons" id="wonVowels"></div> | ||
</div> | </div> | ||
</div> | </div> | ||
<div class="solve-input-container hidden" id="wonSolveContainer"> | |||
<div class="solve-input-container hidden" id=" | <input type="text" class="solve-input" id="wonSolveInput" placeholder="Type your answer..."> | ||
<input type="text" class="solve-input" id=" | |||
<div class="solve-buttons"> | <div class="solve-buttons"> | ||
<button class="solve-btn submit" onclick="submitSolve()">Submit</button> | <button class="solve-btn submit" onclick="WON.submitSolve()">Submit</button> | ||
<button class="solve-btn cancel" onclick="cancelSolve()">Cancel</button> | <button class="solve-btn cancel" onclick="WON.cancelSolve()">Cancel</button> | ||
</div> | </div> | ||
</div> | </div> | ||
<div class="action-buttons" id="wonActionButtons"> | |||
<div class="action-buttons" id=" | <button class="action-btn spin" id="wonSpinBtn" onclick="WON.spinWheel()">🎡 Spin Wheel</button> | ||
<button class="action-btn spin" id=" | <button class="action-btn solve" id="wonSolveBtn" onclick="WON.attemptSolve()">💡 Solve Puzzle</button> | ||
<button class="action-btn solve" id=" | <button class="action-btn hint" id="wonHintBtn" onclick="WON.useHint()">🔍 Hint (-$200)</button> | ||
<button class="action-btn hint" id=" | |||
</div> | </div> | ||
<div class="hint-box hidden" id="wonHintBox"> | |||
<div class="hint-box hidden" id=" | <strong>💡 Hint:</strong> <span id="wonHintText"></span> | ||
<strong>💡 Hint:</strong> <span id=" | |||
</div> | </div> | ||
<div class="result-screen hidden" id="wonResultScreen"> | |||
<div class="result-screen hidden" id=" | <h2 id="wonResultTitle">Congratulations!</h2> | ||
<h2 id=" | <p>Total Score: <span class="total-score" id="wonFinalScore">$0</span></p> | ||
<p>Total Score: <span class="total-score" id=" | |||
<div class="result-buttons"> | <div class="result-buttons"> | ||
<button class="result-btn next" onclick="nextPuzzle()">Next Puzzle →</button> | <button class="result-btn next" onclick="WON.nextPuzzle()">Next Puzzle →</button> | ||
<button class="result-btn new-game" onclick="newGame()">New Game</button> | <button class="result-btn new-game" onclick="WON.newGame()">New Game</button> | ||
</div> | </div> | ||
</div> | </div> | ||
</div> | </div> | ||
</div> | </div> | ||
</div> | |||
<script> | |||
(function() { | |||
// Namespace to avoid conflicts with MediaWiki | |||
window.WON = window.WON || {}; | |||
const QUESTIONS = [ | |||
{ category: "CARDIOVASCULAR", clue: "This class of medications ending in '-pril' treats hypertension by blocking angiotensin conversion", answer: "ACE INHIBITORS", hint: "Think lisinopril, enalapril" }, | |||
{ category: "ENDOCRINE", clue: "This hormone produced by beta cells of the pancreas lowers blood glucose levels", answer: "INSULIN", hint: "Diabetic patients may inject this" }, | |||
{ category: "RESPIRATORY", clue: "This bronchodilator class ending in '-terol' provides quick relief for asthma attacks", answer: "BETA AGONISTS", hint: "Albuterol is an example" }, | |||
{ category: "PAIN MANAGEMENT", clue: "This opioid antagonist reverses respiratory depression from narcotic overdose", answer: "NALOXONE", hint: "Brand name Narcan" }, | |||
{ category: "RENAL", clue: "This class of diuretics acts on the loop of Henle and includes furosemide", answer: "LOOP DIURETICS", hint: "Lasix is a common one" }, | |||
{ category: "PSYCHIATRIC", clue: "This class of antidepressants selectively inhibits serotonin reuptake", answer: "SSRI", hint: "Prozac and Zoloft belong here" }, | |||
{ category: "GI/HEPATIC", clue: "This class of medications ending in '-prazole' reduces stomach acid by blocking proton pumps", answer: "PPI", hint: "Omeprazole is an example" }, | |||
{ category: "IMMUNE/HEMATOLOGY", clue: "This vitamin is essential for proper blood clotting and is reversed by warfarin", answer: "VITAMIN K", hint: "Given to newborns at birth" }, | |||
{ category: "NEUROLOGICAL", clue: "This medication is the first-line treatment for status epilepticus", answer: "BENZODIAZEPINES", hint: "Lorazepam or diazepam" }, | |||
{ category: "MUSCULOSKELETAL", clue: "This bisphosphonate medication treats osteoporosis by inhibiting bone resorption", answer: "ALENDRONATE", hint: "Brand name Fosamax" }, | |||
{ category: "FUNDAMENTALS", clue: "These are the six rights of medication administration: right patient, drug, dose, route, time, and this", answer: "DOCUMENTATION", hint: "Record keeping" }, | |||
{ category: "FLUID & ELECTROLYTE", clue: "This electrolyte imbalance causes peaked T waves on ECG and requires immediate treatment", answer: "HYPERKALEMIA", hint: "Too much potassium" }, | |||
{ category: "INFECTION", clue: "This antibiotic class ending in '-cillin' works by inhibiting cell wall synthesis", answer: "PENICILLINS", hint: "Amoxicillin belongs here" }, | |||
{ category: "SENSORY", clue: "These eye drops ending in '-olol' treat glaucoma by reducing aqueous humor production", answer: "BETA BLOCKERS", hint: "Timolol is commonly used" }, | |||
{ category: "CARDIOVASCULAR", clue: "This cardiac glycoside from the foxglove plant increases cardiac contractility", answer: "DIGOXIN", hint: "Check apical pulse before giving" }, | |||
{ category: "PATHOPHYSIOLOGY", clue: "This condition occurs when the heart cannot pump enough blood to meet the body's needs", answer: "HEART FAILURE", hint: "Can be left or right sided" }, | |||
{ category: "MED ADMINISTRATION", clue: "This injection angle is used for subcutaneous medications like insulin", answer: "FORTY FIVE DEGREES", hint: "Between 45 and 90 degrees" }, | |||
{ category: "TEACHING", clue: "This teaching method uses return demonstration to verify patient understanding", answer: "TEACH BACK", hint: "Show me how you would..." } | |||
]; | |||
const WHEEL_SEGMENTS = [ | |||
{ value: 100, color: '#e74c3c' }, { value: 200, color: '#3498db' }, | |||
{ value: 300, color: '#2ecc71' }, { value: 400, color: '#f39c12' }, | |||
{ value: 500, color: '#9b59b6' }, { value: 600, color: '#1abc9c' }, | |||
{ value: 700, color: '#e67e22' }, { value: 800, color: '#34495e' }, | |||
{ value: 'BANKRUPT', color: '#000000' }, { value: 900, color: '#16a085' }, | |||
{ value: 1000, color: '#c0392b' }, { value: 'LOSE TURN', color: '#7f8c8d' } | |||
]; | |||
const CONSONANTS = 'BCDFGHJKLMNPQRSTVWXYZ'.split(''); | |||
const VOWELS = ['A', 'E', 'I', 'O', 'U']; | |||
let currentQuestion = null; | |||
let revealedLetters = new Set(); | |||
let totalScore = 0; | |||
let roundScore = 0; | |||
let wheelRotation = 0; | |||
let currentWheelValue = null; | |||
let gamePhase = 'start'; | |||
let spinning = false; | |||
let usedQuestions = []; | |||
let hintUsed = false; | |||
let audioContext = null; | |||
let musicGain = null; | |||
let sfxGain = null; | |||
let musicEnabled = true; | |||
let sfxEnabled = true; | |||
let musicPlaying = false; | |||
function initAudio() { | |||
if (!audioContext) { | |||
audioContext = new (window.AudioContext || window.webkitAudioContext)(); | |||
musicGain = audioContext.createGain(); | |||
musicGain.gain.value = 0.15; | |||
musicGain.connect(audioContext.destination); | |||
sfxGain = audioContext.createGain(); | |||
sfxGain.gain.value = 0.3; | |||
sfxGain.connect(audioContext.destination); | |||
} | } | ||
if (audioContext.state === 'suspended') audioContext.resume(); | |||
} | |||
function playNote(frequency, duration, type, gain) { | |||
if (!audioContext || !sfxEnabled) return; | |||
gain = gain || sfxGain; | |||
const osc = audioContext.createOscillator(); | |||
const noteGain = audioContext.createGain(); | |||
osc.type = type || 'sine'; | |||
osc.frequency.setValueAtTime(frequency, audioContext.currentTime); | |||
noteGain.gain.setValueAtTime(0.3, audioContext.currentTime); | |||
noteGain.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + duration); | |||
osc.connect(noteGain); | |||
noteGain.connect(gain); | |||
osc.start(); | |||
osc.stop(audioContext.currentTime + duration); | |||
} | |||
function playClick() { | |||
if (!audioContext || !sfxEnabled) return; | |||
const osc = audioContext.createOscillator(); | |||
const clickGain = audioContext.createGain(); | |||
osc.type = 'square'; | |||
osc.frequency.setValueAtTime(800 + Math.random() * 400, audioContext.currentTime); | |||
clickGain.gain.setValueAtTime(0.2, audioContext.currentTime); | |||
clickGain.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.05); | |||
osc.connect(clickGain); | |||
clickGain.connect(sfxGain); | |||
osc.start(); | |||
osc.stop(audioContext.currentTime + 0.05); | |||
} | |||
function playWheelSpin(duration) { | |||
if (!audioContext || !sfxEnabled) return; | |||
let time = 0; | |||
for (let i = 0; i < 60; i++) { | |||
const interval = 30 * Math.pow(1 + (i/60) * 3, 2); | |||
if (time < duration) setTimeout(playClick, time); | |||
time += interval; | |||
} | } | ||
} | |||
function playCorrect() { | |||
if (!sfxEnabled) return; | |||
[523.25, 659.25, 783.99].forEach((f, i) => setTimeout(() => playNote(f, 0.2, 'sine'), i * 100)); | |||
} | |||
function playWrong() { | |||
if (!audioContext || !sfxEnabled) return; | |||
const osc = audioContext.createOscillator(); | |||
const g = audioContext.createGain(); | |||
osc.type = 'sawtooth'; | |||
osc.frequency.setValueAtTime(150, audioContext.currentTime); | |||
g.gain.setValueAtTime(0.2, audioContext.currentTime); | |||
g.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3); | |||
osc.connect(g); | |||
g.connect(sfxGain); | |||
osc.start(); | |||
osc.stop(audioContext.currentTime + 0.3); | |||
} | |||
function playBankrupt() { | |||
if (!sfxEnabled) return; | |||
[400, 350, 300, 250, 200, 150].forEach((f, i) => setTimeout(() => playNote(f, 0.15, 'sawtooth'), i * 80)); | |||
} | |||
function playWin() { | |||
if (!sfxEnabled) return; | |||
const m = [{f:523.25,d:0.15},{f:523.25,d:0.15},{f:523.25,d:0.15},{f:523.25,d:0.4},{f:415.30,d:0.4},{f:466.16,d:0.4},{f:523.25,d:0.3},{f:466.16,d:0.15},{f:523.25,d:0.6}]; | |||
let t = 0; | |||
m.forEach(n => { setTimeout(() => playNote(n.f, n.d, 'square'), t); t += n.d * 500; }); | |||
} | |||
function playLose() { | |||
if (!sfxEnabled) return; | |||
[392, 369.99, 349.23, 329.63, 293.66].forEach((f, i) => setTimeout(() => playNote(f, 0.3, 'sine'), i * 200)); | |||
} | |||
function playMusicNote(frequency, duration, type) { | |||
if (!audioContext || !musicPlaying) return; | |||
const osc = audioContext.createOscillator(); | |||
const g = audioContext.createGain(); | |||
osc.type = type; | |||
osc.frequency.setValueAtTime(frequency, audioContext.currentTime); | |||
g.gain.setValueAtTime(0.1, audioContext.currentTime); | |||
g.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + duration); | |||
osc.connect(g); | |||
g.connect(musicGain); | |||
osc.start(); | |||
osc.stop(audioContext.currentTime + duration); | |||
} | |||
function playMusicLoop() { | |||
if (!musicPlaying || !audioContext) return; | |||
const bass = [{f:130.81,d:0.5},{f:146.83,d:0.5},{f:164.81,d:0.5},{f:174.61,d:0.5},{f:196.00,d:0.5},{f:174.61,d:0.5},{f:164.81,d:0.5},{f:146.83,d:0.5}]; | |||
const mel = [{f:523.25,d:0.25},{f:587.33,d:0.25},{f:659.25,d:0.5},{f:698.46,d:0.25},{f:783.99,d:0.75},{f:659.25,d:0.5},{f:523.25,d:0.5},{f:587.33,d:0.5}]; | |||
let t = 0; | |||
bass.forEach(n => { setTimeout(() => { if(musicPlaying) playMusicNote(n.f, n.d*0.9, 'triangle'); }, t); t += n.d*500; }); | |||
let mt = 250; | |||
mel.forEach(n => { setTimeout(() => { if(musicPlaying) playMusicNote(n.f, n.d*0.8, 'sine'); }, mt); mt += n.d*500; }); | |||
setTimeout(() => { if(musicPlaying) playMusicLoop(); }, 4000); | |||
} | |||
function startMusic() { | |||
if (!audioContext || musicPlaying || !musicEnabled) return; | |||
musicPlaying = true; | |||
playMusicLoop(); | |||
} | |||
function stopMusic() { musicPlaying = false; } | |||
WON.toggleMusic = function() { | |||
initAudio(); | |||
musicEnabled = !musicEnabled; | |||
const btn = document.getElementById('wonMusicToggle'); | |||
if (musicEnabled) { btn.textContent = '🎵 Music ON'; btn.className = 'on'; startMusic(); } | |||
else { btn.textContent = '🔇 Music OFF'; btn.className = 'off'; stopMusic(); } | |||
}; | |||
WON.toggleSfx = function() { | |||
initAudio(); | |||
sfxEnabled = !sfxEnabled; | |||
const btn = document.getElementById('wonSfxToggle'); | |||
btn.textContent = sfxEnabled ? '🔊 SFX ON' : '🔇 SFX OFF'; | |||
btn.className = sfxEnabled ? 'on' : 'off'; | |||
}; | |||
WON.setMusicVolume = function(v) { if (musicGain) musicGain.gain.value = v / 100; }; | |||
WON.setSfxVolume = function(v) { if (sfxGain) sfxGain.gain.value = v / 100; }; | |||
function drawWheel() { | |||
const svg = document.getElementById('wonWheel'); | |||
} | svg.innerHTML = ''; | ||
const segAngle = 360 / WHEEL_SEGMENTS.length; | |||
WHEEL_SEGMENTS.forEach((seg, i) => { | |||
const sa = i * segAngle, ea = (i+1) * segAngle; | |||
const sr = (sa-90)*Math.PI/180, er = (ea-90)*Math.PI/180; | |||
const x1 = 100+90*Math.cos(sr), y1 = 100+90*Math.sin(sr); | |||
const x2 = 100+90*Math.cos(er), y2 = 100+90*Math.sin(er); | |||
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); | |||
path.setAttribute('d', `M 100 100 L ${x1} ${y1} A 90 90 0 0 1 ${x2} ${y2} Z`); | |||
path.setAttribute('fill', seg.color); | |||
path.setAttribute('stroke', '#fff'); | |||
path.setAttribute('stroke-width', '2'); | |||
svg.appendChild(path); | |||
const ma = ((sa+ea)/2-90)*Math.PI/180; | |||
const tx = 100+60*Math.cos(ma), ty = 100+60*Math.sin(ma); | |||
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); | |||
text.setAttribute('x', tx); | |||
text.setAttribute('y', ty); | |||
text.setAttribute('fill', '#fff'); | |||
text.setAttribute('font-size', typeof seg.value === 'number' ? '10' : '6'); | |||
text.setAttribute('font-weight', 'bold'); | |||
text.setAttribute('text-anchor', 'middle'); | |||
text.setAttribute('dominant-baseline', 'middle'); | |||
text.setAttribute('transform', `rotate(${(sa+ea)/2}, ${tx}, ${ty})`); | |||
text.textContent = typeof seg.value === 'number' ? `$${seg.value}` : seg.value; | |||
svg.appendChild(text); | |||
}); | |||
const c = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); | |||
c.setAttribute('cx', '100'); c.setAttribute('cy', '100'); c.setAttribute('r', '20'); | |||
c.setAttribute('fill', '#ffd700'); c.setAttribute('stroke', '#fff'); c.setAttribute('stroke-width', '3'); | |||
svg.appendChild(c); | |||
} | |||
function renderPuzzle() { | |||
const cont = document.getElementById('wonLetterTiles'); | |||
cont.innerHTML = ''; | |||
currentQuestion.answer.toUpperCase().split('').forEach(ch => { | |||
const tile = document.createElement('div'); | |||
tile.className = 'letter-tile'; | |||
if (ch === ' ') tile.classList.add('space'); | |||
else if (revealedLetters.has(ch) || !/[A-Z]/.test(ch)) { tile.classList.add('revealed'); tile.textContent = ch; } | |||
else tile.classList.add('hidden'); | |||
cont.appendChild(tile); | |||
}); | |||
document.getElementById('wonCategory').textContent = currentQuestion.category; | |||
document.getElementById('wonClue').textContent = currentQuestion.clue; | |||
} | |||
function renderLetterButtons() { | |||
const cc = document.getElementById('wonConsonants'), vc = document.getElementById('wonVowels'); | |||
cc.innerHTML = ''; vc.innerHTML = ''; | |||
CONSONANTS.forEach(l => { | |||
const btn = document.createElement('button'); | |||
btn.className = 'letter-btn consonant'; | |||
btn.textContent = l; | |||
btn.disabled = revealedLetters.has(l); | |||
if (gamePhase !== 'guess') btn.classList.add('inactive'); | |||
btn.onclick = () => guessLetter(l); | |||
cc.appendChild(btn); | |||
}); | |||
VOWELS.forEach(v => { | |||
const btn = document.createElement('button'); | |||
btn.className = 'letter-btn vowel'; | |||
btn.textContent = v; | |||
btn.disabled = revealedLetters.has(v) || roundScore < 250; | |||
if (gamePhase !== 'spin') btn.classList.add('inactive'); | |||
btn.onclick = () => buyVowel(v); | |||
vc.appendChild(btn); | |||
}); | |||
} | |||
} | |||
function updateUI() { | |||
document.getElementById('wonRoundScore').textContent = `$${roundScore}`; | |||
document.getElementById('wonTotalScore').textContent = `$${totalScore}`; | |||
const spinBtn = document.getElementById('wonSpinBtn'); | |||
spinBtn.disabled = spinning || gamePhase !== 'spin'; | |||
spinBtn.textContent = spinning ? '🎡 Spinning...' : '🎡 Spin Wheel'; | |||
document.getElementById('wonSolveBtn').disabled = gamePhase !== 'spin'; | |||
renderLetterButtons(); | |||
} | |||
function setMessage(msg, wv) { | |||
document.getElementById('wonMessage').textContent = msg; | |||
const wve = document.getElementById('wonWheelValue'); | |||
if (wv !== null && wv !== undefined) { wve.textContent = `Current: $${wv}`; wve.classList.remove('hidden'); } | |||
else wve.classList.add('hidden'); | |||
} | |||
WON.startGame = function() { | |||
initAudio(); | |||
if (musicEnabled) startMusic(); | |||
document.getElementById('wonStartScreen').classList.add('hidden'); | |||
document.getElementById('wonGameScreen').classList.remove('hidden'); | |||
drawWheel(); | |||
startNewRound(); | |||
}; | |||
function startNewRound() { | |||
let avail = QUESTIONS.filter((_, i) => !usedQuestions.includes(i)); | |||
if (avail.length === 0) { usedQuestions = []; avail = QUESTIONS; } | |||
const idx = QUESTIONS.indexOf(avail[Math.floor(Math.random() * avail.length)]); | |||
usedQuestions.push(idx); | |||
currentQuestion = QUESTIONS[idx]; | |||
revealedLetters = new Set(); | |||
roundScore = 0; | |||
} | currentWheelValue = null; | ||
gamePhase = 'spin'; | |||
hintUsed = false; | |||
document.getElementById('wonHintBox').classList.add('hidden'); | |||
document.getElementById('wonHintBtn').disabled = false; | |||
document.getElementById('wonResultScreen').classList.add('hidden'); | |||
document.getElementById('wonWheelContainer').classList.remove('hidden'); | |||
document.getElementById('wonLetterBoard').classList.remove('hidden'); | |||
document.getElementById('wonActionButtons').classList.remove('hidden'); | |||
document.getElementById('wonSolveContainer').classList.add('hidden'); | |||
renderPuzzle(); | |||
updateUI(); | |||
setMessage('Spin the wheel!'); | |||
} | |||
WON.spinWheel = function() { | |||
if (spinning || gamePhase !== 'spin') return; | |||
initAudio(); | |||
spinning = true; | |||
setMessage('Spinning...'); | |||
updateUI(); | |||
playWheelSpin(3000); | |||
const spins = 3 + Math.random() * 3; | |||
const segAngle = 360 / WHEEL_SEGMENTS.length; | |||
const randSeg = Math.floor(Math.random() * WHEEL_SEGMENTS.length); | |||
wheelRotation += (spins * 360) + (randSeg * segAngle); | |||
document.getElementById('wonWheel').style.transform = `rotate(${wheelRotation}deg)`; | |||
currentWheelValue = | setTimeout(() => { | ||
const seg = WHEEL_SEGMENTS[randSeg]; | |||
currentWheelValue = seg.value; | |||
spinning = false; | |||
if (seg.value === 'BANKRUPT') { roundScore = 0; setMessage('BANKRUPT! You lost your round earnings. Spin again!'); gamePhase = 'spin'; playBankrupt(); } | |||
else if (seg.value === 'LOSE TURN') { setMessage('Lost your turn! Spin again.'); gamePhase = 'spin'; playWrong(); } | |||
else { setMessage(`$${seg.value}! Pick a consonant.`, seg.value); gamePhase = 'guess'; playNote(880, 0.1, 'sine'); } | |||
updateUI(); | updateUI(); | ||
}, 3000); | |||
}; | |||
function guessLetter(letter) { | |||
if (gamePhase !== 'guess' || revealedLetters.has(letter)) return; | |||
const ans = currentQuestion.answer.toUpperCase(); | |||
const cnt = (ans.match(new RegExp(letter, 'g')) || []).length; | |||
revealedLetters.add(letter); | |||
if (cnt > 0) { const e = currentWheelValue * cnt; roundScore += e; setMessage(`Yes! ${cnt} ${letter}'s for $${e}! Spin or solve.`); playCorrect(); } | |||
else { setMessage(`No ${letter}'s. Spin the wheel!`); playWrong(); } | |||
gamePhase = 'spin'; | |||
renderPuzzle(); | |||
updateUI(); | |||
checkPuzzleComplete(); | |||
} | |||
function buyVowel(vowel) { | |||
if (gamePhase !== 'spin' || revealedLetters.has(vowel) || roundScore < 250) return; | |||
roundScore -= 250; | |||
const ans = currentQuestion.answer.toUpperCase(); | |||
const cnt = (ans.match(new RegExp(vowel, 'g')) || []).length; | |||
revealedLetters.add(vowel); | |||
if (cnt > 0) { setMessage(`Yes! ${cnt} ${vowel}'s! Spin or solve.`); playCorrect(); } | |||
else { setMessage(`No ${vowel}'s. Spin the wheel!`); playWrong(); } | |||
renderPuzzle(); | |||
updateUI(); | |||
checkPuzzleComplete(); | |||
} | |||
} | |||
function checkPuzzleComplete() { | |||
const ans = currentQuestion.answer.toUpperCase(); | |||
const unique = new Set(ans.replace(/[^A-Z]/g, '').split('')); | |||
if ([...unique].every(l => revealedLetters.has(l))) { | |||
totalScore += roundScore; | |||
setMessage(`Puzzle Complete! You earned $${roundScore}!`); | |||
showResult(true); | |||
playWin(); | |||
} | } | ||
} | |||
WON.attemptSolve = function() { | |||
if (gamePhase !== 'spin') return; | |||
gamePhase = 'solve'; | |||
document.getElementById('wonSolveContainer').classList.remove('hidden'); | |||
document.getElementById('wonActionButtons').classList.add('hidden'); | |||
document.getElementById('wonSolveInput').focus(); | |||
setMessage('Type your answer:'); | |||
}; | |||
WON.submitSolve = function() { | |||
const guess = document.getElementById('wonSolveInput').value.toUpperCase().trim(); | |||
const ans = currentQuestion.answer.toUpperCase().trim(); | |||
if (guess === ans) { totalScore += roundScore + 500; setMessage(`Correct! "${ans}" - You earned $${roundScore + 500}!`); showResult(true); playWin(); } | |||
else { setMessage(`Wrong! The answer was "${ans}".`); showResult(false); playLose(); } | |||
document.getElementById('wonSolveInput').value = ''; | |||
}; | |||
WON.cancelSolve = function() { | |||
gamePhase = 'spin'; | |||
document.getElementById('wonSolveContainer').classList.add('hidden'); | |||
document.getElementById('wonActionButtons').classList.remove('hidden'); | |||
setMessage('Spin the wheel!'); | |||
}; | |||
WON.useHint = function() { | |||
if (hintUsed) return; | |||
hintUsed = true; | |||
roundScore = Math.max(0, roundScore - 200); | |||
document.getElementById('wonHintText').textContent = currentQuestion.hint; | |||
document.getElementById('wonHintBox').classList.remove('hidden'); | |||
document.getElementById('wonHintBtn').disabled = true; | |||
setMessage(`Hint used (-$200): ${currentQuestion.hint}`); | |||
updateUI(); | |||
playNote(600, 0.05, 'square'); | |||
}; | |||
function showResult(won) { | |||
gamePhase = won ? 'won' : 'lost'; | |||
document.getElementById('wonWheelContainer').classList.add('hidden'); | |||
document.getElementById('wonLetterBoard').classList.add('hidden'); | |||
} | document.getElementById('wonActionButtons').classList.add('hidden'); | ||
document.getElementById('wonSolveContainer').classList.add('hidden'); | |||
const rs = document.getElementById('wonResultScreen'); | |||
rs.classList.remove('hidden', 'won', 'lost'); | |||
rs.classList.add(won ? 'won' : 'lost'); | |||
document.getElementById('wonResultTitle').textContent = won ? '🎉 Congratulations!' : '😔 Better Luck Next Time!'; | |||
document.getElementById('wonFinalScore').textContent = `$${totalScore}`; | |||
} | |||
WON.nextPuzzle = function() { playNote(600, 0.05, 'square'); startNewRound(); }; | |||
WON.newGame = function() { playNote(600, 0.05, 'square'); totalScore = 0; usedQuestions = []; startNewRound(); }; | |||
document.getElementById('wonSolveInput').addEventListener('keypress', function(e) { if (e.key === 'Enter') WON.submitSolve(); }); | |||
})(); | |||
</script> | |||
</includeonly> | </includeonly> | ||
Revision as of 00:33, 11 January 2026
This widget displays the Wheel of Nursing pharmacology game.
Usage
{{#widget:WheelOfNursing}}
Parameters
This widget does not accept any parameters.