# Lightsaber +

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4><i class="fa-clock-rotate-left">:clock-rotate-left:</i></h4></td><td>Changelogs</td><td><a href="/pages/dzu0DLXU2151dv4i49B7">/pages/dzu0DLXU2151dv4i49B7</a></td></tr><tr><td><h4><i class="fa-hexagon-exclamation">:hexagon-exclamation:</i></h4></td><td>Help/Knownledgebase</td><td><a href="/pages/xr2uaM8jIKHAaYWnfqon">/pages/xr2uaM8jIKHAaYWnfqon</a></td></tr></tbody></table>

## Code Documentation

## **🪝Hooks**

### 🟦 `lsp_playerloaded(ply,playerdata)`

**Description**

called after initialize a Player

***

## Inventory

### 🟦 `{P}:LSP_getInventoryData()`

**Description**

returns the data table from the player inventory

**Returns**

| Type  | Description     |
| ----- | --------------- |
| table | Playerinventory |

### 🟦 `{P}:LSP_updateInventoryData( table data )`

**Description**

replaces with (data) the data table of the inventory WITHOUT converting it in the database

**Arguments**

| Name | Type  | Description              |
| ---- | ----- | ------------------------ |
| data | table | New inventory data table |

### 🟦 `{P}:giveItem(id)`

**Description**

Gives the player the item with the given ID.

**Arguments**

| Name | Type   | Description |
| ---- | ------ | ----------- |
| id   | string | Item ID     |

### 🟦 `{P}:LSP_getInventoryData()`

**Description**

Returns the data table from the player inventory.

**Returns**

| Type  | Description                 |
| ----- | --------------------------- |
| table | Player inventory data table |

### 🟦 `{P}:LSP_updateInventoryData( table data )`

**Description**

Replaces the inventory data table with the given data WITHOUT saving it to the database.

**Arguments**

| Name | Type  | Description              |
| ---- | ----- | ------------------------ |
| data | table | New inventory data table |

### 🟦 `{P}:LSP_saveInventoryData( table inventory )`

**Description**

Replaces the inventory data table and saves it permanently to the database.

**Arguments**

| Name      | Type  | Description                               |
| --------- | ----- | ----------------------------------------- |
| inventory | table | Inventory data table to store permanently |

### 🟦 `{P}:LSP_setInventoryData( string itemToAdd, int pos, int prevPos )`

**Description**

Adds an item to the inventory and saves the change permanently to the database.

**Example usage:**

```lua
net.Receive("LSP:SaveNewItemPos", function(len,ply)
	local item = net.ReadString()
	local pos = net.ReadUInt(32)
	local prevPos = net.ReadUInt(32)
	ply:LSP_setInventoryData(item,!pos and nil or pos,prevPos and prevPos or nil)
end)
```

{% hint style="warning" %}
**Warning:** Please only use this function if you know what you are doing, otherwise use the :giveItem() function..
{% endhint %}

**Arguments**

| Name      | Type   | Description                                |
| --------- | ------ | ------------------------------------------ |
| itemToAdd | string | Item identifier (internal ITEM index only) |
| pos       | int    | Target inventory slot                      |
| prevPos   | int    | Previous inventory slot                    |

{% hint style="info" %}
**Notes**

* itemToAdd is only intended for use with the internal ITEM indices.
  {% endhint %}

### 🟦 `{P}:haveItem( string itemToCheck )`

**Description**

Checks whether the player owns the given item.

**Arguments**

| Name        | Type   | Description                                         |
| ----------- | ------ | --------------------------------------------------- |
| itemToCheck | string | Item identifier to check (internal ITEM index only) |

**Returns**

| Type | Description                                      |
| ---- | ------------------------------------------------ |
| bool | True if the player has the item, otherwise false |

{% hint style="info" %}
**Notes**

* itemToCheck is only intended for use with the internal ITEM indices.
  {% endhint %}

### 🟦 `{P}:LSP_removeInventoryData( int itemToRemove )`

**Description**

Removes an item from the inventory.

**Arguments**

| Name         | Type | Description                            |
| ------------ | ---- | -------------------------------------- |
| itemToRemove | int  | Inventory slot or item index to remove |

## Lightsaber

### 🟦 `{LS}:LSP_setHilt( bool left, string item )`

**Description**

Sets the saber hilt item.

**Arguments**

