shk_parser 0.1.1

A parser for Stronghold Kingdoms attack formation files (.cas)
Documentation
# SHK Parser


A Rust library for parsing Stronghold Kingdoms attack formation files (`.cas` files).

## Features


- ๐Ÿš€ **Fast & Safe**: Written in Rust with zero-copy parsing where possible
- ๐ŸŽฏ **Type-Safe**: Strong typing for all unit types and abilities
- ๐Ÿ“– **Well-Documented**: Comprehensive API documentation and examples
- ๐Ÿงช **Well-Tested**: Extensive test coverage with real game files
- ๐Ÿ”ง **Easy to Use**: Simple, clean API with helpful error messages
- ๐ŸŒ **Serialization**: Optional JSON support via serde
- ๐Ÿ’ป **CLI Tool**: Command-line interface with multiple output formats
- โšก **Better Errors**: Detailed error messages with thiserror

## Optional Features


Enable additional functionality with cargo features:

```toml
[dependencies]
shk_parser = { version = "0.1.0", features = [
  "serde",
  "tsify",
  "cli"
] }
```

- **`serde`**: Enables JSON serialization/deserialization
- **`tsify`**: Enables TypeScript type generation for WASM bindings (requires `serde`)
- **`cli`**: Enables the command-line interface

## Quick Start


Add this to your `Cargo.toml`:

```toml
[dependencies]
shk_parser = "0.1.0"
```

Parse a formation file:

```rust
use shk_parser::parse_formation_file;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let units = parse_formation_file("my_formation.cas")?;

    println!("Formation contains {} units:", units.len());
    for (i, unit) in units.iter().enumerate() {
        println!("  {}: {}", i + 1, unit);
    }

    Ok(())
}
```

## Supported Units


The parser supports all Stronghold Kingdoms unit types:

### Basic Units

- **Archer**: Basic ranged units
- **Pikeman**: Basic melee units

### Advanced Units

- **Catapult**: Siege weapons with target coordinates
- **Captain**: Special command units with various abilities

### Captain Abilities

- **Delay**: Wait for a specified time before acting
- **Rallying Cry**: Rally nearby troops to boost morale
- **Arrow Volley**: Coordinate arrow attack at target location
- **Battle Cry**: Boost unit morale and effectiveness
- **Catapults Volley**: Coordinate catapult bombardment at target

## API Reference


### Core Functions


```rust
// Parse from raw bytes
fn parse_formation(data: &[u8]) -> Result<Vec<UnitRecord>, ParseError>

// Parse directly from file path
fn parse_formation_file<P: AsRef<Path>>(path: P) -> Result<Vec<UnitRecord>, ParseError>
```

### Types


```rust
pub struct UnitRecord {
    pub position: Position,
    pub unit_type: UnitType,
}

pub struct Position {
    pub x: u8,
    pub y: u8,
}

pub enum UnitType {
    Archer,
    Pikeman,
    Catapult { target: Position },
    Captain { ability: CaptainAbility, wait_time: u8 },
    Unknown(u8),
}

pub enum CaptainAbility {
    Delay,
    RallyingCry,
    ArrowVolley { target: Position },
    BattleCry,
    CatapultsVolley { target: Position },
    Unknown(u8),
}
```

## Command Line Usage


With the `cli` feature enabled, you can use the binary tool:

```bash
# Parse all test files (default behavior)

cargo run --features cli --bin parse_formations

# Parse specific files

cargo run --features cli --bin parse_formations -- file1.cas file2.cas

# Verbose output with detailed parsing info

cargo run --features cli --bin parse_formations -- --verbose file.cas

# JSON output (requires serde feature)

cargo run --features cli,serde --bin parse_formations -- --format json file.cas
```

### CLI Options


```
A parser for Stronghold Kingdoms formation files (.cas)

Usage: parse_formations [OPTIONS] [FILES]...

Arguments:
  [FILES]...  Formation file(s) to parse

Options:
  -f, --format <FORMAT>  Output format [default: human]
  -v, --verbose          Show detailed unit information
  -h, --help             Print help
```

## File Format


`.cas` files use a simple binary format:

1. **Header** (4 bytes): Number of units as little-endian u32
2. **Unit Records** (variable length): One record per unit

### Record Formats


| Unit Type | Size | Format |
|-----------|------|--------|
| Archer/Pikeman | 3 bytes | `x, y, unit_type` |
| Catapult | 5 bytes | `x, y, unit_type, target_x, target_y` |
| Captain (simple) | 4 bytes | `x, y, unit_type, wait_time` |
| Captain (with target) | 6 bytes | `x, y, unit_type, wait_time, target_x, target_y` |

## Examples


### Parse and Display All Units


```rust
use shk_parser::parse_formation_file;

let units = parse_formation_file("formation.cas")?;
for unit in &units {
    match &unit.unit_type {
        UnitType::Archer => println!("Archer at ({}, {})", unit.position.x, unit.position.y),
        UnitType::Captain { ability, wait_time } => {
            println!("Captain using {:?} for {}s at ({}, {})",
                ability, wait_time, unit.position.x, unit.position.y);
        }
        _ => println!("{}", unit),
    }
}
```

### Filter by Unit Type


```rust
use shk_parser::{parse_formation_file, UnitType};

let units = parse_formation_file("formation.cas")?;

// Find all captains
let captains: Vec<_> = units.iter()
    .filter(|unit| matches!(unit.unit_type, UnitType::Captain { .. }))
    .collect();

println!("Found {} captains", captains.len());
```

### Access Captain Abilities


```rust
use shk_parser::{parse_formation_file, UnitType, CaptainAbility};

let units = parse_formation_file("formation.cas")?;

for unit in &units {
    if let UnitType::Captain { ability, wait_time } = &unit.unit_type {
        match ability {
            CaptainAbility::ArrowVolley { target } => {
                println!("Arrow volley targeting ({}, {}) after {}s",
                    target.x, target.y, wait_time);
            }
            CaptainAbility::Delay => {
                println!("Waiting for {}s", wait_time);
            }
            _ => println!("Captain ability: {:?}", ability),
        }
    }
}
```

## Error Handling


The library provides detailed error information:

```rust
use shk_parser::{parse_formation_file, ParseError};

match parse_formation_file("formation.cas") {
    Ok(units) => println!("Parsed {} units", units.len()),
    Err(ParseError::FileNotFound(path)) => eprintln!("File not found: {}", path),
    Err(ParseError::InvalidFormat(msg)) => eprintln!("Invalid file format: {}", msg),
    Err(ParseError::IoError(err)) => eprintln!("IO error: {}", err),
}
```

## Testing


Run the test suite:

```bash
cargo test
```

The library includes tests with real `.cas` files to ensure compatibility.

## License


Licensed under either of

 * Apache License, Version 2.0 ([LICENSE-APACHE]LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
 * MIT license ([LICENSE-MIT]LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.