-
Notifications
You must be signed in to change notification settings - Fork 249
Missile orders #5771
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Missile orders #5771
Changes from all commits
77243b7
91c1f7b
e7ecd5e
31f64c1
b84a180
4e7be09
dd3fe28
6d7a261
3d83d6b
d5f3a7d
5606e56
dd43a39
608fac6
3437dab
da09486
7173b99
812e693
908d1bb
f083735
757d44d
5a70f50
40349a3
fe9a8e8
1bfac14
afe7a9e
7f56fb6
dbfbda8
6078092
1bb6c0e
47e54b8
990893d
ca90b4d
3836ec0
b225774
ea710ab
1680e39
9a4566e
6a880c4
ed0733e
899a89e
bf1506f
1c8eda9
f20aae1
5d1bc8e
4c60a8f
1898071
3d45ca7
1daeda9
3a2e595
82a87a9
046d4bb
412d126
3d6ee9e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| -- Missile launcher configuration. Shared by the Missile Command Center widget | ||
| -- (launch/build behaviour) and integral_menu_config.lua (Launch tab layout), so a | ||
| -- missile type is described in exactly one place. One entry per launch button, in | ||
| -- display order. Command ids are assigned automatically from CMD_BASE below. | ||
| -- | ||
| -- Entry fields: | ||
| -- key - internal id (widget command table key). | ||
| -- unit - unit def name; supplies the button icon. | ||
| -- label - display name. | ||
| -- col, row - position in the Launch tab grid. | ||
| -- tooltip - button tooltip. | ||
| -- cmdType - "ICON_MAP" (default) or "ICON_UNIT_OR_MAP" (can target a unit). | ||
| -- siloBuild - unit this type is built as at a missile silo (enables Alt-click build). | ||
| -- zenith - true for the Zenith meteor controller (special, non-stockpile behaviour). | ||
| -- controllerScope - "separate": this button only exists when Eos/Scylla are NOT combined. | ||
| -- launch - list of launchable unit types, each: | ||
| -- unit - unit def name that carries/fires this missile. | ||
| -- cmd - "ATTACK" or "MANUALFIRE". | ||
| -- weaponId - weapon index on that unit. | ||
| -- stockpile - "silo" (sits on a silo pad) or "engine" (GetUnitStockpile); omit for Zenith. | ||
| -- scope - "combine": active only when Eos and Scylla are combined. | ||
|
|
||
| local CMD_BASE = 39610 | ||
|
|
||
| local missiles = { | ||
| { key = "zenith", unit = "zenith", label = "Zenith", col = 1, row = 1, | ||
| zenith = true, cmdType = "ICON_UNIT_OR_MAP", | ||
| tooltip = "Zenith (Meteor Controller)\nRains meteors on the target for a few seconds.", | ||
| launch = { { unit = "zenith", cmd = "ATTACK", weaponId = 1 } }, | ||
| }, | ||
| { key = "trinity", unit = "staticnuke", label = "Trinity", col = 2, row = 1, | ||
| tooltip = "Launch Trinity (Strategic Nuke)\nLong-range nuclear missile.", | ||
| launch = { { unit = "staticnuke", cmd = "ATTACK", weaponId = 1, stockpile = "engine" } }, | ||
| }, | ||
| { key = "reef", unit = "shipcarrier", label = "Reef Missile", col = 3, row = 1, | ||
| cmdType = "ICON_UNIT_OR_MAP", | ||
| tooltip = "Launch Disarm Missile\nDisables units temporarily.", | ||
| launch = { { unit = "shipcarrier", cmd = "MANUALFIRE", weaponId = 2, stockpile = "engine" } }, | ||
| }, | ||
| { key = "scylla", unit = "subtacmissile", label = "Scylla", col = 4, row = 1, | ||
| controllerScope = "separate", | ||
| tooltip = "Launch Scylla (Tactical Nuke)\nSubmarine-launched tactical nuke.", | ||
| launch = { { unit = "subtacmissile", cmd = "ATTACK", weaponId = 1, stockpile = "engine" } }, | ||
| }, | ||
| { key = "eos", unit = "tacnuke", label = "Eos", col = 1, row = 2, | ||
| siloBuild = "tacnuke", | ||
| tooltip = "Launch Eos (Tactical Nuke)\nTactical nuclear missile with high damage.\nAlt-click the map to build one.", | ||
| launch = { | ||
| { unit = "tacnuke", cmd = "ATTACK", weaponId = 1, stockpile = "silo" }, | ||
| -- Scylla folds in here only when the Combine Eos and Scylla option is on. | ||
| { unit = "subtacmissile", cmd = "ATTACK", weaponId = 1, stockpile = "engine", scope = "combine" }, | ||
| }, | ||
| }, | ||
| { key = "seismic", unit = "seismic", label = "Seismic", col = 2, row = 2, | ||
| siloBuild = "seismic", | ||
| tooltip = "Launch Seismic\nArea denial seismic missile, slows units.\nAlt-click the map to build one.", | ||
| launch = { { unit = "seismic", cmd = "ATTACK", weaponId = 1, stockpile = "silo" } }, | ||
| }, | ||
| { key = "shockley", unit = "empmissile", label = "Shockley", col = 3, row = 2, | ||
| siloBuild = "empmissile", | ||
| tooltip = "Launch Shockley (EMP)\nElectromagnetic pulse missile disables units.\nAlt-click the map to build one.", | ||
| launch = { { unit = "empmissile", cmd = "ATTACK", weaponId = 1, stockpile = "silo" } }, | ||
| }, | ||
| { key = "inferno", unit = "napalmmissile", label = "Inferno", col = 4, row = 2, | ||
| siloBuild = "napalmmissile", | ||
| tooltip = "Launch Inferno (Napalm)\nNapalm missile with persistent damage.\nAlt-click the map to build one.", | ||
| launch = { { unit = "napalmmissile", cmd = "ATTACK", weaponId = 1, stockpile = "silo" } }, | ||
| }, | ||
| { key = "zeno", unit = "missileslow", label = "Zeno", col = 5, row = 2, | ||
| siloBuild = "missileslow", | ||
| tooltip = "Launch Zeno (Slow Missile)\nSlow homing missile with lingering damage.\nAlt-click the map to build one.", | ||
| launch = { { unit = "missileslow", cmd = "ATTACK", weaponId = 1, stockpile = "silo" } }, | ||
| }, | ||
| } | ||
|
|
||
| -- Command ids come from the shared registry (LuaRules/Configs/customcmds.lua) so they | ||
| -- are reserved ZK commands, keyed MISSILE_<KEY>. Fall back to the sequential range if the | ||
| -- registry is not available (both resolve to the same 39610.. block). | ||
| local registeredCmds = Spring.Utilities and Spring.Utilities.CMD | ||
| for i = 1, #missiles do | ||
| local m = missiles[i] | ||
| m.cmd = (registeredCmds and registeredCmds["MISSILE_" .. string.upper(m.key)]) or (CMD_BASE + i - 1) | ||
| end | ||
|
|
||
| return missiles |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -215,6 +215,25 @@ end | |
| --initialization | ||
| -------------------------------------------------------------------------------- | ||
|
|
||
| -- Vlaunch (starburst) flight parameters, derived purely from the weapon def. | ||
| -- Used by the AoE preview here and exposed via WG for the missile launch preview, | ||
| -- so both compute impact points from an identical trajectory model. | ||
| local function BuildVlaunch(weaponDef) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why vlaunch in particular? The next time someone wants a different type of weapondef are they going to make their own builder? Instead, getWeaponInfo should be split into the bits that need unitDef and the bits that don't (or have a fallback). |
||
| if (weaponDef.uptime or 0) <= 0 then | ||
| return nil | ||
| end | ||
| -- In the first frame the projectile moves startVelocity + 2*Acceleration | ||
| local startSpeed = math.min(weaponDef.startvelocity + weaponDef.weaponAcceleration, weaponDef.projectilespeed) | ||
| return { | ||
| upFrames = math.floor(weaponDef.uptime * 30 + 0.5) - 2, | ||
| accel = weaponDef.weaponAcceleration, | ||
| turnRate = weaponDef.turnRate, | ||
| startSpeed = startSpeed, | ||
| startHeight = startHeights[weaponDef.name] or 0, | ||
| endSpeed = weaponDef.projectilespeed, | ||
| } | ||
| end | ||
|
|
||
| local function getWeaponInfo(weaponDef, unitDef) | ||
| local retData | ||
|
|
||
|
|
@@ -277,18 +296,7 @@ local function getWeaponInfo(weaponDef, unitDef) | |
| else | ||
| retData.aoe = 0 | ||
| end | ||
| if (weaponDef.uptime or 0) > 0 then | ||
| -- In the first frame the projectile moves startVelocity + 2*Acceleration | ||
| local startSpeed = math.min(weaponDef.startvelocity + weaponDef.weaponAcceleration, weaponDef.projectilespeed) | ||
| retData.vlaunch = { | ||
| upFrames = math.floor(weaponDef.uptime * 30 + 0.5) - 2, | ||
| accel = weaponDef.weaponAcceleration, | ||
| turnRate = weaponDef.turnRate, | ||
| startSpeed = startSpeed, | ||
| startHeight = startHeights[weaponDef.name] or 0, | ||
| endSpeed = weaponDef.projectilespeed, | ||
| } | ||
| end | ||
| retData.vlaunch = BuildVlaunch(weaponDef) | ||
| retData.cost = cost | ||
| retData.mobile = not unitDef.isImmobile | ||
| retData.waterWeapon = waterWeapon | ||
|
|
@@ -487,6 +495,39 @@ local function DrawAoE(tx, ty, tz, aoe, ee, alphaMult, offset, circleMode) | |
| glLineWidth(1) | ||
| end | ||
|
|
||
| -- Shared blast-radius preview, exposed via WG so other widgets (e.g. the missile | ||
| -- launch UI) draw their AoE footprint with THIS falloff code instead of duplicating | ||
| -- it. Nested rings at (tx,ty,tz) whose alpha decays toward the edge by | ||
| -- edgeEffectiveness `ee`. `color` (optional {r,g,b[,a]}) overrides the ring colour; | ||
| -- `alphaMult` (optional) scales overall opacity (e.g. a pulse). Line width is derived | ||
| -- from the live camera distance, so callers need no per-frame setup of their own. | ||
| local function DrawAoEPreview(tx, ty, tz, aoe, ee, color, alphaMult) | ||
| if not aoe or aoe <= 0 then | ||
| return | ||
| end | ||
| ee = ee or 1 | ||
| local cx, cy, cz = GetCameraPosition() | ||
| local dx, dy, dz = cx - tx, cy - ty, cz - tz | ||
| local camDist = sqrt(dx*dx + dy*dy + dz*dz) | ||
| if camDist < 1 then | ||
| camDist = 1 | ||
| end | ||
| local r = (color and color[1]) or aoeColor[1] | ||
| local g = (color and color[2]) or aoeColor[2] | ||
| local b = (color and color[3]) or aoeColor[3] | ||
| local baseAlpha = ((color and color[4]) or aoeColor[4]) * (alphaMult or 1) | ||
|
|
||
| glLineWidth(math.max(0.05, aoeLineWidthMult * aoe / camDist)) | ||
| for i = 1, numAoECircles do | ||
| local proportion = i / (numAoECircles + 1) | ||
| local alpha = baseAlpha * (1 - proportion) / (1 - proportion * ee) | ||
| glColor(r, g, b, alpha) | ||
| DrawCircle(tx, ty, tz, aoe * proportion) | ||
| end | ||
| glColor(1, 1, 1, 1) | ||
| glLineWidth(1) | ||
| end | ||
|
|
||
| -------------------------------------------------------------------------------- | ||
| --dgun/noexplode | ||
| -------------------------------------------------------------------------------- | ||
|
|
@@ -939,6 +980,33 @@ local function CalculateVlaunchImpact(info, fx, fy, fz, tx, ty, tz) | |
| return false | ||
| end | ||
|
|
||
| -------------------------------------------------------------------------------- | ||
| -- Shared vlaunch impact query (used by the missile launch preview widget) | ||
| -------------------------------------------------------------------------------- | ||
|
|
||
| local vlaunchInfoCache = {} | ||
|
|
||
| -- Returns the terrain impact point (x, y, z) of a vlaunch (starburst) shot fired | ||
| -- from (fx, fy, fz) at (tx, ty, tz), or nil if it reaches the target | ||
| -- unobstructed or the weapon is not a vlaunch weapon. | ||
| local function GetVlaunchImpact(weaponDefID, fx, fy, fz, tx, ty, tz) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is duplicate and locally-dead code. Also in my tested the visuals were bugged. |
||
| local info = vlaunchInfoCache[weaponDefID] | ||
| if info == nil then | ||
| local wd = WeaponDefs[weaponDefID] | ||
| local vlaunch = wd and BuildVlaunch(wd) | ||
| info = (vlaunch and {vlaunch = vlaunch, range = wd.range}) or false | ||
| vlaunchInfoCache[weaponDefID] = info | ||
| end | ||
| if not info then | ||
| return nil | ||
| end | ||
| local hx, hy, hz = CalculateVlaunchImpact(info, fx, fy, fz, tx, ty, tz) | ||
| if hx then | ||
| return hx, hy, hz | ||
| end | ||
| return nil | ||
| end | ||
|
|
||
| -------------------------------------------------------------------------------- | ||
| --Main draw | ||
| -------------------------------------------------------------------------------- | ||
|
|
@@ -1027,10 +1095,12 @@ function widget:Initialize() | |
| aoeDefInfo[unitDefID], dgunInfo[unitDefID], extraDrawRangeDefInfo[unitDefID] = SetupUnit(unitDef) | ||
| end | ||
| SetupDisplayLists() | ||
| WG.AttackAoE = {GetVlaunchImpact = GetVlaunchImpact, DrawAoEPreview = DrawAoEPreview} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not how these tables are usually constructed so will be hard to search. Use externalFunctions. |
||
| end | ||
|
|
||
| function widget:Shutdown() | ||
| DeleteDisplayLists() | ||
| WG.AttackAoE = nil | ||
| end | ||
|
|
||
| function widget:DrawWorld() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these here and hardcoded?