| Name | Type   | Description                                     |
| ---- | ------ | ----------------------------------------------- |
| left | bool   | Left saber flag                                 |
| item | string | Only intended for use with our own ITEM indices |

{% hint style="info" %}
**Notes**

* Do not change the offhand saber while holding it in your hand. Intended for sabercrafter while temporarily in OHAND mode. left = false!
  {% endhint %}

### 🟦 `{P}:LSP_proveOffhandSaber( int saberID )`

**Description**

Assigns the given saber to the Offhand (left hand) instead of the Onhand (right hand).

**Arguments**

| Name    | Type | Description |
| ------- | ---- | ----------- |
| saberID | int  | Saber ID    |

### 🟦 `{P}:LSP_proveOnhandSaber( int saberID )`

**Description**

Assigns the given saber to the Onhand (right hand) instead of the Offhand (left hand).

**Arguments**

| Name    | Type | Description |
| ------- | ---- | ----------- |
| saberID | int  | Saber ID    |

### 🟦 `{P}:LSP_clearOffhandSaber( int saberID )`

**Description**

Removes the saber from the Offhand (left hand) without changing the Onhand (right hand).

**Arguments**

| Name    | Type | Description |
| ------- | ---- | ----------- |
| saberID | int  | Saber ID    |

### 🟦 `{P}:LSP_clearOnhandSaber( int saberID )`

**Description**

Removes the saber from the Onhand (right hand) without changing the Offhand (left hand).

**Arguments**

| Name    | Type | Description |
| ------- | ---- | ----------- |
| saberID | int  | Saber ID    |

### 🟦 `{LS}:LSP_setHilt( bool left, string item )`

**Description**

Sets the hilt for either Offhand (left = true) or Onhand (left = false).

**Arguments**

| Name | Type   | Description                    |
| ---- | ------ | ------------------------------ |
| left | bool   | true = Offhand, false = Onhand |
| item | string | Item index                     |

### 🟦 `{LS}:LSP_setCrystal( bool left, integer pos, string crystal )`

**Description**

Sets a crystal for either Offhand (left = true) or Onhand (left = false).

**Arguments**

| Name    | Type    | Description                    |
| ------- | ------- | ------------------------------ |
| left    | bool    | true = Offhand, false = Onhand |
| pos     | integer | Crystal slot                   |
| crystal | string  | Item index                     |

### 🟦 `{LS}:LSP_removeCrystal( bool left, string pos )`

**Description**

Removes a crystal from either Offhand (left = true) or Onhand (left = false).

**Arguments**

| Name | Type   | Description                    |
| ---- | ------ | ------------------------------ |
| left | bool   | true = Offhand, false = Onhand |
| pos  | string | Crystal slot                   |

### 🟦 `{LS}:LSP_setCrystalInner( bool left, integer pos, string crystal )`

**Description**

Sets an inner crystal for either Offhand (left = true) or Onhand (left = false).

**Arguments**

| Name    | Type    | Description                    |
| ------- | ------- | ------------------------------ |
| left    | bool    | true = Offhand, false = Onhand |
| pos     | integer | Inner slot                     |
| crystal | string  | Item index                     |

### 🟦 `{LS}:LSP_removeCrystalInner( bool left, integer pos )`

**Description**

Removes an inner crystal from either Offhand (left = true) or Onhand (left = false).

**Arguments**

| Name | Type    | Description                    |
| ---- | ------- | ------------------------------ |
| left | bool    | true = Offhand, false = Onhand |
| pos  | integer | Inner slot                     |

### 🟦 `{LS}:LSP_setQuillonCrystal( bool left, integer pos, string crystal )`

**Description**

Sets a quillon crystal for either Offhand (left = true) or Onhand (left = false).

**Arguments**

| Name    | Type    | Description                    |
| ------- | ------- | ------------------------------ |
| left    | bool    | true = Offhand, false = Onhand |
| pos     | integer | Quillon slot                   |
| crystal | string  | Item index                     |

### 🟦 `{LS}:LSP_removeQuillonCrystal( bool left, integer pos )`

**Description**

Removes a quillon crystal from either Offhand (left = true) or Onhand (left = false).

**Arguments**

| Name | Type    | Description                    |
| ---- | ------- | ------------------------------ |
| left | bool    | true = Offhand, false = Onhand |
| pos  | integer | Quillon slot                   |

### 🟦 `LSP.DB_createSaber( string steamid64, string item, table crystals, table inners, table quillon, table quilloninner, int active, bool leftsaber, string sabername )`

