Skip to main content
Glama

check_cover

Calculate cover between attacker and target positions to determine Armor Class and Dexterity save bonuses for combat scenarios.

Instructions

Check cover between attacker and target, returning AC and Dex save bonuses

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
attackerYes
targetYes
obstaclesNo
creaturesNo
creaturesProvideCoverNo

Implementation Reference

  • Main handler function for check_cover tool. Computes the highest level of cover between attacker and target positions by checking obstacles and creatures on the line of sight. Returns ASCII-formatted output with AC and Dex save bonuses based on D&D 5e rules (none: +0, half: +2, three-quarters: +5, total: blocked).
    export function checkCover(input: CheckCoverInput): string { const content: string[] = []; const attackerPos: Position = { x: input.attacker.x, y: input.attacker.y, z: input.attacker.z ?? 0, }; const targetPos: Position = { x: input.target.x, y: input.target.y, z: input.target.z ?? 0, }; // Calculate distance const dx = targetPos.x - attackerPos.x; const dy = targetPos.y - attackerPos.y; const dz = (targetPos.z ?? 0) - (attackerPos.z ?? 0); const distance = Math.sqrt(dx * dx + dy * dy + dz * dz) * 5; // Convert to feet // Build header content.push(centerText('COVER CHECK', COVER_DISPLAY_WIDTH)); content.push(''); content.push(`Attacker: (${attackerPos.x}, ${attackerPos.y}, ${attackerPos.z ?? 0})`); content.push(`Target: (${targetPos.x}, ${targetPos.y}, ${targetPos.z ?? 0})`); content.push(`Distance: ${Math.round(distance)} feet`); content.push(''); content.push(BOX.LIGHT.H.repeat(COVER_DISPLAY_WIDTH)); content.push(''); // Find highest cover level from all obstacles let coverLevel: CoverLevel = 'none'; const coverSources: Array<{ type: string; position: string }> = []; // Check static obstacles const obstacles = input.obstacles || []; for (const obstacle of obstacles) { // Skip obstacles at the attacker's position if ( obstacle.x === attackerPos.x && obstacle.y === attackerPos.y && (obstacle.z ?? 0) === (attackerPos.z ?? 0) ) { continue; } const obstacleCover = calculateCoverFromObstacle(obstacle, attackerPos, targetPos); if (obstacleCover !== null) { coverLevel = determineCoverLevel(coverLevel, obstacleCover); if (obstacleCover !== 'none') { coverSources.push({ type: obstacle.type, position: `(${obstacle.x}, ${obstacle.y}, ${obstacle.z ?? 0})`, }); } } } // Check creature cover if (input.creaturesProvideCover && input.creatures) { for (const creature of input.creatures) { if (isOnLine(attackerPos, targetPos, creature)) { const creatureCover = getCreatureCover(creature.size); coverLevel = determineCoverLevel(coverLevel, creatureCover); if (creatureCover !== 'none') { coverSources.push({ type: `${creature.size} creature`, position: `(${creature.x}, ${creature.y}, ${creature.z ?? 0})`, }); } } } } // Display cover sources if any if (coverSources.length > 0) { content.push(centerText('COVER SOURCES', COVER_DISPLAY_WIDTH)); content.push(''); for (const source of coverSources) { content.push(` ${source.type} at ${source.position}`); } content.push(''); content.push(BOX.LIGHT.H.repeat(COVER_DISPLAY_WIDTH)); content.push(''); } // Display result content.push(centerText('RESULT', COVER_DISPLAY_WIDTH)); content.push(''); switch (coverLevel) { case 'total': content.push('TOTAL COVER'); content.push(''); content.push('Target cannot be directly targeted.'); content.push('No line of effect for attacks or spells.'); break; case 'three_quarters': content.push('THREE-QUARTERS COVER'); content.push(''); content.push(`AC Bonus: +${COVER_BONUSES.three_quarters}`); content.push(`Dex Save Bonus: +${COVER_BONUSES.three_quarters}`); break; case 'half': content.push('HALF COVER'); content.push(''); content.push(`AC Bonus: +${COVER_BONUSES.half}`); content.push(`Dex Save Bonus: +${COVER_BONUSES.half}`); break; default: content.push('NO COVER'); content.push(''); content.push('AC Bonus: +0'); content.push('Dex Save Bonus: +0'); break; } return createBox('COVER CHECK', content); }
  • Zod input schema for validating check_cover tool arguments, defining attacker/target positions and optional obstacles/creatures.
    export const checkCoverSchema = z.object({ attacker: CoverPositionSchema, target: CoverPositionSchema, obstacles: z.array(ObstacleSchema).optional(), creatures: z.array(CreatureBlockSchema).optional(), creaturesProvideCover: z.boolean().default(false), });
  • Registration of check_cover tool in the MCP registry, including name, description, input schema conversion, and wrapper handler that validates input and calls the spatial checkCover function.
    check_cover: { name: 'check_cover', description: 'Check cover between attacker and target, returning AC and Dex save bonuses', inputSchema: toJsonSchema(checkCoverSchema), handler: async (args) => { try { const validated = checkCoverSchema.parse(args); const result = checkCover(validated); return success(result); } catch (err) { if (err instanceof z.ZodError) { const messages = err.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', '); return error(`Validation failed: ${messages}`); } const message = err instanceof Error ? err.message : String(err); return error(message); } },

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Mnehmos/ChatRPG'

If you have feedback or need assistance with the MCP directory API, please join our Discord server