;The CSC script. No longer messy and unreadable. Allows effective control over capital ship turrets.
#Conditional Hooks
$Application: FS2_Open
$On Key Pressed: [[csc_KeyPressed.lua]]
$On Key Released: [[csc_KeyReleased.lua]]
$On Game Init:
[
ui_keyToggleFunctions = {}
InputStates = {}
ui_keyToggleFunctions["6"] = function(val) InputStates.up = val end
ui_keyToggleFunctions["7"] = function(val) InputStates.down = val end
ui_keyToggleFunctions["8"] = function(val) InputStates.left = val end
ui_keyToggleFunctions["9"] = function(val) InputStates.right = val end
ui_keyToggleFunctions["0"] = function(val) InputStates.zero = val end
function getTargetName(target)
local targetname
if target then
local targetship = mn.getObjectFromSignature(target:getSignature())
if targetship:isValid() then
if targetship:getBreedName() == "Ship" then
targetname = targetship.Name
end
else
targetname = "None"
end
else
targetname = "None"
end
return targetname
end
function getTargetClass(target)
local targetname
if target then
local targetship = mn.getObjectFromSignature(target:getSignature())
if targetship:isValid() then
if targetship:getBreedName() == "Ship" then
targetname = targetship.Class.Type.Name
end
else
targetname = "None"
end
else
targetname = "None"
end
return targetname
end
function setTurretColor(weapon)
gr.setColor(csc.turretColors[weapon][1], csc.turretColors[weapon][2], csc.turretColors[weapon][3])
end
function drawTurretUI()
local sel = csc.shipdef[csc.shipIdx].turretControl[csc.acnum]
local weapon
gr.drawString("", 5, gr.getScreenHeight() * 0.6)
for i = 1, #csc.shipdef[csc.shipIdx].turretControl, 1 do
weapon = csc.shipdef[csc.shipIdx].turretControl
ba.print("CSC: ui: " .. weapon)
if sel == weapon then
gr.setColor(255, 255, 255)
else
setTurretColor(weapon)
end
gr.drawString(csc.turretDisplay[weapon] .. csc.turretMode[weapon][csc.turretStatus[weapon]])
setTurretColor(weapon)
for i = 1, #csc.turretGroup[weapon], 1 do
local targetname = getTargetName(csc.turretGroup[weapon].Target)
if not targetname then targetname = "None" end
if weapon == "pd" then
gr.drawString(" PD Turret: " .. targetname)
else
gr.drawString(" " .. csc.turretGroup[weapon].Name .. ": " .. targetname)
end
end
end
gr.setColor(255, 255, 255)
local targetname = getTargetName(csc.CurrentTarget)
local classname = getTargetClass(csc.CurrentTarget)
if not classname then classname = "None" end
if not targetname then targetname = "Invalid" end
gr.drawString("Current Target: " .. targetname .. " Class: " .. classname)
end
function fillturretlist(ship)
local turretnum = 1
ba.print("CSC: Entered fillturretlist\n")
csc.turrets = {}
for i = 1, 60, 1 do
if i < 10 then
turretname = "turret0" .. i
else
turretname = "turret" .. i
end
ba.print("CSC: Looking for turret: " .. turretname .. "\n")
if ship[turretname]:isValid() then
csc.turrets[turretnum] = ship[turretname]
ba.print("CSC: Found Turret.\n")
turretnum = turretnum + 1
end
end
end
function groupTurrets()
ba.print("CSC: Entered GroupTurrets\n")
for i = 1, #csc.turrets, 1 do
if csc.turrets.PrimaryBanks[1].WeaponClass:isValid() or csc.turrets.SecondaryBanks[1].WeaponClass:isValid() then
for j = 1, #csc.weapondef, 1 do
if string.find(csc.turrets.PrimaryBanks[1].WeaponClass.Name, csc.weapondef[j].weapon) then
csc.turretGroup[csc.weapondef[j].turret][#csc.turretGroup[csc.weapondef[j].turret] + 1] = csc.turrets
ba.print("CSC: Found " .. csc.weapondef[j].weapon .. ". Turret Number: " .. i .. " weaponnum: " .. #csc.turretGroup[csc.weapondef[j].turret] .. "\n")
end
end
end
end
csc.initComplete = true
end
function drawTargetBraces(weapon)
setTurretColor(weapon)
for i = 1, #csc.turretGroup[weapon], 1 do
target = csc.turretGroup[weapon].Target
if target:isValid() then
gr.drawTargetingBrackets(target, true, csc.turretColors[weapon][4])
end
end
end
function doInput()
MissionTime = mn.getMissionTime()
if OldMissionTime ~= MissionTime and MissionTime ~= 0 then
if InputStates.up and not csc.inputstates.keyup then
csc.acnum = csc.acnum - 1
if csc.acnum == 0 then
csc.acnum = #csc.shipdef[csc.shipIdx].turretControl
end
csc.inputstates.keyup = true
elseif not InputStates.up then
csc.inputstates.keyup = false
end
if InputStates.down and not csc.inputstates.keydown then
csc.acnum = csc.acnum + 1
if csc.acnum == #csc.shipdef[csc.shipIdx].turretControl + 1 then
csc.acnum = 1
end
csc.inputstates.keydown = true
elseif not InputStates.down then
csc.inputstates.keydown = false
end
local weapon = csc.shipdef[csc.shipIdx].turretControl[csc.acnum]
if InputStates.left and not csc.inputstates.keyleft then
if csc.turretStatus[weapon] <= 1 then
csc.turretStatus[weapon] = #csc.turretMode[weapon]
else
csc.turretStatus[weapon] = csc.turretStatus[weapon] - 1
end
csc.inputstates.keyleft = true
elseif not InputStates.left then
csc.inputstates.keyleft = false
end
if InputStates.right and not csc.inputstates.keyright then
if csc.turretStatus[weapon] >= #csc.turretMode[weapon] then
csc.turretStatus[weapon] = 1
else
csc.turretStatus[weapon] = csc.turretStatus[weapon] + 1
end
csc.inputstates.keyright = true
elseif not InputStates.right then
csc.inputstates.keyright = false
end
if InputStates.zero or io.isMouseButtonDown(MOUSE_LEFT_BUTTON) then
csc.CurrentTarget = csc.plrship.Target
csc.inputstates.zero = true
elseif not InputStates.zero or not io.isMouseButtonDown(MOUSE_LEFT_BUTTON) then
csc.inputstates.zero = false
end
OldMissionTime = MissionTime
end
end
function doTurretMode()
local weapon
for j = 1, #csc.shipdef[csc.shipIdx].turretControl, 1 do
weapon = csc.shipdef[csc.shipIdx].turretControl[j]
if csc.turretStatus[weapon] == 1 then
for i = 1, #csc.turretGroup[weapon] do
csc.turretGroup[weapon]:targetingOverride(false)
end
elseif csc.turretStatus[weapon] == 2 then
for i = 1, #csc.turretGroup[weapon] do
csc.turretGroup[weapon].Target = csc.plrship.Target
end
elseif csc.turretStatus[weapon] == 3 then
if csc.CurrentTarget then
if csc.CurrentTarget:isValid() then
for i = 1, #csc.turretGroup[weapon] do
csc.turretGroup[weapon].Target = csc.CurrentTarget
end
end
end
elseif csc.turretStatus[weapon] == 4 then
for i = 1, #csc.turretGroup[weapon] do
csc.turretGroup[weapon]:targetingOverride(true)
end
end
end
end
function drawRangeDisplay()
local turposCount = #csc.shipdef[csc.shipIdx].turretRange
if turposCount > 0 then
csc.range = nil
csc.range = {}
csc.range.Shipname = {}
csc.range.Range = {}
local plrship = hv.Player
local turpos = {}
for j = 1, turposCount, 1 do
turpos[j] = (plrship.Position + plrship[csc.shipdef[csc.shipIdx].turretRange[j]].Position)
end
items = 1
for i = 1, #mn.Ships do
local tempship = mn.Ships
local class = getTargetClass(tempship)
if class ~= "Fighter" and class ~= "Bomber" then
if tempship ~= csc.plrship then
local temp = tempship.Position
local tempsum = 0
for j = 1, turposCount, 1 do
tempsum = tempsum + math.sqrt( (temp[1] - turpos[j][1])^2 + (temp[2] - turpos[j][2])^2 + (temp[3] - turpos[j][3])^2 )
end
csc.range.Shipname[items] = tempship.Name
csc.range.Range[items] = math.floor( tempsum / turposCount)
items = items + 1
end
end
end
gr.setColor(255,255,255)
gr.drawString("Range:", gr.getScreenWidth() * 0.17, gr.getScreenHeight() * 0.78)
for i = 1, #csc.range.Shipname do
if csc.range.Range < 1000 then
local c = math.floor((csc.range.Range / 4)) + 5
gr.setColor(255, c, c)
gr.drawString(" " .. csc.range.Shipname .. ": " .. csc.range.Range)
gr.setColor(255, 255, 255)
else
gr.drawString(" " .. csc.range.Shipname .. ": " .. csc.range.Range)
end
end
end
end
function turretInit(weapon, display, r, g, b, p)
csc.turretGroup[weapon] = {}
csc.turretMode[weapon] = {"Automatic", "Track", "Lock", "Offline"}
csc.turretStatus[weapon] = 1
csc.turretColors[weapon] = {r, g, b, p}
csc.turretDisplay[weapon] = display
ba.print("CSC: Turret init " .. weapon .. "\n")
end;
function weaponInit(weapon, turret)
local i = #csc.weapondef + 1
csc.weapondef = {}
csc.weapondef.weapon = weapon
csc.weapondef.turret = turret
ba.print("CSC: Weapon init " .. weapon .. "\n")
end
function defineTurrets()
csc.turretGroup = {}
csc.turretStatus = {}
csc.turretColors = {}
csc.turretMode = {}
csc.turretDisplay = {}
-- config stuff start
-- turret group, UI display, R, G, B, Brace padding
--
turretInit("pd", "point defense turrets: ", 61, 93, 255, 8)
turretInit("flak", "flak turrets: ", 61, 93, 255, 8)
turretInit("md", "mass drivers: ", 255, 93, 48, 11)
turretInit("gauss", "gauss cannons: ", 255, 187, 53, 14)
turretInit("torpedo", "apocalypse torpedoes: ", 255, 255, 53, 17)
turretInit("missile", "missile launchers: ", 255, 255, 53, 17)
turretInit("GTVAtorpedo", "torpedo launchers: ", 255, 255, 53, 17)
turretInit("gattler", "gattler: ", 255, 187, 53, 14)
turretInit("rapier", "rapier: ", 255, 187, 53, 14)
turretInit("aaa", "AAA beams: ", 255, 187, 53, 14)
turretInit("beam", "beam cannons: ", 255, 93, 48, 11)
turretInit("slash", "slash beams: ", 255, 255, 53, 17)
turretInit("pulse", "pulse cannons: ", 255, 187, 53, 14)
turretInit("A", "Art: ", 255, 93, 53, 17)
turretInit("HA", "H Art: ", 255, 93, 48, 17)
turretInit("HMA", "HM Art: ", 255, 255, 53, 17)
turretInit("LMA", "LM Art: ", 255, 187, 53, 17)
turretInit("FLK", "Flak: ", 61, 93, 255, 17)
turretInit("HFLK", "H Flak: ", 61, 93, 48, 17)
turretInit("C", "CIWS ", 61, 93, 255, 17)
turretInit("HC", "H CIWS: ", 61, 93, 255, 17)
turretInit("CFLK", "CIWS Flak: ", 61, 93, 255, 17)
turretInit("HCFLK", "H CIWS Flak: ", 61, 93, 255, 17)
turretInit("PLX", "Phalanx: ", 61, 93, 255, 17)
end
function defineWeapons()
csc.weapondef = {}
--weaponClassName -> turret group
weaponInit("Colonial Artillery", "A")
weaponInit("Colonial Heavy Artillery ", "HA")
weaponInit("Colonial Heavy Mount Artillery", "HMA")
weaponInit("Colonial Light Mount Artillery", "LMA")
weaponInit("Colonial Flak", "FLK")
weaponInit("Colonial Heavy Flak", "HFLK")
weaponInit("Colonial CIWS", "C")
weaponInit("Colonial Heavy CIWS", "HC")
weaponInit("Colonial CIWS Flak", "CFLK")
weaponInit("Colonial Heavy CIWS Flak", "HCFLK")
weaponInit("Colonial Phalanx Cannon", "PLX")
weaponInit("PD Turret#Player", "pd")
weaponInit("Burst Flak", "flak")
weaponInit("Mass Driver", "md")
weaponInit("Gauss Cannon", "gauss")
weaponInit("Apocalypse", "torpedo")
weaponInit("Apocalypse#Solaris", "torpedo")
weaponInit("Warhammer", "missile")
weaponInit("Gattler", "gattler")
weaponInit("Gattler Turret#Solaris", "gattler")
weaponInit("Rapier", "rapier")
weaponInit("AAAf", "aaa")
weaponInit("ULTRA Anti-Fighter Beam", "aaa")
weaponInit("BGreen", "beam")
weaponInit("BFGreen", "beam")
weaponInit("LRBGreen", "beam")
weaponInit("SGreen", "beam")
weaponInit("Green Beam", "beam")
weaponInit("BVas", "beam")
weaponInit("SVas", "beam")
weaponInit("HBlue", "beam")
weaponInit("BBlue", "beam")
weaponInit("SBlue", "beam")
weaponInit("LTerSlash", "slash")
weaponInit("VSlash", "slash")
weaponInit("TerSlash", "slash")
weaponInit("TerSlashBlue", "slash")
weaponInit("@Terran Turret", "pd")
weaponInit("Terran Huge Turret", "pd")
weaponInit("Vasudan Turret", "pd")
weaponInit("Vasudan Huge Turret", "pd")
weaponInit("STerPulse", "pulse")
weaponInit("TerPulse", "pulse")
weaponInit("SVasPulse", "pulse")
weaponInit("VasPulse", "pulse")
weaponInit("Standard Flak", "flak")
weaponInit("Heavy Flak", "flak")
weaponInit("Piranha", "missile")
weaponInit("@FighterKiller", "missile")
weaponInit("@Fusion Mortar", "missile")
weaponInit("Eos", "GTVAtorpedo")
weaponInit("Supernova", "GTVAtorpedo")
end
function defineShips()
csc.shipdef = {}
local
--Solaris
--Entry number - don't forget to change while copypasting this one
i = 1
csc.shipdef = {}
csc.shipdef.shipClassName = "UED Solaris#Player"
--turrets showing target braces
csc.shipdef.turretTargets={"pd", "flak", "md", "gauss", "torpedo"}
--turrets aviable in UI
csc.shipdef.turretControl={"md", "gauss", "torpedo"}
--turrets to calculate target range
csc.shipdef.turretRange={"turret01", "turret02", "turret03", "turret04"}
-- possible turret weapon groups:
-- {"pd", "flak", "md", "gauss", "torpedo", "gattler", "missile", "aaa", "beam", "slash", "pulse, "GTVAtorpedo"}
--Bolitho
i = 2
csc.shipdef = {}
csc.shipdef.shipClassName = Bolitho
csc.shipdef.turretTargets={"HMA", "LMA", "HCFLK", "HC"}
csc.shipdef.turretControl={"HC", "HCFLK"}
csc.shipdef.turretRange={}
end
-- config stuff end
function cscInit()
csc = {}
if not csc.initComplete then
defineShips()
defineWeapons()
ba.print("CSC: init \n")
if not csc.plrship then
csc.plrship = hv.Player
csc.disable = true
if csc.plrship:getBreedName() == "Ship" then
csc.shipIdx = 0
for i = 1, #csc.shipdef, 1 do
if csc.plrship.Class.Name == csc.shipdef.shipClassName then
csc.shipIdx = i
csc.disable = false
ba.print("CSC: Ship found " .. csc.shipdef.shipClassName)
end
end
end
if not csc.disable and not csc.turrets then
defineTurrets()
csc.active = {"*", " ", " "}
csc.acnum = 1
csc.inputstates = {}
inputlocked = false
fillturretlist(csc.plrship)
groupTurrets()
--The Shieldman and Betty script overrides
ShieldmanOverride = true
BettyOverride = true
end
end
end
end
]
$On Gameplay Start:
[
if (csc) then
ba.warning("There was already a CSC table present when initing the CSC script!")
end
cscInit()
]
$State: GS_STATE_GAME_PLAY
$On Frame:
[
cscMissionTime = mn.getMissionTime()
if cscMissionTime ~= 0 then
if csc then
if not csc.disable and csc.initComplete then
doInput()
doTurretMode()
for j = 1, #csc.shipdef[csc.shipIdx].turretTargets, 1 do
drawTargetBraces(csc.shipdef[csc.shipIdx].turretTargets[j])
end
end
end
end
]
$On HUD Draw:
[
if csc then
if not csc.disable and csc.initComplete then
drawRangeDisplay()
drawTurretUI()
end
end
]
$On Mission End:
[
csc = nil
ShieldmanOverride = false
BettyOverride = false
]
#End
One-Stop-Shop Capship Tutorial
For anyone who wants to put flyable capships in their mod, but didn't know how, here's a guide to everything you need to get a working capship in-game.
You need to: create working entries for each player-flyable capship in your ships.tbl/shp.tbm; download the Capship Control Script and input every ship, weapons group, and capship weapon which you are using into it; and properly set up your mission in FRED.
I'll add a capship abilities tutorial later, if there is enough demand.
To see capship control in action, check out Blue Planet's mission 'The Blade Itself', or my totally awesome in-progress series of mini-campaigns, Blue Planet: The Battle Captains. [/shamelessplug]
SHIPS.TBM:
All player-flyable capships should have the following table edits. You should make a separate table entry for every player-flyable capship. If you're using an existing capship class, and that ship class doesn't show up anywhere else in the campaign, you can save some work by just adding the following features to its table with +nocreate. Otherwise, copy over a full new ship table entry, named (Ship Class)#Player (if you're using a retail ship, you may want to add the original ship's MediaVPs updates to your new Ship#Player table.)
Add the following flags to the flags list: "player_ship" "generate icon" "no pain flash" "show ship"
This will make your ship player-flyable, show up without needing icons, and not show the red pain flash everytime it's hit.
Optional: If you want to make your player-capship quicker and more responsive than the original, raise its speed and reduce its turn times (probably not by too much, though.)
If you want the capship control script to properly label each class of turret on your ship during gameplay, add the following line as the second line of every turret entry in your ship's table entry:
$Alt Subsystem Name: (X)
(X) will be the turret's name in the capship control script's turret list (in the lower-left-hand corner of the screen during gameplay); if the turret carries a Terran Huge Turret, write Heavy Turret; if it's an AAAf, write AAA Beam; and so on. Just keep the turret names short.
(YOURMODHERE)-CSC-SCT.TBM
The capital ship control script is the most important part of making a flyable capship, and also the most complicated.
Dragon's modular capship control script, which I'm using here, is the simplest capship control option out there, and it's still complicated. You should probably read that post over, so you know the basics of how the script functions.
Download this and extract it to your mod's root folder; it contains the capship control script, and a couple scripts which it needs to work.
Open the CSC script; yeah, it's intimidating. Fortunately, you can add new ships and weapons to it without touching most of it, or understanding any LUA.
If your capship has shields, and you still want the player to be able to shift shield power around like in a fighter, that's a bit more complicated; see Dragon's post.
The following two sets of entries specify what weapon groups and weapons the capship command script will recognize in-game. This script already supports all (retail and Blue Planet) Terran, Vasudan, and UEF capship weapons, but if you want to add new types of capship weapons in your mod, add them here; otherwise, skip these two entries.
Anyway, scroll down until you see this part:
function defineTurrets()
function defineTurrets()
csc.turretGroup = {}
csc.turretStatus = {}
csc.turretColors = {}
csc.turretMode = {}
csc.turretDisplay = {}
-- config stuff start
-- turret group, UI display, R, G, B, Brace padding
--
turretInit("pd", "point defense turrets: ", 61, 93, 255, 8)
turretInit("flak", "flak turrets: ", 61, 93, 255, 8)
turretInit("md", "mass drivers: ", 255, 93, 48, 11)
Etc . . . . .
Each of the turretInit lines specifies one group of weapons which the script will recognize in-game: "pd" corresponds to your point-defense laser turrets, "beam" to your standard beam cannons, "slash" to your slashing beams, ect.
The first entry is the weapon group's name in the script; it will not show up in game, but whenever you're referring to that weapon group in the script, use this name. The second entry is the weapon group's name in-game. The next three numbers are the RGB values for that weapon group entry's color; this isn't very important. I dunno what Brace padding is.
Next, specify individual weapons, and which group they fall under.
function defineWeapons()
csc.weapondef = {}
--weaponClassName -> turret group
weaponInit("Point Defense Turret", "pd")
weaponInit("PD Turret#Player", "pd")
weaponInit("Burst Flak", "flak")
weaponInit("Mass Driver", "md")
weaponInit("Gauss Cannon", "gauss")
Etc . . . . . .
Here, each line's first entry specifies a weapon from your weapons.tbl or .tbm. The second entry puts that weapon in a weapon group. Give an entry to each new capship weapon which you are using.
Last, but not least, is the ships section. Give each flyable capship in your mod its own entry.
function defineShips()
csc.shipdef = {}
local
--Solaris
--Entry number - don't forget to change while copypasting this one
i = 1
csc.shipdef[i] = {}
csc.shipdef[i].shipClassName = "UED Solaris#Player"
--turrets showing target braces
csc.shipdef[i].turretTargets={"pd", "flak", "md", "gauss", "torpedo"}
--turrets aviable in UI
csc.shipdef[i].turretControl={"md", "gauss", "torpedo"}
--turrets to calculate target range
csc.shipdef[i].turretRange={"turret01", "turret02", "turret03", "turret04"}
-- possible turret weapon groups:
-- {"pd", "flak", "md", "gauss", "torpedo", "gattler", "missile", "aaa", "beam", "slash", "pulse, "GTVAtorpedo"}
--Custos
i = 2
csc.shipdef[i] = {}
Etc . . . . . .
FYI, all lines preceded by a -- are commented-out in LUA; they are ignored by the game.
i = x: Just give your ships consecutive i = numbers (i = 1, i = 2, etc.), and you'll be fine.
csc.shipdef
.shipClassName = "x": Here, x is the ship's table name.
csc.shipdef.turretTargets={"x", "y", "z"}: Here, specify each weapon group represented on this ship.
csc.shipdef.turretControl={"x", "y", "z"}: List each weapon group on your ship which you want the player to be able to control in-game. To minimize clutter, you probably want to only list your big anti-capital weapons (like beams) here.
csc.shipdef.turretRange={"x", "y", "z"} : List each TURRET (not weapon group) on your ship which you want the script's rangefinder to measure its range. The rangefinder isn't critical, and can be annoying if you have a dozen large ships in-mission, so you may just want to leave this entry blank anyway.
Aaand that's it for the table script.
FRED
If your ships.tbl/.tbm and csc-sct.tbm are properly set up, you should now be able to set the player's ship as a capship in FRED, and run the mission. However, there are some things you need to keep in mind when FREDding a capship mission.
Every time you save or load the mission, if your capship doesn't have any native primary weapons, FRED will whine about it every time you save or load the mission; just hit Enter to skip the error message.
In Mission Specs, check the No Traitor and (probably) Scramble flags. No Traitor will prevent you from turning traitor by, say, accidentally hitting allied fighters with your flak guns. Scramble will lock your ship and weapon selection, preventing the game from crashing when you try to alter the primary weapons of a ship which doesn't have any primary weapons banks. (Ignore this if your capship has one or more native primary weapons in addition to its turrets.)
Make your capship its own wing; name this wing (Your Capship's Name)#. FRED will now recognize your capship as (Your Capship's Name)# 1, as it is the first ship in a wing, but the game will just identify your capship as (Your Capship's Name). If you're also commanding one or more strikecraft wings, rename them as appropriate. Retitle the wing names under Mission Specs/Custom Wing Names to match your new names, or FRED will whine about that too.
When FREDding a capship-control mission, you need to approach mission design and balancing differently than if you were FREDding a standard strikecraft mission. Your capship is a lot slower and less maneuverable than strikecraft are (how much so depends on how big the capship is), but has many weapons, some of which are quite long-range. Memorize your chosen capship's main weapons, their ranges, and its strong and weak firing arcs. Tactical planning and positioning become more important than twitch reflexes; design scenarios which will force the player to think ahead and position their ship in the right position to blow away enemy capships and attacking fighter wings with the mighty power of its weapons batteries. Still, it's boring to just sit there and wait for your turrets to kill your enemy; give the player some strikecraft wings to command, manually-firing beams, and cool but well-balanced capship abilities, so they have something else to do.
END
Tada! You should now have a working, player-flyable capship in-game. A well-made capship mission requires a lot of effort, and both the FREDder and the player have to approach it in a different way than your standard strikecraft mission, but it provides its own unique and awesome kind of gameplay and challenge.
If any of these instructions are unclear, or if I missed anything, complain about it.