**Description**

Creates a saber entry for either Offhand (leftsaber = true) or Onhand (leftsaber = false).

**Arguments**

| Name         | Type   | Description                    |
| ------------ | ------ | ------------------------------ |
| steamid64    | string | SteamID64                      |
| item         | string | Hilt item                      |
| crystals     | table  | Crystals                       |
| inners       | table  | Inner crystals                 |
| quillon      | table  | Quillon crystals               |
| quilloninner | table  | Inner quillon crystals         |
| active       | int    | Active flag                    |
| leftsaber    | bool   | true = Offhand, false = Onhand |
| sabername    | string | Saber name                     |

### 🟦 `LSP.DB_updateSaber( int saberid, string steamid64, string item, table crystals, table inners, table quillon, table quilloninner, int active, bool leftsaber, string sabername )`

**Description**

Updates a saber entry for either Offhand (leftsaber = true) or Onhand (leftsaber = false).

**Arguments**

| Name         | Type   | Description                    |
| ------------ | ------ | ------------------------------ |
| saberid      | int    | Saber ID                       |
| steamid64    | string | SteamID64                      |
| item         | string | Hilt item                      |
| crystals     | table  | Crystals                       |
| inners       | table  | Inner crystals                 |
| quillon      | table  | Quillon crystals               |
| quilloninner | table  | Inner quillon crystals         |
| active       | int    | Active flag                    |
| leftsaber    | bool   | true = Offhand, false = Onhand |
| sabername    | string | Saber name                     |

## Leveling

### 🟧🟦 `LSP.calculateXPincome(number level)`

**Description**

Calculates the XP gained for a given level.

**Details**

* Currently returns a fixed base XP value defined in the configuration.
* The level parameter is reserved for future scaling logic.

**Arguments**

| Name  | Type   | Description   |
| ----- | ------ | ------------- |
| level | number | Current level |

**Returns**

\| Type | Description | | --- | --- | --- | | number | Base XP value |

### 🟧🟦 `LSP.getLevelXP(number level)`

**Description**

Returns the total amount of XP required to have reached a specific level.

**Details**

* Level 1 always starts at 0 XP
* XP scales exponentially using xp\_growthExponent

**Arguments**

| Name  | Type   | Description  |
| ----- | ------ | ------------ |
| level | number | Target level |

**Returns**

| Type   | Description                     |
| ------ | ------------------------------- |
| number | Required XP for the given level |

### 🟦 `{P}:LSP_AddXP( int amount )`

**Description**

adds XP to the player

**Arguments**

| Name   | Type    | Description  |
| ------ | ------- | ------------ |
| amount | integer | amount of xp |

### 🟦 `{P}:LSP_AddPoints( int amount )`

**Description**

adds points to the player

**Arguments**

| Name   | Type    | Description      |
| ------ | ------- | ---------------- |
| amount | integer | amount of points |

### 🟦 `{P}:LSP_SetLevel( int amount )`

**Description**

set the level of the player

**Arguments**

| Name   | Type    | Description |
| ------ | ------- | ----------- |
| amount | integer | wich level  |

## Stamina

### 🟦 `{P}:LSP_useStamina( number reduce )`

**Description**

reduce this is the value to reduce the Stamina

**Arguments**

| Name   | Type   | Description             |
| ------ | ------ | ----------------------- |
| reduce | number | Value to reduce stamina |

### 🟧🟦 `{P}:LSP_canAffordStamina( number stamina )`

**Description**

This value is calculated against the current value and if it is less than 0 it returns false

**Arguments**

| Name    | Type   | Description   |
| ------- | ------ | ------------- |
| stamina | number | Cost to check |

**Returns**

\| Type | Description | | --- | --- | --- | | bool | Whether the countercalculated value is above 0 (>0 TRUE, <0 FALSE) |

## Force Powers

### Create a force power

**Description**

**1. Folder Structure**

Create a folder in your **addons** folder **(NOT in LightsaberPlus!)**

`garrysmod/addons/(YOUR-ADDON)/lua/lightsaberplus/powers/`

```
garrysmod
  addons
      YOUR-ADDON
          lua
              lightsaberplus
                  powers
                      your_forcepower.lua (THE NAME MUST BE UNIQUE!!!)
```

**Write your Power**

Template for Force Power building

