UNPKG

@zerospacegg/vynthra

Version:
538 lines • 16.4 kB
import { getSearchIndex } from "@zerospacegg/iolin/meta/search-index"; import chalk from "chalk"; /** * Emoji mappings for different entity types and stats */ const EMOJIS = { // Entity types faction: "šŸ›ļø", unit: "āš”ļø", building: "šŸ—ļø", map: "šŸ—ŗļø", mission: "šŸŽÆ", // Unit stats health: "ā¤ļø", speed: "⚔", vision: "šŸ‘ļø", supply: "šŸž", damage: "āš”ļø", range: "šŸŽÆ", armor: "šŸ›”ļø", shields: "šŸ”®", // Resources hexite: "šŸ’Ž", flux: "🟣", energy: "šŸ”‹", buildTime: "ā±ļø", // Abilities cooldown: "ā±ļø", duration: "ā°", energyCost: "šŸ”‹", classicEnergy: "šŸ”‹", abesEnergy: "⚔", topbarEnergy: "šŸ”“", healthEnergy: "ā¤ļø", dps: "šŸ”„", splash: "šŸ’„", bonus: "šŸŽÆ", // Domains ground: "šŸŒ", air: "ā˜ļø", // Tiers T0: "0ļøāƒ£", T1: "1ļøāƒ£", T2: "2ļøāƒ£", T3: "3ļøāƒ£", "T1.5": "šŸ”ø", "T2.5": "šŸ”¹", "T3.5": "šŸ”·", T4: "4ļøāƒ£", // General check: "āœ…", cross: "āŒ", arrow: "āžœ", info: "ā„¹ļø", link: "šŸ”—", shield: "šŸ›”ļø", sword: "āš”ļø", lightning: "⚔", tag: "šŸ·ļø", creates: "šŸ­", createdBy: "šŸ”§", unlocks: "šŸ”“", unlockedBy: "šŸ”’", upgrades: "ā¬†ļø", biomass: "🌱", mapInfo: "šŸ—ŗļø", players: "šŸ‘„", towers: "šŸ—¼", ladder: "šŸ†", }; /** * Format duration in seconds to readable format */ function formatDuration(seconds) { return `${seconds}s`; } /** * Calculate DPS from damage and cooldown */ function calculateDPS(damage, cooldown) { if (cooldown <= 0) return 0; return damage / cooldown; } /** * Get energy emoji based on energy type */ function getEnergyEmoji(energyType) { switch (energyType) { case "classic": return EMOJIS.classicEnergy; case "abes": return EMOJIS.abesEnergy; case "topbar": return EMOJIS.topbarEnergy; case "health": return EMOJIS.healthEnergy; default: return EMOJIS.energy; } } /** * Get entity display name from search index */ function getEntityDisplayName(entityIdOrSlug) { const searchIndex = getSearchIndex(); // Try direct lookup first let entity = searchIndex.all[entityIdOrSlug]; if (entity) return entity.name; // check by slug const fullId = searchIndex.ids[entityIdOrSlug]; if (fullId) { entity = searchIndex.all[fullId]; if (entity) return entity.name; } // Fallback to the original string, formatted return entityIdOrSlug .replace(/-/g, " ") .replace(/\b\w/g, (l) => l.toUpperCase()); } /** * Get faction display name from search index */ function getFactionDisplayName(factionSlug) { const searchIndex = getSearchIndex(); const factionEntity = searchIndex.all[`faction/${factionSlug}`]; return factionEntity ? factionEntity.name : factionSlug; } /** * Render entity basic information as rich markdown */ function renderEntityBasic(entity) { const parts = []; // Title with emoji and info in one line const typeEmoji = EMOJIS[entity.type] || EMOJIS.info; let title = `# ${typeEmoji} **${entity.name}**`; // Build the info section const infoParts = []; // Add faction name first if available if (entity.faction) { const factionName = getFactionDisplayName(entity.faction); infoParts.push(factionName); } // Add tier if available if (entity.tier) { infoParts.push(entity.tier); } // Add type and subtype let typeText = entity.type; if (entity.subtype) { typeText = `${entity.subtype} ${entity.type}`; } // Capitalize each word typeText = typeText .split(" ") .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .join(" "); infoParts.push(typeText); // Combine title and info if (infoParts.length > 0) { title += ` • ${infoParts.join(" ")}`; } parts.push(title); return parts.join("\n"); } /** * Render cost information (simplified for now) */ function renderCost(entity) { const costParts = []; // Core resource costs if (entity.hexiteCost) { costParts.push(`${EMOJIS.hexite} ${entity.hexiteCost} hexite`); } if (entity.fluxCost) { costParts.push(`${EMOJIS.flux} ${entity.fluxCost} flux`); } // Build time (separate from resource costs) if (entity.buildTime) { costParts.push(`${EMOJIS.buildTime} ${formatDuration(entity.buildTime)} build`); } if (costParts.length === 0) return ""; return `**Cost:** ${costParts.join(" • ")}`; } /** * Render tags as simple display (simplified for now) */ function renderTags(entity) { if (!entity.tags || entity.tags.length === 0) return ""; const displayTags = entity.tags .filter((tag) => !tag.startsWith("tier:") && !tag.startsWith("faction:")) .slice(0, 8); // Limit to avoid overwhelming display if (displayTags.length === 0) return ""; return `**${EMOJIS.tag} Tags:** ${displayTags.join(" • ")}`; } /** * Render basic unit stats (simplified - no combat for now) */ function renderUnitBasic(unit) { const parts = []; const basicParts = []; // Basic stats that should be safe to access if (unit.hp) { basicParts.push(`${EMOJIS.health} HP ${unit.hp}`); } if (unit.speed) { basicParts.push(`${EMOJIS.speed} Speed ${unit.speed}`); } if (unit.supply) { basicParts.push(`${EMOJIS.supply} Supply ${unit.supply}`); } if (basicParts.length > 0) { parts.push(`**Stats:** ${basicParts.join(" • ")}`); } return parts.join("\n"); } /** * Render building basic stats (enhanced) */ function renderBuildingBasic(building) { const parts = []; const basicParts = []; if (building.hp) { basicParts.push(`${EMOJIS.health} HP ${building.hp}`); } if (building.providesSupply) { basicParts.push(`${EMOJIS.supply} +${building.providesSupply} supply`); } if (building.providesBiomass) { basicParts.push(`${EMOJIS.biomass} +${building.providesBiomass} biomass`); } if (building.gathersFlux) { basicParts.push(`${EMOJIS.flux} ${building.gathersFlux} flux/min`); } if (building.gathersRichFlux) { basicParts.push(`${EMOJIS.flux} ${building.gathersRichFlux} rich flux/min`); } if (basicParts.length > 0) { parts.push(`**Stats:** ${basicParts.join(" • ")}`); } return parts.join("\n"); } /** * Render map details (new for Phase 5) */ function renderMapDetails(map) { const parts = []; const mapParts = []; if (map.players) { mapParts.push(`${EMOJIS.players} ${map.players} Players`); } if (map.xpTowers) { mapParts.push(`${EMOJIS.towers} ${map.xpTowers} XP Towers`); } if (map.fluxDistance) { mapParts.push(`${EMOJIS.flux} Flux Distance: ${map.fluxDistance}`); } if (map.mapSize) { mapParts.push(`${EMOJIS.mapInfo} Size: ${map.mapSize}`); } if (map.inLadderPool) { mapParts.push(`${EMOJIS.ladder} In Ladder Pool`); } if (mapParts.length > 0) { parts.push(`**Map Info:** ${mapParts.join(" • ")}`); } return parts.join("\n"); } /** * Render building production capabilities (new for Phase 5) */ function renderBuildingProduction(building) { const parts = []; // Units this building can produce if (building.produces && building.produces.length > 0) { const unitsList = building.produces .map((slug) => getEntityDisplayName(slug)) .join(", "); parts.push(`**${EMOJIS.creates} Produces:** ${unitsList}`); } // Buildings this building can create if (building.creates && building.creates.length > 0) { const buildingsList = building.creates .map((slug) => getEntityDisplayName(slug)) .join(", "); parts.push(`**${EMOJIS.creates} Creates:** ${buildingsList}`); } // What this building unlocks if (building.unlocks && building.unlocks.length > 0) { const unlocksList = building.unlocks .map((slug) => getEntityDisplayName(slug)) .join(", "); parts.push(`**${EMOJIS.unlocks} Unlocks:** ${unlocksList}`); } return parts.join("\n"); } /** * Render weapon/ability information in compact list format */ function renderAbility(ability, index) { const parts = []; // Ability header with name and key stats let header = `• **${ability.name || `Ability ${index + 1}`}**`; // Core stats in parentheses const coreStats = []; // Basic damage/healing stats - need to cast to specific types if (ability.abilityType === "attack") { const attack = ability; if (attack.damage) { coreStats.push(`${EMOJIS.damage} ${attack.damage}`); } } if (ability.abilityType === "heal") { const heal = ability; if (heal.healAmount) { coreStats.push(`ā¤ļø ${heal.healAmount}`); } } if (ability.cooldown) { coreStats.push(`${EMOJIS.cooldown} ${formatDuration(ability.cooldown)}`); } if (ability.range) { coreStats.push(`${EMOJIS.range} ${ability.range}`); } if (ability.energyCost) { const energyEmoji = getEnergyEmoji(ability.energyType); coreStats.push(`${energyEmoji} ${ability.energyCost}`); } if (coreStats.length > 0) { header += ` (${coreStats.join(" • ")})`; } parts.push(header); // Description if available if (ability.description) { parts.push(` *${ability.description}*`); } // Additional effects and bonuses const effects = []; // DPS calculation for attacks if (ability.abilityType === "attack" && ability.cooldown) { const attack = ability; if (attack.damage) { const dps = calculateDPS(attack.damage, ability.cooldown); effects.push(`${EMOJIS.dps} ${dps.toFixed(1)} DPS`); } } // Duration if (ability.duration) { effects.push(`Duration: ${formatDuration(ability.duration)}`); } // Targets if (ability.targets && ability.targets.length > 0) { effects.push(`Targets: ${ability.targets.join(", ")}`); } if (effects.length > 0) { parts.push(` ${effects.join(" • ")}`); } return parts.join("\n"); } /** * Render abilities from ability collections */ function renderAbilities(entity) { const parts = []; let abilityIndex = 0; // Render attacks const attacks = Object.values(entity.attacks || {}); if (attacks.length > 0) { parts.push("\n## Attacks"); attacks.forEach((attack) => { parts.push(renderAbility(attack, abilityIndex++)); }); } // Render heals const heals = Object.values(entity.heals || {}); if (heals.length > 0) { parts.push("\n## Heals"); heals.forEach((heal) => { parts.push(renderAbility(heal, abilityIndex++)); }); } // Render spells const spells = Object.values(entity.spells || {}); if (spells.length > 0) { parts.push("\n## Spells"); spells.forEach((spell) => { parts.push(renderAbility(spell, abilityIndex++)); }); } // Render passives const passives = Object.values(entity.passives || {}); if (passives.length > 0) { parts.push("\n## Passives"); passives.forEach((passive) => { parts.push(renderAbility(passive, abilityIndex++)); }); } // Render sieges const sieges = Object.values(entity.sieges || {}); if (sieges.length > 0) { parts.push("\n## Siege Abilities"); sieges.forEach((siege) => { parts.push(renderAbility(siege, abilityIndex++)); }); } return parts.join("\n"); } /** * Render full entity data with basic stats (Phase 3 - simplified) */ function renderEntityFull(entity, fullEntity) { const parts = []; // Basic info parts.push(renderEntityBasic(entity)); if (!fullEntity || fullEntity === entity) { return parts.join("\n\n"); } // Basic stats for units (no combat details yet) if (entity.type === "unit") { const unitStats = renderUnitBasic(fullEntity); if (unitStats) parts.push(unitStats); } // Basic stats for buildings if (entity.type === "building") { const buildingStats = renderBuildingBasic(fullEntity); if (buildingStats) parts.push(buildingStats); } // Map details for maps if (entity.type === "map") { const mapDetails = renderMapDetails(fullEntity); if (mapDetails) parts.push(mapDetails); } // Cost information (only for gamepieces) if (entity.type === "unit" || entity.type === "building") { const costInfo = renderCost(fullEntity); if (costInfo) parts.push(costInfo); } // Tags (simplified) const tagsDisplay = renderTags(fullEntity); if (tagsDisplay) parts.push(tagsDisplay); // Abilities for units if (entity.type === "unit") { const abilities = renderAbilities(fullEntity); if (abilities) parts.push(abilities); } // Production capabilities for buildings if (entity.type === "building") { const production = renderBuildingProduction(fullEntity); if (production) parts.push(production); } // Footer with link if (entity.id) { const url = `https://zerospace.gg/library/${entity.id}`; const entityType = entity.type === "unit" ? "unit" : entity.type; parts.push(`\n${EMOJIS.link} See full ${entityType} info: <${url}>`); } return parts.join("\n\n"); } /** * Render search results to markdown */ export function renderSearchResult(result) { switch (result.type) { case "single": return renderEntityFull(result.entity, result.fullEntity); case "multi": const parts = [ `# ${EMOJIS.info} Multiple Matches Found (${result.matches.length})`, "", ]; result.matches.forEach((match, index) => { const typeEmoji = EMOJIS[match.type] || EMOJIS.info; parts.push(`${index + 1}. ${typeEmoji} **${match.name}** (${match.type})`); }); parts.push(""); parts.push("šŸ’” *Try a more specific search term to get detailed info*"); return parts.join("\n"); case "none": return `# ${EMOJIS.cross} No Results Found\n\nNo matches found for "${result.query}".\n\nšŸ’” *Try different search terms or check spelling*`; } } /** * Render markdown to terminal with colors */ export function renderToTerminal(markdown) { const lines = markdown.split("\n"); const formattedLines = []; for (const line of lines) { // Handle headers if (line.startsWith("# ")) { formattedLines.push(chalk.bold.blue(line.slice(2))); } else if (line.startsWith("## ")) { formattedLines.push(chalk.bold.green(line.slice(3))); } else if (line.startsWith("### ")) { formattedLines.push(chalk.bold.yellow(line.slice(4))); } else if (line.startsWith("**") && line.endsWith("**")) { // Bold text formattedLines.push(chalk.bold(line.slice(2, -2))); } else if (line.startsWith("*") && line.endsWith("*")) { // Italic text formattedLines.push(chalk.italic(line.slice(1, -1))); } else { formattedLines.push(line); } } return formattedLines.join("\n"); } /** * Render search results to terminal with colors */ export function renderSearchResultToTerminal(result) { const markdown = renderSearchResult(result); return renderToTerminal(markdown); } /** * Render search results as markdown (passthrough) */ export function renderSearchResultAsMarkdown(result) { return renderSearchResult(result); } //# sourceMappingURL=renderer.js.map