diff --git a/projects/GunsAndGadgets/operations.md b/projects/GunsAndGadgets/operations.md index 3acc776..bec543f 100644 --- a/projects/GunsAndGadgets/operations.md +++ b/projects/GunsAndGadgets/operations.md @@ -29,9 +29,10 @@ triggers and the data preserved when stats change. ## Ammunition selection -Crouch and right-click with a gun to cycle through compatible ammunition carried -in the inventory. The next reload uses the selected calibre, and the choice is -saved on that gun. Already loaded ammunition stays loaded. Without a selection, +Press the swap-hands key with a gun in hand to cycle through compatible +ammunition carried in the inventory (crouching aims instead, see "Draw time and +aiming"). Messages name the player's own key binding. The next reload uses the +selected calibre, and the choice is saved on that gun. Already loaded ammunition stays loaded. Without a selection, reloads use the first compatible ammunition carried. The action bar confirms the selection and carried amount, or reports that no @@ -56,6 +57,8 @@ multiplier 1, no falloff. | `max-spread-degrees` | Upper limit for the final launch spread. No limit when left out. | | `falloff.start-distance` | Bullets do full damage up to this many blocks from the muzzle. | | `falloff.min-multiplier` | Damage multiplier at the shot's maximum range, reached linearly. `1` turns falloff off. | +| `rockets.safe-distance`, `rockets.min-multiplier` | A rocket blast hurts others by `min-multiplier` (0.1) until the rocket has flown `safe-distance` (4) blocks, so firing at the ground at your feet barely hurts anyone else. The shooter always takes their own blast in full. | +| `rockets.full-damage-distance` | The blast reaches full damage at this many blocks flown (40), rising linearly from the safe distance. Left out or `0`: the old arming time (full after one second of flight), which made slower rockets hit harder. | Non-finite values (`.nan`, `.inf`) fall back to each key's default. @@ -80,6 +83,257 @@ Players standing on a vehicle's deck count as on foot. Swimming fast counts as sprinting. Falloff applies to bullet hits on living entities; rocket explosions and vehicle hits are unchanged. +Two more `handling` keys: + +| Key | Effect | +| --- | --- | +| `smooth-accuracy` | `true`: above accuracy 5, each point tightens spread by 5%. Off or left out: the old line, which reaches 1.2° at 20 and 0.07° at 30. | +| `pellet-cone.tighten-per-accuracy` / `pellet-cone.min-factor` | A shotgun barrel's pellet cone (its `spread` stat) shrinks by this share per point of accuracy, down to `min-factor` of its size. Defaults 0.03 and 0.4. | + +## Forged parts + +A part in `parts.yml` with `tendencies` is forged. It becomes one part per +material in `metals.yml`, with the id `@` (for example +`heavy_barrel@steel`), which is what `/gg give` and crafted guns use. In the +gunsmith, players pick the part, then the material. + +`metals.yml` lists the materials. Each one has: +- `kind`: `metal` or `wood`. A part forges from one kind: `material: wood` for + stocks; metal by default. +- `tier`: sets the part tier, and the shot tier a barrel loads. +- `name` and `color`: the material's name as shown, and its hex colour (see + "Names and lore"). +- `cost` and `permission`: the ingot or wood paid per part, and who may forge it. +- `better` and `worse`: multiply a part's upsides and downsides. A number sets + every stat; a section sets `default` plus per-stat factors. +- `description`: notes on the material for config readers; players see the + part lore instead. + +A new material (an alloy) only needs a new entry. Every forged part of its kind +gains it. + +Part keys: + +| Key | Effect | +| --- | --- | +| `tendencies` | `stat value` lines written for the reference material (steel; maplewood for stocks). The material scales them. Lore shows them as one to three arrows, not numbers. | +| `fixed` | Stats no material changes: shots held, a shotgun's pellet cone (`spread`), a revolver's damage percentage. | +| `by-metal` | Extra stats per material, e.g. the multi-tube chamber's rockets. | +| `metals` | Limits the part to these materials. | +| `cost-amount`, `cost` | Ingots of the material (default 2), plus any other cost entries. | +| `ammo-family` | `shot`, `spreadshot` or `rocket`: the barrel loads that family up to its material's tier. Ammunition entries carry `family`, `tier` and `powered` (default: true when the id ends in `_powered`). | +| `ammo-filter` | `powered` or `plain`: the gun loads only that shot. | +| `skin-base` | Matches gun designs as if the action were this part, e.g. `flintlock`. | +| `metal-lore` | One lore line per material (`iron: "..."`), shown on that variant. The part list, before a material is picked, shows `lore`. | +| `sound-overrides` | Sounds that replace every other sound of that group on the gun (all parts and the material's layers), e.g. the steamlock's quiet report. | + +New stats: `damage_percent` (scales gun and shot damage), `falloff` (blocks +added to `falloff.start-distance`), `pierce` (added to the shot's pierce), and +`moving`, `mounted` and `sneaking`. The last three are percentages: positive +means steadier. `moving 40` lets 60% of the walking, sprinting and jumping +penalty through, and `sneaking 50` deepens the crouch bonus by half. The +combined factor stays between 0.5 and 2. Editing `metals.yml` or a part changes +its revision, so existing guns refresh to the new numbers. + +### Existing servers + +GunsAndGadgets writes a bundled file only when it is missing, so a server that +already runs the plugin keeps its old `config.yml`, `skins.yml`, +`ammunition.yml` and `parts.yml`. Switching to forged parts means, by hand: +- `parts.yml` and `metals.yml` replaced with the bundled ones, and the old + `parts.yml` entries moved to `retired-parts.yml` (below); +- `ammunition.yml` merged with the bundled one: every entry needs `family`, + `tier` and `powered`, and the bundled file adds the powered shots, the + per-metal spreadshot and rockets, and mythril shot (their items must exist). + Without powered shot, builds with the proof chamber show "These parts don't + make a gun"; +- `skins.yml` given the four `forged_*` entries, or forged guns keep the old + designs; +- `config.yml` given `stock` in `required-parts.pistol` (the grip; without it + pistols are drawn with none), and the new keys: `handling` `hip`, `rockets`, + `smooth-accuracy`, `pellet-cone` and `draw`; `aiming`; `part-icons`; + `type-icons`; `refunds`. + +### Retiring old parts + +Forged parts reuse old part ids (`matchlock`, `single_shot`, …), so move the old +`parts.yml` entries to `retired-parts.yml` when switching, before installing the +new `parts.yml`. Those parts load disabled: guns built from them still resolve, +but nobody can craft them. An id that `parts.yml` also defines is skipped. + +When `retired-parts.yml` is missing, the plugin writes its bundled copy: the +plugin's old default parts. It has the same 21 ids Main used, but the repo's +default values, not Main's tuned ones (Main's rifled barrel, revolver and shot +lists differ). It is only a safety net: a server that tuned its parts, Main +included, should still move its own old `parts.yml` there, or old guns refresh to +the default values; parts the bundle lacks count as removed. + +With `retire-disabled-part-guns: true` in `config.yml`, a gun stamped with a +disabled part refuses to fire or reload. Nothing is written to the gun, so +setting it back to `false` restores the gun. Its holder sees one warning per gun +per restart. + +### Refunds + +`refunds` in `config.yml` removes old guns so none stay on the server. A gun is +old when: +- it carries a part loaded from `retired-parts.yml`; +- it carries a part that no longer exists. This only counts while `parts.yml` + and `retired-parts.yml` both loaded cleanly, and never for forged ids + (`@`): those go missing only by a config mistake, such as a + material removed from `metals.yml`, so their guns stay broken until it is + fixed; +- it is from before guns recorded their parts (GunsAndGadgets 2.0.0; on Main, + guns crafted 15–23 September 2026). + +A part that is only `disabled: true` in `parts.yml` stops new crafts and leaves +its guns alone. A `parts.yml` that fails to read keeps the parts already loaded +and logs an error. A `retired-parts.yml` that fails to read logs an error and +its parts stay unloaded until it is fixed: their guns refuse to fire, but are +neither refunded nor marked broken. +A `parts.yml` that fails to read at startup, or has a line that is not a part, +also skips `retired-parts.yml` until it is fixed, so guns built from retired +parts say they are broken (missing parts) meanwhile. +A gun with a missing part is marked broken for good only while both files +loaded cleanly and none of its missing parts is forged; otherwise it only +refuses to fire, and works again once the config is fixed. + +What the player gets back: +- what the crafting took, recorded on guns crafted since 2.0.6; +- older stamped guns: the `cost` of each stamped part, from `parts.yml` or + `retired-parts.yml`; +- nothing for guns crafted for free (staff bypass, `/gg give`), unstamped guns, + and guns with a removed part and nothing recorded. They are just removed. + +Any shots still loaded in the gun come back too, whatever else it returns. + +A full inventory drops the rest at the player's feet. + +- Right-clicking the gun station with an old gun takes it apart. +- `automatic: true` also does it on join (inventory and ender chest), on + selecting it in the hotbar, and on clicking it in the player's own inventory. + Guns in chests and other storage are only refreshed when opened. Picking one + up onto the cursor takes it apart for the player who took it; one moved with + shift-click or a number key is taken apart when next selected, clicked or on + join. These checks + read each item's data in place and copy only guns. +- Each refund is logged: `[Refund] gun_id= returned {...}`. + +`enabled` turns refunds on; `automatic` does nothing without it. Both are off by +default. Turn them on with the switch to forged parts. + +### Forged gun looks + +A gun built only from forged parts is drawn from the parts it is made of. It +needs ServerAssets' `tfmc_guns` ItemsAdder pack folder, generated by +`tools/forged_guns/build.js`. + +- `skins.yml` entries with `forged-model` (`forged_rifle`, `forged_pistol`, + `forged_shotgun`, `forged_launcher`) win over every other skin for such a gun. + The item model is `_carry`, `_reload`, `_aim` or `_ads` + (crouched to aim), on the `carry`/`reload`/`aim`/`ads` material: a crossbow + keeps the aiming hold. Remove those + entries to show forged guns with the old fixed designs. +- The gun's `custom_model_data` strings tell the pack which part goes in each + slot: barrel, its material, loader, material, chamber, material, action, + material, stock (`none` without one), wood (the stock's, or `barkwood`). +- Pistols take a grip in the stock slot (`standard_grip`, `birdshead_grip`, + `pommel_grip`, `wrapped_grip`), so `required-parts.pistol` includes `stock`. + Launchers never have one. +- `part-icons` in `config.yml` (`tfmc_guns:part/` in the bundled config; blank + when left out) shows each forged part's pack icon in the gunsmithing menus, + plus `_` once the material is chosen. Blank shows each part's own + `item`. +- A skin's `ads` material is used for the aiming pose (default: its `aim`). + +Sound and effect keys: + +| Where | Key | Effect | +| --- | --- | --- | +| Part or material `sounds` | `pitch=` / `volume=` after the keys | Scale that sound group, e.g. `- shoot minecraft:guns.musket_5 pitch=0.95`. | +| Part | `sound-pitch`, `sound-volume` | Multiply the gun's whole report, e.g. the proof chamber's heavier charge. | +| Part | `ignition` | Effect at the lock when firing: `flint`, `ember`, `wheel`, `steam`, `arc` or `fuse`. | +| Part | `smoke`, `smoke-cone`, `backblast` | Muzzle smoke amount (1 = the old cloud) and fan width (default 0.2); `backblast: true` also blows smoke out of the back. | +| Material | `sound-pitch`, `sound-volume`, `sounds` | The barrel's material pitches the report and can add layers, e.g. mythril's ring. | +| Material | `flash`, `trail` | Hex colours of the muzzle flash and the shot's trail for a barrel of that material. | + +Steamlocks keep `smokeless` and `no_light`, so they show only their steam. +Sound changes count as part changes, so existing guns refresh to them. + +### Draw time and aiming + +`handling.draw` in `config.yml` gives guns a draw time. A gun taken into the +hand can't fire or start a reload until it is drawn. It counts as taken into +the hand after: +- a hotbar change; +- a swap into the main hand; +- moving it into the hand slot; +- a respawn or join. + +The hotbar shows the vanilla cooldown sweep for the time left. + +| Key | Effect | +| --- | --- | +| `draw.base-seconds.` | Seconds for `pistol`, `shotgun`, `rifle`, `launcher`. Leave the section out for no draw time. | +| `draw.stance.` | How much longer drawing takes each tick spent `moving`, `sprinting`, `airborne` (jumping or falling) or `mounted` (a moving seat). `sneaking` multiplies the on-foot value, so below 1 is quicker. | + +The parts' `draw` stat (Draw Speed) scales the base time: `+25` is 25% quicker +and `-30` is 30% slower, held between half and double. + +`aiming.enabled: true` turns on crouch to aim (off when left out). Crouching with +a loaded, drawn gun raises it: +- the model becomes `_ads`; +- walking slows by `slow` (0 to 0.9), which also narrows the field of view. + Players with FOV effects off get only the slowdown. + +A gun with a `scoped` part (the arclock) becomes a spyglass while aimed: hold +right-click to look through it, then release to fire. The release fires only +after `aiming.scope-settle-seconds` (0.6 in the bundled config; 0, at once, when +left out); an earlier release lowers the +scope without a shot. A click sound and "Steady" on the action bar mark the +moment. Releasing the crouch, changing item or running empty lowers the gun. A +gun moved, dropped or lost on death while aimed goes back to its normal look. + +`handling.spread-multipliers.hip` (1.75 in the bundled config) widens the spread +of shots fired without aiming, only while `aiming` is on. Aimed shots still take +the `sneaking` multiplier. + +The swap-hands key with a gun in hand picks the next shot (see "Ammunition +selection"). + +### Balance (2026-11-07 pass) + +Checked with a calculator over every legal build (about 1.7 million) and bot shots on Dev +against crafted mythril armour (within 3% for bullets): +- Smoothbore barrels hit harder and pierce less; rifled barrels pierce more and hit softer. + At mythril the smoothbore does about 19% more to light armour and the rifled barrel about + 26% more to heavy armour. +- The proof chamber has no damage cut but reloads slower, so it adds pierce to any barrel. +- The double chamber fires its second shot after at least about 0.9 s and does 10% less per + shot; the single shot keeps the best sustained damage. +- The single-shot launcher does 15% more; the multi-tube is less accurate and 25% weaker per + rocket. +- The best mythril builds do about 8 damage a second to a Warlord in mythril medium armour at + 25 blocks (melee classes do 6 to 10 in contact); a median build about half that. + +### Names and lore + +- `metals.yml` `color` (hex) is the material's colour: its ingot or refined + wood. A forged part's name is written in it ("Steel Long Rifled Barrel"). +- An assembled gun's name takes the colour of the metal of its final (majority) + tier. Bundled `name-impact` entries build [chamber] [action] [barrel], e.g. + "Double Flintlock Rifle", "Revolving Wheellock Pistol", "Salvo Rocket + Launcher". +- Each part and material has its own line of lore (`metal-lore`). Its arrows + show the tendencies in that material, so the lore adds no line on what the + material does. +- Every stat on an assembled gun has a short note on what it measures. +- Parts whose shot rules leave the gun nothing to load show a barrier: "These + parts don't make a gun". +- `type-icons` in `config.yml` (`tfmc_guns:` in the bundled config; blank when + left out) draws the gun type buttons as a steel gun of that type + (`_carry`). Blank shows paper. + ## Character sessions and reload cleanup The build pins TLibs 2.3.0. With an older TLibs that lacks the character API,