```lua
local power = ForcePower
power.name = "UNIQUE NAME"
power.Author = "AUTHORNAME"
power.icon = "PATHTOICON"
power.desc = "DESCRIPTION"
power.sound = "PATHTOSOUND"
power.cost = number
power.cooldown = number
power.cfg = {
    cost = number,
    cooldown = number,
}

function power:OnExecute(ply)
    -- Code(ply)
end
```

### 🟦 `power:requireToUse(ply)`

**Description**

Define your own rules before you can use the ability.

Example:

```lua
function power:requireToUse(ply)
   local tar = ply:laneTarget(getPower(power.name).effectiveradius)
   if IsValid(tar) and tar:IsPlayer() then
       return true
   end

   return false
end
```

**Arguments**

| Name | Type   | Description            |
| ---- | ------ | ---------------------- |
| ply  | PLAYER | Player using the power |

**Returns**

\| Type | Description | | --- | --- | --- | | bool | false: Denied, true: Approved |

### 🟧🟦 `{power}:LoopStart( ply PLAYER )`

**Description**

**Example**

```lua
function power:LoopStart(ply)
   if ( !ply.lsp_plyCHSound ) then
       ply.lsp_plyCHSound = CreateSound( ply, "ambient/levels/citadel/field_loop1.wav" )
       ply.lsp_plyCHSound:Play()
   else
       ply.lsp_plyCHSound:Play()
   end
   ply:anim("wos_hatred_loop",1, 500)
end
```

**Details**

* Use this to start any continuous behavior that should persist while the power is active.
* Typically paired with LoopEnd to clean up.

**Arguments**

| Name | Type   | Description            |
| ---- | ------ | ---------------------- |
| ply  | PLAYER | Player using the power |

{% hint style="info" %}
**Notes**

* Always stop sounds / timers / effects in LoopEnd to avoid leaks.
  {% endhint %}

### 🟧🟦 `{power}:LoopEnd( ply PLAYER )`

**Description**

**Example**

```lua
function power:LoopEnd(ply)
   if ( ply.lsp_plyCHSound ) then
       ply.lsp_plyCHSound:Stop()
       ply.lsp_plyCHSound = nil
   end
   ply:endAnim()
end
```

**Details**

* Stop looping sounds, remove timers, stop animations, reset states, etc.

**Arguments**

| Name | Type   | Description            |
| ---- | ------ | ---------------------- |
| ply  | PLAYER | Player using the power |

{% hint style="info" %}
**Notes**

* If you created a sound object, make sure to Stop() it and set it to nil.
  {% endhint %}

### 🟧🟦 `meta PLAYER:FindFirstLivingThreatAhead(dist NUMBER) | Player`

**Description**

Performs a forward sweep to detect the first living threat in front of the player.

**Details**

* Iterates forward in steps of 100 units up to the given distance.
* At each step, scans a 75-unit radius sphere along the player's forward direction.

**Arguments**

| Name | Type   | Description    |
| ---- | ------ | -------------- |
| dist | NUMBER | Sweep distance |

**Returns**

| Type         | Description                  |
| ------------ | ---------------------------- |
| Player / NPC | First detected living threat |
| nil          | If no valid entity is found  |

{% hint style="info" %}
**Notes**

* Detection order: first NPC found, or first living player that is not self.
  {% endhint %}

### 🟧🟦 `meta PLAYER:FindFirstLivingPlayerAheadWide(dist NUMBER) | Player`

**Description**

Performs a wide forward sweep to find the first living player ahead.

**Details**

* Uses the same sweep logic as FindFirstLivingThreatAhead, but with a wider scan radius.
* Step size: 100 units
* Sphere radius: 150 units

**Arguments**

| Name | Type   | Description    |
| ---- | ------ | -------------- |
| dist | NUMBER | Sweep distance |

**Returns**

| Type   | Description                  |
| ------ | ---------------------------- |
| Player | First matching living player |
| nil    | If none found                |

{% hint style="info" %}
**Notes**

* Living players only.
* Self is excluded.
  {% endhint %}

### 🟧🟦 `meta PLAYER:FindFirstLivingThreatAhead(dist NUMBER) | Player`

**Description**

Performs a forward-moving scan for the first living player ahead.

**Details**

* This version actively moves the player forward during each iteration:
* Forward() \* (50 \* abs(i)) + Vector(0,0,3)
* After each movement, it scans a 75-unit radius sphere with an additional forward offset.

**Arguments**

| Name | Type   | Description   |
| ---- | ------ | ------------- |
| dist | NUMBER | Scan distance |

