Skip to main content
Glama

calculate_aoe

Calculate area of effect for D&D 5e spells and abilities, supporting sphere, cone, line, cube, and cylinder shapes to determine combat impact.

Instructions

Calculate area of effect for D&D 5e spells/abilities (sphere, cone, line, cube, cylinder)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
encounterIdNo
shapeYes
originYes
lengthNo
widthNo
radiusNo
sideLengthNo
heightNo
directionNo
includeOriginNo
excludeIdsNo

Implementation Reference

  • Core handler function implementing calculate_aoe tool logic: computes affected grid tiles for D&D 5e AoE shapes (sphere, cone, line, cube, cylinder) and generates formatted ASCII output with parameters, tile count, and sample positions.
    export function calculateAoe(input: CalculateAoeInput): string {
      const content: string[] = [];
      const {
        encounterId,
        shape,
        origin,
        length,
        width = 5,
        radius,
        sideLength,
        height,
        direction,
        includeOrigin = false,
        excludeIds = [],
      } = input;
    
      // Calculate affected tiles based on shape
      let tiles: Position[] = [];
    
      switch (shape) {
        case 'sphere':
          tiles = calculateSphereTiles(origin, radius!, includeOrigin);
          break;
        case 'cone':
          tiles = calculateConeTiles(origin, length!, direction || { x: 1, y: 0 }, includeOrigin);
          break;
        case 'line':
          tiles = calculateLineTiles(origin, length!, width, direction || { x: 1, y: 0 });
          break;
        case 'cube':
          tiles = calculateCubeTiles(origin, sideLength!, direction, includeOrigin);
          break;
        case 'cylinder':
          tiles = calculateCylinderTiles(origin, radius!, height!, includeOrigin);
          break;
      }
    
      // Build header
      content.push(centerText(`${shape.toUpperCase()} AoE`, AOE_DISPLAY_WIDTH));
      content.push('');
      content.push(`Origin: (${origin.x}, ${origin.y}, ${origin.z ?? 0})`);
      content.push('');
      content.push(BOX.LIGHT.H.repeat(AOE_DISPLAY_WIDTH));
      content.push('');
    
      // Show shape parameters
      content.push(centerText('PARAMETERS', AOE_DISPLAY_WIDTH));
      content.push('');
      content.push(`Shape: ${shape}`);
    
      switch (shape) {
        case 'sphere':
          content.push(`Radius: ${radius} ft`);
          break;
        case 'cone':
          content.push(`Length: ${length} ft`);
          content.push(`Width at base: ${length} ft`);
          if (direction) {
            content.push(`Direction: (${direction.x}, ${direction.y})`);
          }
          break;
        case 'line':
          content.push(`Length: ${length} ft`);
          content.push(`Width: ${width} ft`);
          if (direction) {
            content.push(`Direction: (${direction.x}, ${direction.y})`);
          }
          break;
        case 'cube':
          content.push(`Side: ${sideLength} ft`);
          break;
        case 'cylinder':
          content.push(`Radius: ${radius} ft`);
          content.push(`Height: ${height} ft`);
          break;
      }
    
      content.push('');
      content.push(BOX.LIGHT.H.repeat(AOE_DISPLAY_WIDTH));
      content.push('');
    
      // Show tile count
      content.push(centerText('AFFECTED AREA', AOE_DISPLAY_WIDTH));
      content.push('');
      content.push(`Tiles affected: ${tiles.length} squares`);
      content.push(`Origin included: ${includeOrigin ? 'Yes' : 'No'}`);
    
      // If includeOrigin, show the origin position
      if (includeOrigin) {
        content.push(`Origin tile: (${origin.x}, ${origin.y}, ${origin.z ?? 0})`);
      }
    
      // Show sample tiles (first few)
      if (tiles.length > 0) {
        content.push('');
        const sampleSize = Math.min(5, tiles.length);
        content.push(`Sample tiles (first ${sampleSize}):`);
        for (let i = 0; i < sampleSize; i++) {
          const t = tiles[i];
          content.push(`  (${t.x}, ${t.y}, ${t.z ?? 0})`);
        }
        if (tiles.length > sampleSize) {
          content.push(`  ... and ${tiles.length - sampleSize} more`);
        }
      }
    
      // Find creatures in AoE if encounterId provided
      if (encounterId) {
        content.push('');
        content.push(BOX.LIGHT.H.repeat(AOE_DISPLAY_WIDTH));
        content.push('');
        content.push(centerText('CREATURES IN AoE', AOE_DISPLAY_WIDTH));
        content.push('');
    
        // This would check encounter participants
        // For now, show placeholder
        content.push('(Encounter integration pending)');
      }
    
      // Show excluded IDs if any
      if (excludeIds.length > 0) {
        content.push('');
        content.push(`Excluded: ${excludeIds.join(', ')}`);
      }
    
      return createBox('AREA OF EFFECT', content);
    }
  • Zod schema for validating calculate_aoe input parameters, including shape-specific refinements.
    export const calculateAoeSchema = z.object({
      encounterId: z.string().optional(),
      shape: AoeShapeSchema,
      origin: PositionSchema,
    
      // Shape-specific parameters
      length: z.number().optional(),    // Line, Cone
      width: z.number().default(5).optional(),  // Line
      radius: z.number().optional(),    // Sphere, Cylinder
      sideLength: z.number().optional(), // Cube
      height: z.number().optional(),    // Cylinder
    
      direction: DirectionSchema.optional(),
    
      // Options
      includeOrigin: z.boolean().default(false),
      excludeIds: z.array(z.string()).optional(),
    }).refine((data) => {
      // Validate required parameters based on shape
      switch (data.shape) {
        case 'sphere':
          return data.radius !== undefined;
        case 'cone':
          return data.length !== undefined;
        case 'line':
          return data.length !== undefined;
        case 'cube':
          return data.sideLength !== undefined;
        case 'cylinder':
          return data.radius !== undefined && data.height !== undefined;
        default:
          return true;
      }
    }, {
      message: 'Missing required parameters for shape',
    });
  • Tool registration in the central registry, including name, description, schema conversion, and wrapper handler with validation and error handling.
    calculate_aoe: {
      name: 'calculate_aoe',
      description: 'Calculate area of effect for D&D 5e spells/abilities (sphere, cone, line, cube, cylinder)',
      inputSchema: toJsonSchema(calculateAoeSchema),
      handler: async (args) => {
        try {
          const validated = calculateAoeSchema.parse(args);
          const result = calculateAoe(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