better gen
Browse files
src/lib/components/MonsterGenerator/MonsterGenerator.svelte
CHANGED
@@ -8,6 +8,7 @@
|
|
8 |
import { saveMonster } from '$lib/db/monsters';
|
9 |
import { extractPicletMetadata } from '$lib/services/picletMetadata';
|
10 |
import { savePicletInstance } from '$lib/db/piclets';
|
|
|
11 |
|
12 |
interface Props extends MonsterGeneratorProps {}
|
13 |
|
@@ -300,30 +301,54 @@ Focus on: colors, body shape, eyes, limbs, mouth, and key visual features. Omit
|
|
300 |
// Default tier (will be set from the generated stats)
|
301 |
let tier: 'low' | 'medium' | 'high' | 'legendary' = 'medium';
|
302 |
|
303 |
-
// Extract
|
304 |
-
const
|
305 |
-
const
|
|
|
|
|
|
|
|
|
306 |
|
307 |
// Extract only the Monster Lore section for description
|
308 |
const loreMatch = state.monsterConcept.match(/## Monster Lore\s*\n([\s\S]*?)(?=##|$)/);
|
309 |
const monsterLore = loreMatch ? loreMatch[1].trim() : '';
|
310 |
|
|
|
|
|
|
|
|
|
|
|
311 |
// Create stats prompt - only ask for battle-related stats
|
312 |
const statsPrompt = `Based on this monster concept, generate a JSON object with battle stats and abilities:
|
313 |
"${state.monsterConcept}"
|
314 |
|
|
|
|
|
315 |
First, assess the rarity of the original object based on real-world availability and value:
|
316 |
β’ COMMON: Everyday items everyone has (stationery, grass, rocks, basic furniture, common tools)
|
317 |
β’ UNCOMMON: Items that cost money but are widely available (electronics, appliances, vehicles, branded items)
|
318 |
β’ RARE: Expensive or specialized items (luxury goods, professional equipment, gold jewelry, antiques)
|
319 |
β’ LEGENDARY: Priceless or one-of-a-kind items (crown jewels, world wonders, famous artifacts, masterpiece art)
|
320 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
321 |
The output should be formatted as a JSON instance that conforms to the JSON schema below.
|
322 |
|
323 |
\`\`\`json
|
324 |
{
|
325 |
"properties": {
|
326 |
"rarity": {"type": "string", "enum": ["common", "uncommon", "rare", "legendary"], "description": "Rarity of the original object based on real-world availability and value"},
|
|
|
327 |
"height": {"type": "number", "minimum": 0.1, "maximum": 50.0, "description": "Height of the piclet in meters (e.g., 1.2, 0.5, 10.0)"},
|
328 |
"weight": {"type": "number", "minimum": 0.1, "maximum": 10000.0, "description": "Weight of the piclet in kilograms (e.g., 25.4, 150.0, 0.8)"},
|
329 |
"HP": {"type": "integer", "minimum": 0, "maximum": 100, "description": "Health/vitality stat (0=fragile, 100=incredibly tanky)"},
|
@@ -340,7 +365,7 @@ The output should be formatted as a JSON instance that conforms to the JSON sche
|
|
340 |
"specialActionName": {"type": "string", "description": "Name of the monster's ultimate move (one use per battle)"},
|
341 |
"specialActionDescription": {"type": "string", "description": "Describe this powerful finishing move and its dramatic effects in battle"}
|
342 |
},
|
343 |
-
"required": ["rarity", "height", "weight", "HP", "defence", "attack", "speed", "specialPassiveTraitDescription", "attackActionName", "attackActionDescription", "buffActionName", "buffActionDescription", "debuffActionName", "debuffActionDescription", "specialActionName", "specialActionDescription"]
|
344 |
}
|
345 |
\`\`\`
|
346 |
|
@@ -393,7 +418,7 @@ Write your response within \`\`\`json\`\`\``;
|
|
393 |
const parsedStats = JSON.parse(cleanJson.trim());
|
394 |
|
395 |
// Remove any extra fields not in our schema
|
396 |
-
const allowedFields = ['rarity', 'height', 'weight', 'HP', 'defence', 'attack', 'speed',
|
397 |
'specialPassiveTraitDescription', 'attackActionName', 'attackActionDescription',
|
398 |
'buffActionName', 'buffActionDescription', 'debuffActionName', 'debuffActionDescription',
|
399 |
'specialActionName', 'specialActionDescription', 'boostActionName', 'boostActionDescription',
|
|
|
8 |
import { saveMonster } from '$lib/db/monsters';
|
9 |
import { extractPicletMetadata } from '$lib/services/picletMetadata';
|
10 |
import { savePicletInstance } from '$lib/db/piclets';
|
11 |
+
import { PicletType, TYPE_DATA } from '$lib/types/picletTypes';
|
12 |
|
13 |
interface Props extends MonsterGeneratorProps {}
|
14 |
|
|
|
301 |
// Default tier (will be set from the generated stats)
|
302 |
let tier: 'low' | 'medium' | 'high' | 'legendary' = 'medium';
|
303 |
|
304 |
+
// Extract object description from the Object Caption section
|
305 |
+
const objectMatch = state.monsterConcept.match(/# Object Caption\s*\n([\s\S]*?)(?=^# )/m);
|
306 |
+
const objectDescription = objectMatch ? objectMatch[1].trim() : '';
|
307 |
+
|
308 |
+
// Extract monster name - now it's the third heading after Object Caption and Transformation Brainstorm
|
309 |
+
const monsterNameMatch = state.monsterConcept.match(/^# (?!Object Caption|Transformation Brainstorm)(.+)$/m);
|
310 |
+
const monsterName = monsterNameMatch ? monsterNameMatch[1].trim() : 'Unknown Monster';
|
311 |
|
312 |
// Extract only the Monster Lore section for description
|
313 |
const loreMatch = state.monsterConcept.match(/## Monster Lore\s*\n([\s\S]*?)(?=##|$)/);
|
314 |
const monsterLore = loreMatch ? loreMatch[1].trim() : '';
|
315 |
|
316 |
+
// Debug logging
|
317 |
+
console.log('Extracted object description:', objectDescription);
|
318 |
+
console.log('Extracted monster name:', monsterName);
|
319 |
+
console.log('Extracted monster lore:', monsterLore);
|
320 |
+
|
321 |
// Create stats prompt - only ask for battle-related stats
|
322 |
const statsPrompt = `Based on this monster concept, generate a JSON object with battle stats and abilities:
|
323 |
"${state.monsterConcept}"
|
324 |
|
325 |
+
The original object is described as: "${objectDescription}"
|
326 |
+
|
327 |
First, assess the rarity of the original object based on real-world availability and value:
|
328 |
β’ COMMON: Everyday items everyone has (stationery, grass, rocks, basic furniture, common tools)
|
329 |
β’ UNCOMMON: Items that cost money but are widely available (electronics, appliances, vehicles, branded items)
|
330 |
β’ RARE: Expensive or specialized items (luxury goods, professional equipment, gold jewelry, antiques)
|
331 |
β’ LEGENDARY: Priceless or one-of-a-kind items (crown jewels, world wonders, famous artifacts, masterpiece art)
|
332 |
|
333 |
+
Next, determine the monster's type based on its concept and appearance. Choose the most appropriate type from these options:
|
334 |
+
β’ BEAST: Vertebrate wildlife β mammals, birds, reptiles. Raw physicality, instincts, region-based variants.
|
335 |
+
β’ BUG: Arthropods β butterflies, beetles, mantises. Agile swarms, precision strikes, metamorph evolutions.
|
336 |
+
β’ AQUATIC: Life that swims, dives, sloshes, seeps β fish, octopus, sentient puddles. Tides, mist, pressure.
|
337 |
+
β’ FLORA: Plants and fungi β blooming or decaying. Growth, spores, vines, seasonal shifts.
|
338 |
+
β’ MINERAL: Stones, crystals, metals β earth's depths. Durability, reflective armor, seismic shocks.
|
339 |
+
β’ SPACE: Stars, moon, cosmic objects β not of this world. Celestial energy and cosmic forces.
|
340 |
+
β’ MACHINA: Engineered devices β gadgets to machinery. Gears, circuits, drones, power surges.
|
341 |
+
β’ STRUCTURE: Buildings, bridges, monuments β architectural titans. Fortification, terrain shaping.
|
342 |
+
β’ CULTURE: Art, fashion, toys, symbols β creative expressions. Buffs, debuffs, illusion, stories.
|
343 |
+
β’ CUISINE: Dishes, drinks, culinary art β flavors and aromas. Temperature, restorative, spicy offense.
|
344 |
+
|
345 |
The output should be formatted as a JSON instance that conforms to the JSON schema below.
|
346 |
|
347 |
\`\`\`json
|
348 |
{
|
349 |
"properties": {
|
350 |
"rarity": {"type": "string", "enum": ["common", "uncommon", "rare", "legendary"], "description": "Rarity of the original object based on real-world availability and value"},
|
351 |
+
"picletType": {"type": "string", "enum": ["beast", "bug", "aquatic", "flora", "mineral", "space", "machina", "structure", "culture", "cuisine"], "description": "The type that best matches this monster's concept, appearance, and nature"},
|
352 |
"height": {"type": "number", "minimum": 0.1, "maximum": 50.0, "description": "Height of the piclet in meters (e.g., 1.2, 0.5, 10.0)"},
|
353 |
"weight": {"type": "number", "minimum": 0.1, "maximum": 10000.0, "description": "Weight of the piclet in kilograms (e.g., 25.4, 150.0, 0.8)"},
|
354 |
"HP": {"type": "integer", "minimum": 0, "maximum": 100, "description": "Health/vitality stat (0=fragile, 100=incredibly tanky)"},
|
|
|
365 |
"specialActionName": {"type": "string", "description": "Name of the monster's ultimate move (one use per battle)"},
|
366 |
"specialActionDescription": {"type": "string", "description": "Describe this powerful finishing move and its dramatic effects in battle"}
|
367 |
},
|
368 |
+
"required": ["rarity", "picletType", "height", "weight", "HP", "defence", "attack", "speed", "specialPassiveTraitDescription", "attackActionName", "attackActionDescription", "buffActionName", "buffActionDescription", "debuffActionName", "debuffActionDescription", "specialActionName", "specialActionDescription"]
|
369 |
}
|
370 |
\`\`\`
|
371 |
|
|
|
418 |
const parsedStats = JSON.parse(cleanJson.trim());
|
419 |
|
420 |
// Remove any extra fields not in our schema
|
421 |
+
const allowedFields = ['rarity', 'picletType', 'height', 'weight', 'HP', 'defence', 'attack', 'speed',
|
422 |
'specialPassiveTraitDescription', 'attackActionName', 'attackActionDescription',
|
423 |
'buffActionName', 'buffActionDescription', 'debuffActionName', 'debuffActionDescription',
|
424 |
'specialActionName', 'specialActionDescription', 'boostActionName', 'boostActionDescription',
|
src/lib/components/MonsterGenerator/MonsterResult.svelte
CHANGED
@@ -1,6 +1,8 @@
|
|
1 |
<script lang="ts">
|
2 |
import type { MonsterWorkflowState } from '$lib/types';
|
3 |
import { saveMonster } from '$lib/db/monsters';
|
|
|
|
|
4 |
|
5 |
interface Props {
|
6 |
workflowState: MonsterWorkflowState;
|
@@ -118,6 +120,12 @@
|
|
118 |
<div class="tier-badge {workflowState.monsterStats.tier}">{workflowState.monsterStats.tier.toUpperCase()}</div>
|
119 |
<span class="stat-label">Tier</span>
|
120 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
<div class="stat-item">
|
122 |
<div class="stat-bar" style="width: {workflowState.monsterStats.HP}%; background-color: {getStatColor(workflowState.monsterStats.HP)}20"></div>
|
123 |
<span class="stat-label">HP</span>
|
|
|
1 |
<script lang="ts">
|
2 |
import type { MonsterWorkflowState } from '$lib/types';
|
3 |
import { saveMonster } from '$lib/db/monsters';
|
4 |
+
import { TYPE_DATA, PicletType } from '$lib/types/picletTypes';
|
5 |
+
import TypeBadge from '$lib/components/UI/TypeBadge.svelte';
|
6 |
|
7 |
interface Props {
|
8 |
workflowState: MonsterWorkflowState;
|
|
|
120 |
<div class="tier-badge {workflowState.monsterStats.tier}">{workflowState.monsterStats.tier.toUpperCase()}</div>
|
121 |
<span class="stat-label">Tier</span>
|
122 |
</div>
|
123 |
+
{#if (workflowState.monsterStats as any).picletType}
|
124 |
+
<div class="stat-item">
|
125 |
+
<TypeBadge type={(workflowState.monsterStats as any).picletType as PicletType} showLabel={true} size="medium" />
|
126 |
+
<span class="stat-label">Type</span>
|
127 |
+
</div>
|
128 |
+
{/if}
|
129 |
<div class="stat-item">
|
130 |
<div class="stat-bar" style="width: {workflowState.monsterStats.HP}%; background-color: {getStatColor(workflowState.monsterStats.HP)}20"></div>
|
131 |
<span class="stat-label">HP</span>
|
src/lib/db/piclets.ts
CHANGED
@@ -26,8 +26,16 @@ export async function monsterToPicletInstance(monster: Monster, level: number =
|
|
26 |
|
27 |
const maxHp = calculateHp(baseHp, level);
|
28 |
|
29 |
-
// Determine primary type
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
|
32 |
// Create moves based on monster's abilities
|
33 |
const moves: BattleMove[] = [
|
|
|
26 |
|
27 |
const maxHp = calculateHp(baseHp, level);
|
28 |
|
29 |
+
// Determine primary type - use picletType from stats if available, otherwise auto-detect
|
30 |
+
let primaryType: PicletType;
|
31 |
+
if (monster.stats && (monster.stats as any).picletType) {
|
32 |
+
// Use the type determined during stat generation
|
33 |
+
const statsType = (monster.stats as any).picletType as string;
|
34 |
+
primaryType = statsType as PicletType;
|
35 |
+
} else {
|
36 |
+
// Fallback to concept-based detection
|
37 |
+
primaryType = getTypeFromConcept(monster.concept, monster.imageCaption);
|
38 |
+
}
|
39 |
|
40 |
// Create moves based on monster's abilities
|
41 |
const moves: BattleMove[] = [
|