**Returns**

\| Type | Description | | --- | --- | --- | | Player | First detected living player | | nil | If none found |

{% hint style="info" %}
**Notes**

* Living players only.
* Self is excluded.
  {% endhint %}

### 🟧🟦 `meta PLAYER:FindFirstRelevantEntityAhead(dist NUMBER) | Entity`

**Description**

Sweeps forward and returns the first relevant entity found.

**Details**

* Iterates forward in 100-unit steps, scanning a 75-unit radius sphere.

**Arguments**

| Name | Type   | Description    |
| ---- | ------ | -------------- |
| dist | NUMBER | Sweep distance |

**Returns**

\| Type | Description | | --- | --- | --- | | Entity | First matching entity | | nil | If no match is found |

{% hint style="info" %}
**Notes**

* Detection rules:
* Entity with v.LFS == true (e.g. vehicles)
* Entity class "prop\_physics"
* Player (excluding self)
  {% endhint %}

### 🟧🟦 `meta PLAYER:ForEachEntityAhead(dist NUMBER, func FUNCTION) | Player`

**Description**

Executes a callback for every entity detected in a forward sweep.

**Details**

* Step size: 100 units
* Scan radius: 75 units
* No deduplication (same entity may be hit multiple times)

**Arguments**

| Name | Type     | Description                                         |
| ---- | -------- | --------------------------------------------------- |
| dist | NUMBER   | Sweep distance                                      |
| func | FUNCTION | Callback called for every hit (may repeat entities) |

**Returns**

\| Type | Description | | --- | --- | --- | | Player | Self |

{% hint style="info" %}
**Notes**

* Detection rules: v.LFS == true, "prop\_physics", Player (excluding self), NPC
* Callback signature: func(self, v)
* Tip: use a seen table if duplicates are undesirable.
  {% endhint %}

### 🟧🟦 `meta PLAYER:ForEachLivingTargetAhead(dist NUMBER, max NUMBER, func FUNCTION) | Table`

**Description**

Iterates over unique living targets in front of the player and executes a callback.

**Details**

* Step size: 100 units
* Scan radius: 125 units
* Deduplicates entities so each target is processed once

**Arguments**

| Name | Type     | Description                                     |
| ---- | -------- | ----------------------------------------------- |
| dist | NUMBER   | Sweep distance                                  |
| max  | NUMBER   | Optional limit of unique hits (stops early)     |
| func | FUNCTION | Callback executed once per unique living target |

**Returns**

\| Type | Description | | --- | --- | --- | | Table | Set of all processed entities (hasHits / seen) |

{% hint style="info" %}
**Notes**

* Detection rules: living players (excluding self) + NPCs
* Callback signature: func(self, v)
* If max is provided, stops after max unique hits
  {% endhint %}

### 🟧🟦 `meta PLAYER:getMaxForce() | Number`

**Description**

Returns the maximum amount of force points the player can have.

**Details**

* Accesses the player's force data and returns the upper force limit.

**Returns**

| Type   | Description          |
| ------ | -------------------- |
| Number | Maximum force points |

### 🟧🟦 `meta PLAYER:getForce() | Number`

**Description**

Returns the player's current force points.

**Details**

* Represents the currently available force that can be spent on powers.

**Returns**

| Type   | Description          |
| ------ | -------------------- |
| Number | Current force points |

### 🟧🟦 `meta PLAYER:LSP.GetPower(String key) | Table`

**Description**

Returns a force power by its keyword.

**Details**

* The keyword is used to look up and return the corresponding power definition.

**Arguments**

| Name | Type   | Description                          |
| ---- | ------ | ------------------------------------ |
| key  | String | Unique identifier of the force power |

**Returns**

\| Type | Description | | --- | --- | --- | | Table | Force power data |

### 🟧🟦 `LSP.getALLpowers() | Table`

**Description**

Returns all registered force powers.

**Details**

* Provides direct access to the internal force power registry.
* Each entry contains the data and behavior associated with a force power.

**Returns**

| Type  | Description                                    |
| ----- | ---------------------------------------------- |
| Table | All available force powers keyed by identifier |

### 🟧🟦 `meta PLAYER:allowUsePower(boolean state)`

**Description**

**Example**

```lua
ply:allowUsePower(true)
```

**Details**

* Updates the player's synced LSP data and controls whether powers can be used.

**Arguments**

