slashvibe-mcp 0.3.21 → 0.3.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +280 -47
- package/auto-update.js +10 -15
- package/config.js +36 -31
- package/crypto.js +1 -6
- package/debug.js +12 -0
- package/discord.js +19 -19
- package/eslint.config.js +54 -0
- package/index.js +217 -207
- package/intelligence/index.js +2 -9
- package/intelligence/infer.js +10 -16
- package/intelligence/patterns.js +23 -18
- package/intelligence/proactive.js +16 -15
- package/intelligence/serendipity.js +57 -20
- package/memory.js +13 -8
- package/migrate-v2.js +72 -0
- package/notification-emitter.js +2 -2
- package/notify.js +39 -14
- package/package.json +28 -29
- package/post-install.js +141 -0
- package/presence.js +2 -2
- package/prompts.js +5 -9
- package/protocol/index.js +123 -87
- package/protocol/telegram-commands.js +36 -37
- package/store/api.js +358 -529
- package/store/local.js +9 -10
- package/store/profiles.js +48 -192
- package/store/reservations.js +2 -9
- package/store/skills.js +69 -71
- package/store/sqlite.js +355 -0
- package/test-skills-bootstrap.js +20 -0
- package/test-v2-integration.js +385 -0
- package/tools/_actions.js +48 -387
- package/tools/_connection-queue.js +45 -56
- package/tools/_discovery-enhanced.js +52 -57
- package/tools/_discovery.js +87 -185
- package/tools/{l2-status.js → _experimental/l2-status.js} +68 -70
- package/tools/{shipback.js → _experimental/shipback.js} +4 -3
- package/tools/_proactive-discovery.js +60 -73
- package/tools/_shared/index.js +41 -64
- package/tools/admin-inbox.js +10 -15
- package/tools/agents.js +1 -1
- package/tools/artifact-create.js +13 -23
- package/tools/artifact-view.js +4 -4
- package/tools/{_deprecated/back.js → back.js} +1 -1
- package/tools/bye.js +3 -5
- package/tools/consent.js +2 -2
- package/tools/context.js +9 -10
- package/tools/crossword.js +3 -2
- package/tools/discover.js +94 -356
- package/tools/dm.js +27 -86
- package/tools/doctor.js +12 -41
- package/tools/drawing.js +34 -20
- package/tools/echo.js +11 -11
- package/tools/feed.js +30 -58
- package/tools/follow.js +64 -187
- package/tools/{_deprecated/forget.js → forget.js} +4 -7
- package/tools/game.js +144 -48
- package/tools/handoff.js +6 -8
- package/tools/help.js +3 -3
- package/tools/idea.js +15 -27
- package/tools/inbox.js +121 -293
- package/tools/init.js +54 -151
- package/tools/invite.js +8 -21
- package/tools/migrate.js +27 -24
- package/tools/multiplayer-game.js +50 -40
- package/tools/{_deprecated/mute.js → mute.js} +4 -3
- package/tools/notifications.js +58 -48
- package/tools/observe.js +12 -15
- package/tools/onboarding.js +8 -11
- package/tools/open.js +13 -144
- package/tools/party-game.js +23 -12
- package/tools/patterns.js +2 -1
- package/tools/ping.js +5 -7
- package/tools/react.js +28 -30
- package/tools/{_deprecated/recall.js → recall.js} +5 -10
- package/tools/release.js +4 -2
- package/tools/{_deprecated/remember.js → remember.js} +4 -6
- package/tools/report.js +2 -2
- package/tools/request.js +6 -26
- package/tools/reserve.js +1 -1
- package/tools/session-fork.js +97 -0
- package/tools/session-save.js +109 -0
- package/tools/settings.js +30 -99
- package/tools/ship.js +74 -56
- package/tools/{_deprecated/skills-exchange.js → skills-exchange.js} +38 -39
- package/tools/social-inbox.js +22 -28
- package/tools/social-post.js +24 -27
- package/tools/solo-game.js +54 -46
- package/tools/start.js +14 -148
- package/tools/status.js +21 -68
- package/tools/submit.js +4 -2
- package/tools/suggest-tags.js +36 -33
- package/tools/summarize.js +19 -16
- package/tools/tag-suggestions.js +72 -73
- package/tools/test.js +1 -1
- package/tools/{_deprecated/tictactoe.js → tictactoe.js} +26 -26
- package/tools/token.js +4 -4
- package/tools/update.js +1 -2
- package/tools/watch.js +132 -112
- package/tools/who.js +20 -40
- package/tools/{_deprecated/wordassociation.js → wordassociation.js} +23 -20
- package/tools/workshop-buddy.js +52 -53
- package/tools/x-mentions.js +0 -1
- package/tools/x-reply.js +0 -1
- package/twitter.js +14 -20
- package/version.json +8 -10
- package/webhook-runner.js +132 -0
- package/auth-store.js +0 -148
- package/bridges/bridge-monitor.js +0 -388
- package/bridges/discord-bot.js +0 -431
- package/bridges/farcaster.js +0 -299
- package/bridges/telegram.js +0 -261
- package/bridges/webhook-health.js +0 -420
- package/bridges/webhook-server.js +0 -437
- package/bridges/whatsapp.js +0 -441
- package/bridges/x-webhook.js +0 -423
- package/games/arcade.js +0 -406
- package/games/chess.js +0 -451
- package/games/colorguess.js +0 -343
- package/games/crossword-words.js +0 -171
- package/games/crossword.js +0 -461
- package/games/drawing.js +0 -347
- package/games/gameroulette.js +0 -300
- package/games/gamerouter.js +0 -336
- package/games/gamestatus.js +0 -337
- package/games/guessnumber.js +0 -209
- package/games/hangman.js +0 -279
- package/games/memory.js +0 -338
- package/games/multiplayer-tictactoe.js +0 -389
- package/games/pixelart.js +0 -399
- package/games/quickduel.js +0 -354
- package/games/riddle.js +0 -371
- package/games/rockpaperscissors.js +0 -291
- package/games/snake.js +0 -406
- package/games/storybuilder.js +0 -343
- package/games/tictactoe.js +0 -345
- package/games/twentyquestions.js +0 -286
- package/games/twotruths.js +0 -207
- package/games/werewolf.js +0 -508
- package/games/wordassociation.js +0 -247
- package/games/wordchain.js +0 -135
- package/intelligence/interests.js +0 -369
- package/setup.js +0 -480
- package/smart-inbox.js +0 -276
- package/tools/_deprecated/auto-suggest-connections.js +0 -304
- package/tools/_deprecated/bootstrap-skills.js +0 -231
- package/tools/_deprecated/bridge-dashboard.js +0 -342
- package/tools/_deprecated/bridge-health.js +0 -400
- package/tools/_deprecated/bridge-live.js +0 -384
- package/tools/_deprecated/bridges.js +0 -383
- package/tools/_deprecated/colorguess.js +0 -281
- package/tools/_deprecated/discover-insights.js +0 -379
- package/tools/_deprecated/discover-momentum.js +0 -256
- package/tools/_deprecated/discovery-analytics.js +0 -345
- package/tools/_deprecated/discovery-auto-suggest.js +0 -275
- package/tools/_deprecated/discovery-bootstrap.js +0 -267
- package/tools/_deprecated/discovery-daily.js +0 -375
- package/tools/_deprecated/discovery-dashboard.js +0 -385
- package/tools/_deprecated/discovery-digest.js +0 -314
- package/tools/_deprecated/discovery-hub.js +0 -357
- package/tools/_deprecated/discovery-insights.js +0 -384
- package/tools/_deprecated/discovery-momentum.js +0 -281
- package/tools/_deprecated/discovery-monitor.js +0 -319
- package/tools/_deprecated/discovery-proactive.js +0 -300
- package/tools/_deprecated/draw.js +0 -317
- package/tools/_deprecated/farcaster.js +0 -307
- package/tools/_deprecated/games-catalog.js +0 -376
- package/tools/_deprecated/games.js +0 -313
- package/tools/_deprecated/guessnumber.js +0 -194
- package/tools/_deprecated/hangman.js +0 -129
- package/tools/_deprecated/multiplayer-tictactoe.js +0 -303
- package/tools/_deprecated/riddle.js +0 -240
- package/tools/_deprecated/run-bootstrap.js +0 -69
- package/tools/_deprecated/skills-analytics.js +0 -349
- package/tools/_deprecated/skills-bootstrap.js +0 -301
- package/tools/_deprecated/skills-dashboard.js +0 -268
- package/tools/_deprecated/skills.js +0 -380
- package/tools/_deprecated/smart-intro.js +0 -353
- package/tools/_deprecated/storybuilder.js +0 -331
- package/tools/_deprecated/telegram-bot.js +0 -183
- package/tools/_deprecated/telegram-setup.js +0 -214
- package/tools/_deprecated/twentyquestions.js +0 -143
- package/tools/_shared.js +0 -234
- package/tools/_work-context.js +0 -338
- package/tools/_work-context.manual-test.js +0 -199
- package/tools/_work-context.test.js +0 -260
- package/tools/activity.js +0 -220
- package/tools/agent-treasury.js +0 -288
- package/tools/analytics.js +0 -191
- package/tools/approve.js +0 -197
- package/tools/arcade.js +0 -173
- package/tools/artifacts-price.js +0 -107
- package/tools/ask-expert.js +0 -160
- package/tools/available.js +0 -120
- package/tools/become-expert.js +0 -150
- package/tools/broadcast.js +0 -325
- package/tools/chat.js +0 -202
- package/tools/collaborative-drawing.js +0 -286
- package/tools/connection-status.js +0 -178
- package/tools/earnings.js +0 -126
- package/tools/friends.js +0 -207
- package/tools/genesis.js +0 -233
- package/tools/gig-browse.js +0 -206
- package/tools/gig-complete.js +0 -144
- package/tools/health.js +0 -87
- package/tools/leaderboard.js +0 -117
- package/tools/lib/git-apply.js +0 -206
- package/tools/lib/git-bundle.js +0 -407
- package/tools/mint.js +0 -377
- package/tools/plan.js +0 -225
- package/tools/profile.js +0 -219
- package/tools/proof-of-work.js +0 -144
- package/tools/pulse.js +0 -218
- package/tools/reply.js +0 -166
- package/tools/reputation.js +0 -175
- package/tools/schedule.js +0 -367
- package/tools/search-messages.js +0 -123
- package/tools/session.js +0 -467
- package/tools/session_price.js +0 -128
- package/tools/smart-check.js +0 -201
- package/tools/social-processor.js +0 -445
- package/tools/streak.js +0 -147
- package/tools/stuck.js +0 -297
- package/tools/subscribe.js +0 -148
- package/tools/subscriptions.js +0 -134
- package/tools/tip.js +0 -193
- package/tools/wallet.js +0 -269
- package/tools/webhook-test.js +0 -388
- package/tools/withdraw.js +0 -145
- package/tools/work-summary.js +0 -96
- package/tools/workshop.js +0 -327
- /package/tools/{l2-bridge.js → _experimental/l2-bridge.js} +0 -0
- /package/tools/{l2.js → _experimental/l2.js} +0 -0
- /package/tools/{_deprecated/away.js → away.js} +0 -0
package/games/riddle.js
DELETED
|
@@ -1,371 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Riddle Game implementation for /vibe
|
|
3
|
-
* Challenge your mind with classic riddles and brain teasers!
|
|
4
|
-
* Features multiple difficulty levels and hint system
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// Riddle database organized by difficulty
|
|
8
|
-
const RIDDLES = {
|
|
9
|
-
easy: [
|
|
10
|
-
{
|
|
11
|
-
question: "What has keys but no locks, space but no room, and you can enter but not go inside?",
|
|
12
|
-
answer: "keyboard",
|
|
13
|
-
hints: ["It's something you use with computers", "It has letters and numbers on it", "You type on it"],
|
|
14
|
-
category: "technology"
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
question: "What gets wet while drying?",
|
|
18
|
-
answer: "towel",
|
|
19
|
-
hints: ["It's found in bathrooms", "You use it after a shower", "It absorbs water"],
|
|
20
|
-
category: "household"
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
question: "What goes up but never comes down?",
|
|
24
|
-
answer: "age",
|
|
25
|
-
hints: ["It's something everyone has", "It changes every year", "Time affects it"],
|
|
26
|
-
category: "abstract"
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
question: "What has hands but cannot clap?",
|
|
30
|
-
answer: "clock",
|
|
31
|
-
hints: ["You look at it to tell time", "It's usually round", "It has numbers on it"],
|
|
32
|
-
category: "objects"
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
question: "What can you break without touching it?",
|
|
36
|
-
answer: "promise",
|
|
37
|
-
hints: ["It's not a physical object", "People make these to each other", "Trust is involved"],
|
|
38
|
-
category: "abstract"
|
|
39
|
-
}
|
|
40
|
-
],
|
|
41
|
-
|
|
42
|
-
medium: [
|
|
43
|
-
{
|
|
44
|
-
question: "I have cities, but no houses. I have mountains, but no trees. I have water, but no fish. What am I?",
|
|
45
|
-
answer: "map",
|
|
46
|
-
hints: ["I show locations", "I'm flat and can be folded", "Travelers use me for directions"],
|
|
47
|
-
category: "objects"
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
question: "The more you take, the more you leave behind. What am I?",
|
|
51
|
-
answer: "footsteps",
|
|
52
|
-
hints: ["You make me when you walk", "I'm left on the ground", "Animals make me too"],
|
|
53
|
-
category: "abstract"
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
question: "What belongs to you but is used more by others?",
|
|
57
|
-
answer: "name",
|
|
58
|
-
hints: ["It identifies you", "People call you by it", "It's on your ID"],
|
|
59
|
-
category: "abstract"
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
question: "I'm light as a feather, yet the strongest person can't hold me for 5 minutes. What am I?",
|
|
63
|
-
answer: "breath",
|
|
64
|
-
hints: ["You do it automatically", "It's essential for life", "You can hold it temporarily"],
|
|
65
|
-
category: "body"
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
question: "What runs around a house but doesn't move?",
|
|
69
|
-
answer: "fence",
|
|
70
|
-
hints: ["It surrounds property", "It marks boundaries", "It's often made of wood or metal"],
|
|
71
|
-
category: "household"
|
|
72
|
-
}
|
|
73
|
-
],
|
|
74
|
-
|
|
75
|
-
hard: [
|
|
76
|
-
{
|
|
77
|
-
question: "I speak without a mouth and hear without ears. I have no body, but come alive with wind. What am I?",
|
|
78
|
-
answer: "echo",
|
|
79
|
-
hints: ["You hear me in mountains", "I repeat what you say", "I'm a sound phenomenon"],
|
|
80
|
-
category: "nature"
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
question: "What can travel around the world while staying in a corner?",
|
|
84
|
-
answer: "stamp",
|
|
85
|
-
hints: ["I'm found on mail", "I have pictures and values", "I help letters reach destinations"],
|
|
86
|
-
category: "objects"
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
question: "I have a golden head and a golden tail, but no body. What am I?",
|
|
90
|
-
answer: "coin",
|
|
91
|
-
hints: ["I have value", "You find me in wallets", "I'm made of metal"],
|
|
92
|
-
category: "objects"
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
question: "What disappears as soon as you say its name?",
|
|
96
|
-
answer: "silence",
|
|
97
|
-
hints: ["It's the absence of something", "Libraries try to maintain it", "Speaking breaks it"],
|
|
98
|
-
category: "abstract"
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
question: "I can be cracked, made, told, and played. What am I?",
|
|
102
|
-
answer: "joke",
|
|
103
|
-
hints: ["I make people laugh", "Comedians tell me", "I can be funny or bad"],
|
|
104
|
-
category: "entertainment"
|
|
105
|
-
}
|
|
106
|
-
],
|
|
107
|
-
|
|
108
|
-
expert: [
|
|
109
|
-
{
|
|
110
|
-
question: "What has roots as nobody sees, is taller than trees, up, up it goes, and yet never grows?",
|
|
111
|
-
answer: "mountain",
|
|
112
|
-
hints: ["I touch the sky", "I'm made of rock", "Climbers try to reach my peak"],
|
|
113
|
-
category: "nature"
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
question: "Alive without breath, as cold as death, never thirsty, ever drinking, all in mail never clinking.",
|
|
117
|
-
answer: "fish",
|
|
118
|
-
hints: ["I live underwater", "I have scales", "I breathe through gills"],
|
|
119
|
-
category: "animals"
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
question: "What is so fragile that saying its name breaks it?",
|
|
123
|
-
answer: "silence",
|
|
124
|
-
hints: ["It's the absence of sound", "Libraries cherish it", "Even a whisper destroys it"],
|
|
125
|
-
category: "abstract"
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
question: "I am not seen, cannot be felt, cannot be heard, cannot be smelt. I lie behind stars and under hills, and empty holes I fill. What am I?",
|
|
129
|
-
answer: "darkness",
|
|
130
|
-
hints: ["I exist without light", "I'm everywhere at night", "I hide things from view"],
|
|
131
|
-
category: "abstract"
|
|
132
|
-
}
|
|
133
|
-
]
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
// Create initial riddle game state
|
|
137
|
-
function createInitialRiddleState(difficulty = 'medium') {
|
|
138
|
-
const availableRiddles = RIDDLES[difficulty] || RIDDLES.medium;
|
|
139
|
-
const selectedRiddle = availableRiddles[Math.floor(Math.random() * availableRiddles.length)];
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
difficulty: difficulty,
|
|
143
|
-
currentRiddle: selectedRiddle,
|
|
144
|
-
guesses: [],
|
|
145
|
-
hintsUsed: 0,
|
|
146
|
-
moves: 0,
|
|
147
|
-
gameOver: false,
|
|
148
|
-
won: false,
|
|
149
|
-
startTime: Date.now(),
|
|
150
|
-
maxHints: selectedRiddle.hints.length
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Make a guess at the riddle
|
|
155
|
-
function makeGuess(gameState, guess) {
|
|
156
|
-
const { currentRiddle, guesses, moves, gameOver } = gameState;
|
|
157
|
-
|
|
158
|
-
// Validate input
|
|
159
|
-
if (!guess || typeof guess !== 'string') {
|
|
160
|
-
return { error: 'Please enter your guess!' };
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (gameOver) {
|
|
164
|
-
return { error: 'Game is over! Start a new riddle to play again.' };
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Normalize guess and answer for comparison
|
|
168
|
-
const normalizedGuess = guess.toLowerCase().trim();
|
|
169
|
-
const normalizedAnswer = currentRiddle.answer.toLowerCase().trim();
|
|
170
|
-
|
|
171
|
-
// Check if already guessed
|
|
172
|
-
if (guesses.some(g => g.toLowerCase() === normalizedGuess)) {
|
|
173
|
-
return { error: `You already guessed "${guess}". Try something different!` };
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const newGuesses = [...guesses, guess];
|
|
177
|
-
const newMoves = moves + 1;
|
|
178
|
-
const won = normalizedGuess === normalizedAnswer;
|
|
179
|
-
const isGameOver = won;
|
|
180
|
-
|
|
181
|
-
// Calculate final time if won
|
|
182
|
-
const endTime = won ? Date.now() : null;
|
|
183
|
-
const timeToSolve = won ? Math.round((endTime - gameState.startTime) / 1000) : null;
|
|
184
|
-
|
|
185
|
-
const newGameState = {
|
|
186
|
-
...gameState,
|
|
187
|
-
guesses: newGuesses,
|
|
188
|
-
moves: newMoves,
|
|
189
|
-
gameOver: isGameOver,
|
|
190
|
-
won: won,
|
|
191
|
-
lastGuess: guess,
|
|
192
|
-
endTime: endTime,
|
|
193
|
-
timeToSolve: timeToSolve
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
return { success: true, gameState: newGameState };
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Get a hint for the current riddle
|
|
200
|
-
function getHint(gameState) {
|
|
201
|
-
const { currentRiddle, hintsUsed, gameOver } = gameState;
|
|
202
|
-
|
|
203
|
-
if (gameOver) {
|
|
204
|
-
return { error: 'Game is over! The answer was already revealed.' };
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (hintsUsed >= currentRiddle.hints.length) {
|
|
208
|
-
return { error: 'No more hints available! You\'ve used all of them.' };
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const hint = currentRiddle.hints[hintsUsed];
|
|
212
|
-
const newGameState = {
|
|
213
|
-
...gameState,
|
|
214
|
-
hintsUsed: hintsUsed + 1,
|
|
215
|
-
lastHint: hint
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
return { success: true, gameState: newGameState, hint: hint };
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Skip to next riddle (same difficulty)
|
|
222
|
-
function skipRiddle(gameState) {
|
|
223
|
-
const { difficulty, currentRiddle } = gameState;
|
|
224
|
-
const availableRiddles = RIDDLES[difficulty] || RIDDLES.medium;
|
|
225
|
-
|
|
226
|
-
// Find a different riddle
|
|
227
|
-
let newRiddle;
|
|
228
|
-
do {
|
|
229
|
-
newRiddle = availableRiddles[Math.floor(Math.random() * availableRiddles.length)];
|
|
230
|
-
} while (newRiddle.question === currentRiddle.question && availableRiddles.length > 1);
|
|
231
|
-
|
|
232
|
-
return createInitialRiddleState(difficulty);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Format riddle display
|
|
236
|
-
function formatRiddleDisplay(gameState) {
|
|
237
|
-
const { difficulty, currentRiddle, guesses, hintsUsed, moves, gameOver, won, timeToSolve, lastGuess, lastHint } = gameState;
|
|
238
|
-
|
|
239
|
-
const difficultyEmoji = {
|
|
240
|
-
'easy': '🟢',
|
|
241
|
-
'medium': '🟡',
|
|
242
|
-
'hard': '🔴',
|
|
243
|
-
'expert': '💀'
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
let display = `🧩 **Riddle Challenge** ${difficultyEmoji[difficulty] || '🟡'} ${difficulty.toUpperCase()}\n\n`;
|
|
247
|
-
|
|
248
|
-
// Show the riddle question
|
|
249
|
-
display += `**The Riddle:**\n*${currentRiddle.question}*\n\n`;
|
|
250
|
-
|
|
251
|
-
// Show hints if any have been used
|
|
252
|
-
if (hintsUsed > 0) {
|
|
253
|
-
display += `**Hints used (${hintsUsed}/${currentRiddle.hints.length}):**\n`;
|
|
254
|
-
for (let i = 0; i < hintsUsed; i++) {
|
|
255
|
-
display += `${i + 1}. ${currentRiddle.hints[i]}\n`;
|
|
256
|
-
}
|
|
257
|
-
display += '\n';
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Show recent guess feedback
|
|
261
|
-
if (lastGuess && !won) {
|
|
262
|
-
display += `**Last guess:** "${lastGuess}" ❌\n`;
|
|
263
|
-
display += `*Not quite right, keep thinking!*\n\n`;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Show all previous guesses
|
|
267
|
-
if (guesses.length > 0 && !won) {
|
|
268
|
-
display += `**Your guesses:** ${guesses.join(', ')}\n\n`;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Show game result
|
|
272
|
-
if (gameOver) {
|
|
273
|
-
if (won) {
|
|
274
|
-
display += `🎉 **Congratulations!** \n`;
|
|
275
|
-
display += `**Answer:** ${currentRiddle.answer}\n`;
|
|
276
|
-
display += `**Solved in:** ${moves} guesses`;
|
|
277
|
-
if (timeToSolve) {
|
|
278
|
-
display += ` and ${timeToSolve} seconds`;
|
|
279
|
-
}
|
|
280
|
-
display += '\n';
|
|
281
|
-
|
|
282
|
-
// Performance feedback
|
|
283
|
-
if (moves === 1) {
|
|
284
|
-
display += '⭐ **Amazing!** First try! Are you a mind reader?';
|
|
285
|
-
} else if (moves <= 3) {
|
|
286
|
-
display += '🔥 **Excellent!** Great logical thinking!';
|
|
287
|
-
} else if (moves <= 5) {
|
|
288
|
-
display += '👍 **Well done!** You figured it out!';
|
|
289
|
-
} else {
|
|
290
|
-
display += '🎯 **You got it!** Persistence pays off!';
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
if (hintsUsed === 0) {
|
|
294
|
-
display += '\n💎 **Bonus:** Solved without hints! Impressive!';
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
} else {
|
|
298
|
-
display += `**Status:** Thinking... (${moves} guesses)\n`;
|
|
299
|
-
display += `**Hints available:** ${currentRiddle.hints.length - hintsUsed} remaining\n\n`;
|
|
300
|
-
display += '💭 *Take your time and think carefully!*';
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
return display;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Get available difficulties with descriptions
|
|
307
|
-
function getDifficultyInfo() {
|
|
308
|
-
return {
|
|
309
|
-
easy: {
|
|
310
|
-
description: '🟢 **EASY**: Simple riddles to warm up your brain',
|
|
311
|
-
riddles: RIDDLES.easy.length
|
|
312
|
-
},
|
|
313
|
-
medium: {
|
|
314
|
-
description: '🟡 **MEDIUM**: Classic riddles that require some thinking',
|
|
315
|
-
riddles: RIDDLES.medium.length
|
|
316
|
-
},
|
|
317
|
-
hard: {
|
|
318
|
-
description: '🔴 **HARD**: Challenging riddles for puzzle enthusiasts',
|
|
319
|
-
riddles: RIDDLES.hard.length
|
|
320
|
-
},
|
|
321
|
-
expert: {
|
|
322
|
-
description: '💀 **EXPERT**: Mind-bending riddles for the brave',
|
|
323
|
-
riddles: RIDDLES.expert.length
|
|
324
|
-
}
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// Get riddle statistics
|
|
329
|
-
function getRiddleStats() {
|
|
330
|
-
let totalRiddles = 0;
|
|
331
|
-
const byCategory = {};
|
|
332
|
-
|
|
333
|
-
Object.values(RIDDLES).forEach(difficultyRiddles => {
|
|
334
|
-
totalRiddles += difficultyRiddles.length;
|
|
335
|
-
difficultyRiddles.forEach(riddle => {
|
|
336
|
-
byCategory[riddle.category] = (byCategory[riddle.category] || 0) + 1;
|
|
337
|
-
});
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
return {
|
|
341
|
-
total: totalRiddles,
|
|
342
|
-
byDifficulty: Object.fromEntries(
|
|
343
|
-
Object.entries(RIDDLES).map(([diff, riddles]) => [diff, riddles.length])
|
|
344
|
-
),
|
|
345
|
-
byCategory
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// Get a random riddle for testing/preview
|
|
350
|
-
function getRandomRiddle(difficulty = null) {
|
|
351
|
-
if (difficulty && RIDDLES[difficulty]) {
|
|
352
|
-
const riddles = RIDDLES[difficulty];
|
|
353
|
-
return riddles[Math.floor(Math.random() * riddles.length)];
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// Random from all difficulties
|
|
357
|
-
const allRiddles = Object.values(RIDDLES).flat();
|
|
358
|
-
return allRiddles[Math.floor(Math.random() * allRiddles.length)];
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
module.exports = {
|
|
362
|
-
createInitialRiddleState,
|
|
363
|
-
makeGuess,
|
|
364
|
-
getHint,
|
|
365
|
-
skipRiddle,
|
|
366
|
-
formatRiddleDisplay,
|
|
367
|
-
getDifficultyInfo,
|
|
368
|
-
getRiddleStats,
|
|
369
|
-
getRandomRiddle,
|
|
370
|
-
RIDDLES
|
|
371
|
-
};
|
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rock Paper Scissors game implementation for /vibe
|
|
3
|
-
* Classic hand game with emoji display and best-of-series support
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Game choices and their emojis
|
|
7
|
-
const CHOICES = {
|
|
8
|
-
rock: { emoji: '🪨', beats: 'scissors', name: 'Rock' },
|
|
9
|
-
paper: { emoji: '📄', beats: 'rock', name: 'Paper' },
|
|
10
|
-
scissors: { emoji: '✂️', beats: 'paper', name: 'Scissors' }
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
// Battle animations for different outcomes
|
|
14
|
-
const BATTLE_ANIMATIONS = {
|
|
15
|
-
rock_scissors: '🪨 crushes ✂️',
|
|
16
|
-
paper_rock: '📄 covers 🪨',
|
|
17
|
-
scissors_paper: '✂️ cuts 📄',
|
|
18
|
-
scissors_rock: '✂️ breaks against 🪨',
|
|
19
|
-
rock_paper: '🪨 gets covered by 📄',
|
|
20
|
-
paper_scissors: '📄 gets cut by ✂️'
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
// Victory messages
|
|
24
|
-
const VICTORY_MESSAGES = [
|
|
25
|
-
'Victory! 🎉',
|
|
26
|
-
'Nice one! 🔥',
|
|
27
|
-
'You got it! ⚡',
|
|
28
|
-
'Well played! 🌟',
|
|
29
|
-
'Boom! 💥'
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
const DEFEAT_MESSAGES = [
|
|
33
|
-
'Not this time! 😅',
|
|
34
|
-
'So close! 🤷',
|
|
35
|
-
'Next round! 💪',
|
|
36
|
-
'Almost! 🎯',
|
|
37
|
-
'Good try! 👍'
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
// Get random choice for AI opponent
|
|
41
|
-
function getRandomChoice() {
|
|
42
|
-
const choices = Object.keys(CHOICES);
|
|
43
|
-
return choices[Math.floor(Math.random() * choices.length)];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Create initial game state
|
|
47
|
-
function createInitialRPSState(bestOf = 1) {
|
|
48
|
-
return {
|
|
49
|
-
bestOf: bestOf,
|
|
50
|
-
playerScore: 0,
|
|
51
|
-
opponentScore: 0,
|
|
52
|
-
rounds: [],
|
|
53
|
-
gameOver: false,
|
|
54
|
-
winner: null,
|
|
55
|
-
currentRound: 1,
|
|
56
|
-
waitingForMove: true,
|
|
57
|
-
gameType: 'rps' // rock paper scissors
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Determine winner of a single round
|
|
62
|
-
function determineRoundWinner(playerChoice, opponentChoice) {
|
|
63
|
-
if (playerChoice === opponentChoice) {
|
|
64
|
-
return 'tie';
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return CHOICES[playerChoice].beats === opponentChoice ? 'player' : 'opponent';
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Make a move in the game
|
|
71
|
-
function makeMove(gameState, playerMove, opponentMove = null) {
|
|
72
|
-
const { bestOf, playerScore, opponentScore, rounds, currentRound } = gameState;
|
|
73
|
-
|
|
74
|
-
// Validate player move
|
|
75
|
-
const normalizedPlayerMove = playerMove.toLowerCase().trim();
|
|
76
|
-
if (!CHOICES[normalizedPlayerMove]) {
|
|
77
|
-
return { error: 'Invalid choice! Use: rock, paper, or scissors' };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Check if game is already over
|
|
81
|
-
if (gameState.gameOver) {
|
|
82
|
-
return { error: 'Game is over! Start a new game to play again.' };
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Generate opponent move if not provided (for AI games)
|
|
86
|
-
const opponentChoice = opponentMove || getRandomChoice();
|
|
87
|
-
const playerChoice = normalizedPlayerMove;
|
|
88
|
-
|
|
89
|
-
// Determine round winner
|
|
90
|
-
const roundResult = determineRoundWinner(playerChoice, opponentChoice);
|
|
91
|
-
|
|
92
|
-
// Create round record
|
|
93
|
-
const roundData = {
|
|
94
|
-
round: currentRound,
|
|
95
|
-
playerChoice,
|
|
96
|
-
opponentChoice,
|
|
97
|
-
result: roundResult,
|
|
98
|
-
animation: roundResult === 'tie' ?
|
|
99
|
-
`${CHOICES[playerChoice].emoji} vs ${CHOICES[opponentChoice].emoji} - Tie!` :
|
|
100
|
-
roundResult === 'player' ?
|
|
101
|
-
BATTLE_ANIMATIONS[`${playerChoice}_${opponentChoice}`] :
|
|
102
|
-
BATTLE_ANIMATIONS[`${opponentChoice}_${playerChoice}`]
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
// Update scores
|
|
106
|
-
let newPlayerScore = playerScore;
|
|
107
|
-
let newOpponentScore = opponentScore;
|
|
108
|
-
|
|
109
|
-
if (roundResult === 'player') {
|
|
110
|
-
newPlayerScore++;
|
|
111
|
-
} else if (roundResult === 'opponent') {
|
|
112
|
-
newOpponentScore++;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Check if game is over (first to win majority of bestOf rounds)
|
|
116
|
-
const roundsToWin = Math.ceil(bestOf / 2);
|
|
117
|
-
const gameOver = newPlayerScore >= roundsToWin || newOpponentScore >= roundsToWin;
|
|
118
|
-
|
|
119
|
-
let winner = null;
|
|
120
|
-
if (gameOver) {
|
|
121
|
-
winner = newPlayerScore > newOpponentScore ? 'player' : 'opponent';
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const newGameState = {
|
|
125
|
-
...gameState,
|
|
126
|
-
playerScore: newPlayerScore,
|
|
127
|
-
opponentScore: newOpponentScore,
|
|
128
|
-
rounds: [...rounds, roundData],
|
|
129
|
-
currentRound: currentRound + 1,
|
|
130
|
-
gameOver: gameOver,
|
|
131
|
-
winner: winner,
|
|
132
|
-
waitingForMove: !gameOver,
|
|
133
|
-
lastRound: roundData
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
return { success: true, gameState: newGameState };
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Format game display
|
|
140
|
-
function formatRPSDisplay(gameState, opponentName = 'Computer') {
|
|
141
|
-
const { bestOf, playerScore, opponentScore, rounds, gameOver, winner, currentRound, lastRound } = gameState;
|
|
142
|
-
|
|
143
|
-
let display = `🎮 **Rock Paper Scissors**`;
|
|
144
|
-
|
|
145
|
-
if (bestOf > 1) {
|
|
146
|
-
display += ` (Best of ${bestOf})\n`;
|
|
147
|
-
} else {
|
|
148
|
-
display += '\n';
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
display += `**Score:** You ${playerScore} - ${opponentScore} ${opponentName}\n\n`;
|
|
152
|
-
|
|
153
|
-
// Show last round result if exists
|
|
154
|
-
if (lastRound) {
|
|
155
|
-
display += `**Round ${lastRound.round} Result:**\n`;
|
|
156
|
-
display += `${lastRound.animation}\n\n`;
|
|
157
|
-
|
|
158
|
-
if (lastRound.result === 'player') {
|
|
159
|
-
display += `${VICTORY_MESSAGES[Math.floor(Math.random() * VICTORY_MESSAGES.length)]}\n`;
|
|
160
|
-
} else if (lastRound.result === 'opponent') {
|
|
161
|
-
display += `${DEFEAT_MESSAGES[Math.floor(Math.random() * DEFEAT_MESSAGES.length)]}\n`;
|
|
162
|
-
} else {
|
|
163
|
-
display += `It's a tie! 🤝\n`;
|
|
164
|
-
}
|
|
165
|
-
display += '\n';
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Show game status
|
|
169
|
-
if (gameOver) {
|
|
170
|
-
if (winner === 'player') {
|
|
171
|
-
display += `🏆 **YOU WIN THE GAME!** 🏆\n`;
|
|
172
|
-
display += `Congratulations! You beat ${opponentName} ${playerScore}-${opponentScore}!\n`;
|
|
173
|
-
} else if (winner === 'opponent') {
|
|
174
|
-
display += `💀 **GAME OVER** 💀\n`;
|
|
175
|
-
display += `${opponentName} wins ${opponentScore}-${playerScore}. Better luck next time!\n`;
|
|
176
|
-
}
|
|
177
|
-
display += '\nStart a new game to play again!';
|
|
178
|
-
} else {
|
|
179
|
-
display += `**Round ${currentRound}** - Make your choice!\n`;
|
|
180
|
-
display += `🪨 Rock 📄 Paper ✂️ Scissors\n`;
|
|
181
|
-
display += `\nType your move: rock, paper, or scissors`;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Show round history for longer games
|
|
185
|
-
if (rounds.length > 1 && bestOf > 1) {
|
|
186
|
-
display += `\n\n**Round History:**\n`;
|
|
187
|
-
rounds.slice(-3).forEach(round => {
|
|
188
|
-
const result = round.result === 'player' ? '✅' : round.result === 'opponent' ? '❌' : '🤝';
|
|
189
|
-
display += `R${round.round}: ${CHOICES[round.playerChoice].emoji} vs ${CHOICES[round.opponentChoice].emoji} ${result}\n`;
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return display;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Get move from text input
|
|
197
|
-
function parseMove(input) {
|
|
198
|
-
const normalized = input.toLowerCase().trim();
|
|
199
|
-
|
|
200
|
-
// Support various aliases
|
|
201
|
-
const aliases = {
|
|
202
|
-
r: 'rock',
|
|
203
|
-
rock: 'rock',
|
|
204
|
-
stone: 'rock',
|
|
205
|
-
|
|
206
|
-
p: 'paper',
|
|
207
|
-
paper: 'paper',
|
|
208
|
-
|
|
209
|
-
s: 'scissors',
|
|
210
|
-
scissors: 'scissors',
|
|
211
|
-
scissor: 'scissors'
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
return aliases[normalized] || null;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Create a multiplayer game state (for player vs player)
|
|
218
|
-
function createMultiplayerRPSState(bestOf = 1) {
|
|
219
|
-
return {
|
|
220
|
-
...createInitialRPSState(bestOf),
|
|
221
|
-
gameType: 'rps_multiplayer',
|
|
222
|
-
player1Move: null,
|
|
223
|
-
player2Move: null,
|
|
224
|
-
waitingForBoth: true,
|
|
225
|
-
waitingForMove: false // Different for multiplayer
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Make multiplayer move
|
|
230
|
-
function makeMultiplayerMove(gameState, playerId, move) {
|
|
231
|
-
if (gameState.gameOver) {
|
|
232
|
-
return { error: 'Game is over! Start a new game to play again.' };
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const parsedMove = parseMove(move);
|
|
236
|
-
if (!parsedMove) {
|
|
237
|
-
return { error: 'Invalid choice! Use: rock, paper, or scissors' };
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const newGameState = { ...gameState };
|
|
241
|
-
|
|
242
|
-
if (playerId === 1) {
|
|
243
|
-
if (newGameState.player1Move) {
|
|
244
|
-
return { error: 'You already made your move this round!' };
|
|
245
|
-
}
|
|
246
|
-
newGameState.player1Move = parsedMove;
|
|
247
|
-
} else {
|
|
248
|
-
if (newGameState.player2Move) {
|
|
249
|
-
return { error: 'You already made your move this round!' };
|
|
250
|
-
}
|
|
251
|
-
newGameState.player2Move = parsedMove;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Check if both players have moved
|
|
255
|
-
if (newGameState.player1Move && newGameState.player2Move) {
|
|
256
|
-
// Process the round
|
|
257
|
-
const result = makeMove({
|
|
258
|
-
...newGameState,
|
|
259
|
-
gameType: 'rps' // Temporarily treat as single player for processing
|
|
260
|
-
}, newGameState.player1Move, newGameState.player2Move);
|
|
261
|
-
|
|
262
|
-
if (result.success) {
|
|
263
|
-
const processedState = result.gameState;
|
|
264
|
-
newGameState.playerScore = processedState.playerScore;
|
|
265
|
-
newGameState.opponentScore = processedState.opponentScore;
|
|
266
|
-
newGameState.rounds = processedState.rounds;
|
|
267
|
-
newGameState.currentRound = processedState.currentRound;
|
|
268
|
-
newGameState.gameOver = processedState.gameOver;
|
|
269
|
-
newGameState.winner = processedState.winner;
|
|
270
|
-
newGameState.lastRound = processedState.lastRound;
|
|
271
|
-
|
|
272
|
-
// Reset for next round
|
|
273
|
-
newGameState.player1Move = null;
|
|
274
|
-
newGameState.player2Move = null;
|
|
275
|
-
newGameState.waitingForBoth = !processedState.gameOver;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
return { success: true, gameState: newGameState };
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
module.exports = {
|
|
283
|
-
createInitialRPSState,
|
|
284
|
-
createMultiplayerRPSState,
|
|
285
|
-
makeMove,
|
|
286
|
-
makeMultiplayerMove,
|
|
287
|
-
formatRPSDisplay,
|
|
288
|
-
parseMove,
|
|
289
|
-
getRandomChoice,
|
|
290
|
-
CHOICES
|
|
291
|
-
};
|