Retune Iron Coast waves, enemy attacks and weapon presentation

This commit is contained in:
raptorreplica committed 2026-10-17 18:13:20 +11:00
1 parent 00cfcc2031
commit c4a4d821d5
145 files changed
+9242 -2951

No files matched your search

+17 -5
View File
@@ -1,9 +1,21 @@
# Ion Lance 1.0.0
# Ion Lance
Enable **Ion Lance** in Mods and apply at the main menu. This independent API 1 example has no dependencies. Buy its equipment in the shop (425,000 credits, maximum one) or collect its pickup. Choose it in Inventory or cycle special weapons during a mission. The equipped weapon fires with Fire or Special; it consumes no ammunition.
API 1 package, version 1.1.0. Enable it in Mods at the main menu and apply the selection. This package has no mod dependencies.
Projectile: 8 damage, 12 logical pixels per step, 14 step cooldown, `beam`, air and ground targets. The narrow beam pierces every enemy in its column for two steps (16 total damage per enemy per trigger). Rhai stores bounded burst/hit counters and emits local firing/impact sounds and effects.
Selectable reusable special. A brief beam hits every air or ground enemy in the column ahead of your ship. Aim the column, then use Fire or Special while selected. No ammunition is consumed.
`art/equipment-sd.png` is a 16×16 logical icon, `art/equipment-hd.png` its detailed 4× variant. Projectile canvases are 4×32 SD and 16×128 HD. Switch HD artwork in Options. The generated master images, SD/HD sprites, WAV files, provenance and reproduction inputs are tracked in Git. Original game assets and decoded reference images remain outside version control. `python3 generate_audio.py` reproduces both sound files.
Buy **Ion Lance** for **425,000 credits**; carry at most 1. Select it through Inventory or the Cycle control when it is a special weapon.
Validate locally with `cargo run --no-default-features -- --mods mods --validate-mods ion_lance`. Read the shared [API documentation](../../docs/modding-api.md) for save pins, dependencies and sandbox limits.
`ion_lance:projectile`: 8 damage, speed 12, 14-tick cooldown, `beam` behavior.
## Feedback
The actual gameplay renderer draws a **2px-wide column** from the top of the playfield to the pilot for the existing two beam ticks. It does not draw the supplied 4×32 projectile PNG in that path; that asset and its declaration are retained. Damage 8 per beam tick, 14-tick cadence, column aiming and penetration are unchanged. One compact 2-tick contact arc per projectile, 3-tick flash spacing and 6-tick impact-audio spacing replace repeated explosions/audio at every column target. Fire/impact volume is 70/46. Price stays 425,000.
Only declared display sizing, cosmetic hit commands and playback levels/priorities change. No PNG/WAV pixels or samples, equipment icon dimensions, projectile collision rules, damage, cooldown, offsets, targeting, ammunition, capacity, controls or prices are changed. No new muzzle explosion or persistent trail is emitted. Normal original enemy deaths and terrain-destruction effects remain engine-controlled.
The three rapid weapons retain their prior burst/hit counters and reset only their cosmetic tick/projectile gates when mission ticks restart, accepting older saved script state without new fields. This version changes the package save pin; existing pilot compatibility confirmation remains the normal mod mechanism.
## Validation and history
See the [current Iron Coast retune results and limits](../../docs/iron-coast-retune.md). Package-local acceptance reports, validation results and retained test sources describe pre-retune 1.0 behavior unless a result explicitly identifies the newer package and runner. They remain historical material, not current playthrough guarantees.
+4 -4
View File
@@ -50,19 +50,19 @@
"id": "ion_lance:fire",
"name": "Ion Lance Fire",
"file": "audio/fire.wav",
"volume": 92,
"volume": 70,
"pan": 127,
"pitch": 128,
"priority": 1
"priority": 2
},
{
"id": "ion_lance:impact",
"name": "Ion Lance Impact",
"file": "audio/impact.wav",
"volume": 78,
"volume": 46,
"pan": 127,
"pitch": 128,
"priority": 2
"priority": 3
}
]
}
+1 -1
View File
@@ -1,6 +1,6 @@
id = "ion_lance"
name = "Ion Lance"
version = "1.0.0"
version = "1.1.0"
api_version = 1
description = "Naval science-fiction ion lance: independent weapon, equipment, SD/HD artwork and local firing/impact audio."
content = "content.json"
+32 -7
View File
@@ -1,20 +1,45 @@
// Built-in beam projectiles handle the normal volley and collision rules.
// Firing callbacks add audio and counters; impact callbacks add hit visuals.
// Firing callbacks add audio and counters; compact two-tick contact arcs are cosmetic.
fn on_fire(event, state, random) {
// Runtime script state can survive a mission change while tick/entity IDs restart.
// Reset only cosmetic gates; the existing burst/hit counters keep their semantics.
let last_fire = if state.contains("last_fire_tick") { state.last_fire_tick } else { -1 };
let restarted = event.tick <= last_fire
|| (state.contains("feedback_tick") && event.tick <= state.feedback_tick)
|| (state.contains("sound_tick") && event.tick <= state.sound_tick);
let bursts = if state.contains("bursts") { state.bursts % 100000 + 1 } else { 1 };
let hits = if state.contains("hits") { state.hits } else { 0 };
let commands = [
#{ op: "play_sound", sound: "ion_lance:fire" }
];
#{ commands: commands, state: #{ bursts: bursts, hits: hits } }
#{ commands: commands, state: #{ bursts: bursts, hits: hits,
// A new volley cannot be the preceding beam's second hit tick. Forget its
// entity ID, which may be reused in another mission even after a late first shot.
feedback_projectile: -1,
feedback_tick: if !restarted && state.contains("feedback_tick") { state.feedback_tick } else { -10 },
sound_tick: if !restarted && state.contains("sound_tick") { state.sound_tick } else { -10 },
last_fire_tick: event.tick } }
}
fn on_hit(event, state, random) {
let bursts = if state.contains("bursts") { state.bursts } else { 0 };
let hits = if state.contains("hits") { state.hits % 100000 + 1 } else { 1 };
let commands = [
#{ op: "play_sound", sound: "ion_lance:impact" },
#{ op: "effect", x: event.x, y: event.y }
];
#{ commands: commands, state: #{ bursts: bursts, hits: hits } }
// One compact contact flash per projectile, not one explosion per beam target.
// A separate six-tick audio gate also bounds coincident paired/swarm hits.
let previous_projectile = if state.contains("feedback_projectile") { state.feedback_projectile } else { -1 };
let previous_tick = if state.contains("feedback_tick") { state.feedback_tick } else { -10 };
let sound_tick = if state.contains("sound_tick") { state.sound_tick } else { -10 };
let commands = [];
let feedback = event.projectile != previous_projectile && event.tick - previous_tick >= 3;
if feedback {
commands.push(#{op: "arc", x: event.x - 2, y: event.y + 2,
to_x: event.x + 2, to_y: event.y - 2, ticks: 2});
}
let audible = event.tick - sound_tick >= 6;
if audible { commands.push(#{op: "play_sound", sound: "ion_lance:impact"}); }
#{ commands: commands, state: #{ bursts: bursts, hits: hits,
feedback_projectile: if feedback { event.projectile } else { previous_projectile },
feedback_tick: if feedback { event.tick } else { previous_tick },
sound_tick: if audible { event.tick } else { sound_tick },
last_fire_tick: if state.contains("last_fire_tick") { state.last_fire_tick } else { -1 } } }
}