| Name  | Type    | Description                                  |
| ----- | ------- | -------------------------------------------- |
| state | boolean | true can use powers, false cannot use powers |

## Forms

### Create a form

**Description**

**Create new Forms**

**Example Form:** `lightsaberplus/lua/lightsaberplus/forms/soresu.lua`

**What LSP.buildForm Does**

`LSP.buildForm(index, data)` registers a combat form by storing the `data` table at `LSP.Config.Forms[index]`.

Important: The function reads fields and computes default values, but it **does not write those defaults back** to `data`. The stored table is exactly what you pass in.

**Data Schema (What You Can Put In `data`)**

Top-level fields:

* `desc` (string): UI tooltip/description.
* `icon` (string): Displayed in UI and used for sorting.
* `cost` (number): Points required to buy the form.
* `lvl` (number): Present in files, currently not used by code.
* `hold` (string): Weapon hold type while saber is on.
* `block` (string): `"slam"` for slam hold type, otherwise animation name.
* `walk`, `idle`, `run` (string): Movement animation sequences.
* `restriction` (function): Defined in forms but **not used** by current logic.
* `a`, `w`, `d`, `wd`, `wa` (array): Attack tables by movement direction.
* `s` (array, optional): Backward attack table.
* `special` (table, optional): Special air attack.

Attack entry fields (used in `lightsaber_base/init.lua`):

* `anim` (string): Sequence name.
* `rate` (number): Playback rate.
* `shave` (number): Subtracted from animation length.
* `forcedTime` (number, optional): Overrides timing.
* `speed` (number): Movement slow while attacking.
* `dmg` (number): Damage multiplier.

Optional timing modifiers:

* `lightattackdelay`, `midattackdelay`, `heavyattackdelay`, `reduceblockafford` (number): Multiplier for cooldown timing.

Special attack structure:

* `special.charge.anim` (string)
* `special.attack.anim` (string)
* `special.damagemultiplier` (number, optional)

**Important Gotchas**

* Defaults inside `LSP.buildForm` are **not applied** to the stored data.
* `restriction` in the form table is **unused**; restrictions are handled via `LSP.Config.RestrictForms`.
* Empty attack arrays will break combo selection (`math.random(1, #formT.w)`).
* `reduceblockafford` exists in some forms, but combat checks `rereduceblockafford`. If you want it to work, you must use the exact key the combat code reads.

**Minimal Example**

```lua
LSP.buildForm("MyForm", {
   desc = "Short description for the menu.",
   icon = "I",
   cost = 0,
   lvl = 10,

   hold = "melee2",
   block = "slam",
   walk = "melee2",
   idle = "vanguard_f_idle",
   run  = "phalanx_b_run",

   a  = { {anim="judge_b_left_t1", rate=1, dmg=1.0, shave=0.1, speed=2100} },
   w  = { {anim="judge_b_s3_t3",   rate=1, dmg=1.0, shave=0.0, speed=100} },
   d  = { {anim="judge_r_right_t1",rate=1, dmg=1.0, shave=0.1, speed=2100} },
   wd = { {anim="vanguard_b_right_t3", rate=1, dmg=1.0, shave=0.25, speed=100} },
   wa = { {anim="vanguard_b_left_t1",  rate=1, dmg=1.0, shave=0.25, speed=100} },
})
```

## Synced data

### Player datavars

**Description**

Uebersicht der synchronisierten Datavars (LEVEL, XP, POINTS, swordPosR/L, HiltR/L, isBlocking, unlockedForms, unlockedSkills, saberForm).

**Table**

| Data Var       | Type                                            | function?                                       |
| -------------- | ----------------------------------------------- | ----------------------------------------------- |
| LEVEL          | number                                          | Level of the Player                             |
| XP             | number                                          | XP of the Player                                |
| POINTS         | number                                          | Points of the Player                            |
| swordPosR \| L | bool or String(LSP.Config.HolsterPositions$Key) | Position of the SwordHolster (false) == Default |
| HiltR \| L     | bool                                            | provides the active Saber for holster           |
| isBlocking     | bool                                            | if the Player blocking                          |
| unlockedForms  | table                                           | Unlocked Forms if you use the Whitelist         |
| unlockedSkills | table                                           | Unlocked Skills if you use the Whitelist        |
| saberForm      | string                                          | currentSaberForm                                |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://symliaas-scripts.gitbook.io/symscripts/garrys-mod/lightsaber-+.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
