<!-- Generated from sdk/bindings/powershell/README.md and protocol/v2/api.json by protocol/v2/codegen/docs.js; do not edit. Run `make api`. -->
# PowerShell on the .NET binding

PowerShell uses the same generated `net8.0` assembly as C# and F#.
The SDK launcher loads it before parsing a robot's class declarations:
`pwsh -NoProfile -File /opt/clunkyard/sdk/bindings/powershell/run.ps1 bot.ps1`.
There is no copied module or separate protocol, tracking or geometry
implementation. The assembly loads `libclunkyard.so.2`, or the file named
by `CLUNKYARD_LIB`.

Subsystems and facts are properties; methods use PascalCase. Absent values
are `$null`. Pass `$null` for a control field to keep its earlier value in
the turn. `Drive.Get('throttle')` reads the pending value. Throw
`[Clunkyard.Forfeit]::new(code, message)` to forfeit. Other exceptions are
logged and send the controls already set. The .NET `Clunkyard.Play` method
plays lines in memory for tests.

## A tiny robot

```powershell
using namespace Clunkyard

class Tiny : Clunkyard.Robot {
    [void] OnTurn(){
        $target=$this.Sensors.Nearest
        if($null -eq $target){
            $this.Drive.Set(0.75,0.25,$null)
            $this.Scanner.Set($this.Me.Heading,40,$null)
            $this.Status.Set('SEARCH',$this.Scanner.Last.Arc)
            return
        }
        $power=$this.Gun.PowerForFlightTime($target.Range,1)
        $aim=$this.Gun.Lead($target,$power)
        $heading=if($null -eq $aim){$target.Bearing}else{$aim.Heading}
        $pitch=if($null -eq $aim){$target.Elevation}else{$aim.Pitch}
        $this.Gun.Aim($heading,$pitch)
        if($this.Gun.CanFire($power,10)){$this.Gun.Fire($power)}
        $this.Drive.Set(0.5,$this.Angles.Clamp($this.Angles.AngleDiff($target.Bearing,$this.Me.Heading)),$null)
        $this.Scanner.Set($target.Bearing,10,$null)
        $this.Status.Set('TRACK',$target.Range)
    }
}

[Clunkyard.Clunkyard]::Run([Tiny]::new())
```

`make test SDK=...` runs the shared assembly's complete conformance
transcript through PowerShell. The README example also participates in the
cross-language act identity check.

## Names

Every entry of the robot API 2.0.0 in PowerShell.
[names.md](names.md) has every language side by side.

| Canonical | Form | PowerShell |
| --- | --- | --- |
| `match.mode` | property | Match.Mode |
| `match.ruleset` | property | Match.Ruleset |
| `match.control` | property | Match.Control |
| `match.robots` | property | Match.Robots |
| `match.is_3d` | property | Match.Is3d |
| `match.tick_rate` | property | Match.TickRate |
| `match.max_ticks` | property | Match.MaxTicks |
| `match.robot_id` | call | Match.RobotId |
| `clock.tick` | property | Clock.Tick |
| `clock.seconds` | property | Clock.Seconds |
| `clock.remaining_ticks` | property | Clock.RemainingTicks |
| `arena.size` | property | Arena.Size |
| `arena.gravity` | property | Arena.Gravity |
| `arena.terrain_kind` | property | Arena.TerrainKind |
| `arena.ground_height` | call | Arena.GroundHeight |
| `me.health` | property | Me.Health |
| `me.position` | property | Me.Position |
| `me.velocity` | property | Me.Velocity |
| `me.heading` | property | Me.Heading |
| `me.pitch` | property | Me.Pitch |
| `me.roll` | property | Me.Roll |
| `me.angular_velocity` | property | Me.AngularVelocity |
| `me.attitude` | property | Me.Attitude |
| `me.grounded` | property | Me.Grounded |
| `me.altitude` | property | Me.Altitude |
| `me.applied` | property | Me.Applied |
| `battery.charge` | property | Battery.Charge |
| `battery.capacity` | property | Battery.Capacity |
| `battery.regen` | property | Battery.Regen |
| `battery.sustainable_drive` | property | Battery.SustainableDrive |
| `battery.compute` | property | Battery.Compute |
| `battery.drive_cost` | call | Battery.DriveCost |
| `drive.hover_lift` | property | Drive.HoverLift |
| `drive.set` | control | Drive.Set |
| `drive.forces` | control | Drive.Forces |
| `drive.get` | call | Drive.Get |
| `gun.aim_now` | property | Gun.AimNow |
| `gun.cooldown_ticks` | property | Gun.CooldownTicks |
| `gun.spread` | property | Gun.Spread |
| `gun.max_power` | property | Gun.MaxPower |
| `gun.damage_scale` | property | Gun.DamageScale |
| `gun.can_fire` | call | Gun.CanFire |
| `gun.shot_speed` | call | Gun.ShotSpeed |
| `gun.shot_cost` | call | Gun.ShotCost |
| `gun.reload_ticks` | call | Gun.ReloadTicks |
| `gun.shot_damage` | call | Gun.ShotDamage |
| `gun.power_for_speed` | call | Gun.PowerForSpeed |
| `gun.power_for_flight_time` | call | Gun.PowerForFlightTime |
| `gun.lead` | call | Gun.Lead |
| `gun.lead_point` | call | Gun.LeadPoint |
| `gun.aim` | control | Gun.Aim |
| `gun.fire` | control | Gun.Fire |
| `gun.get` | call | Gun.Get |
| `scanner.last` | property | Scanner.Last |
| `scanner.proximity_range` | property | Scanner.ProximityRange |
| `scanner.reach` | call | Scanner.Reach |
| `scanner.arc_for_reach` | call | Scanner.ArcForReach |
| `scanner.set` | control | Scanner.Set |
| `scanner.get` | call | Scanner.Get |
| `sensors.contacts` | property | Sensors.Contacts |
| `sensors.nearest` | property | Sensors.Nearest |
| `sensors.cues` | property | Sensors.Cues |
| `sensors.contact` | call | Sensors.Contact |
| `sensors.position_of` | call | Sensors.PositionOf |
| `tracker.cue` | property | Tracker.Cue |
| `tracker.nearest_bearing_rate` | property | Tracker.NearestBearingRate |
| `tracker.velocity` | call | Tracker.Velocity |
| `tracker.position` | call | Tracker.Position |
| `tracker.last_seen` | call | Tracker.LastSeen |
| `tracker.configure` | call | Tracker.Configure |
| `nav.zone` | property | Nav.Zone |
| `nav.zone.margin` | call | Nav.Zone.Margin |
| `nav.zone.contains` | call | Nav.Zone.Contains |
| `nav.zone.distance_from` | call | Nav.Zone.DistanceFrom |
| `nav.storm` | property | Nav.Storm |
| `nav.storm.margin` | call | Nav.Storm.Margin |
| `nav.storm.contains` | call | Nav.Storm.Contains |
| `nav.storm.distance_from` | call | Nav.Storm.DistanceFrom |
| `nav.hill` | property | Nav.Hill |
| `nav.hill.margin` | call | Nav.Hill.Margin |
| `nav.hill.contains` | call | Nav.Hill.Contains |
| `nav.hill.distance_from` | call | Nav.Hill.DistanceFrom |
| `nav.pickups` | property | Nav.Pickups |
| `nav.nearest_pickup` | call | Nav.NearestPickup |
| `nav.field_distance` | call | Nav.FieldDistance |
| `score.me` | property | Score.Me |
| `score.best` | property | Score.Best |
| `score.armour` | property | Score.Armour |
| `angles.normalize` | call | Angles.Normalize |
| `angles.angle_diff` | call | Angles.AngleDiff |
| `angles.bearing_to` | call | Angles.BearingTo |
| `angles.elevation_to` | call | Angles.ElevationTo |
| `angles.direction` | call | Angles.Direction |
| `angles.distance` | call | Angles.Distance |
| `angles.clamp` | call | Angles.Clamp |
| `status.set` | control | Status.Set |
| `status.get` | call | Status.Get |
| `raw.number` | call | Raw.Number |
| `raw.text` | call | Raw.Text |
| `raw.has` | call | Raw.Has |
| `raw.flag` | call | Raw.Flag |
| `raw.count` | call | Raw.Count |
| `raw.line` | call | Raw.Line |
| `raw.extra` | call | Raw.Extra |
| `session.event` | property | Session.Event |
| `session.next` | call | Session.Next |
| `session.send` | call | Session.Send |
| `session.forfeit` | call | Session.Forfeit |
| `session.log` | call | Session.Log |
| `session.feed` | call | Session.Feed |
| `session.reply` | call | Session.Reply |
