I started playing around with HW2 modding again, and while there is a ton of information available here, most of it is spread out, and I couldn't find any decent tutorials for newbies.
So, I'll try to write up a tutorial series. Comments, suggestions, and "omg you moron that's totally wrong!" posts are welcome!
Over the course of the series we'll attempt to do the following:
- Make the Keepers a playable race
- Give them Bentus as their mothership
- Allow them to build a handful of different units
- Build a tiny research tree
In order to do that, we will have to modify a bunch of files. I am going to assume you know how to extract .zip files and add information to shortcuts, but other than that I'll try to keep it as low-level as possible.
Part One - The Tools
Actually, we don't need a lot of them. The .lua files (contain information on formations, starting ships, races, etc.) as well as the .ship (those contain values for individual ships) and .wepn (weapon info files) can all be edited with the text editor of your choice. I use Windows' built-in editor (Notepad), because it's simple and perfectly suited for this task.
On top of that, we will need a tool to add hardpoints to ships. Hardpoints are "mounts" on which you can put stuff such as weapons and subsystems. For this, we will use a tool called HardEd which was coded by pip and which can be found here.
HardEd requires Microsoft's .NET framework to run. Download it here.
Finally, we need a way to actually get to the data we're going to edit. Most of the HW2 data is packed into .big archives - kinda like giant .zip files.
There are tools available to extract those archives, but then you still have to decompile the files. We don't want to worry about it, so we're going to download the files that have already been decompressed and decompiled. This data.zip can be found here.
This is a self-extracting RAR archive rather than a .zip file, because it achieves better compression. Download and double-click on the file to extract it.
Those are all the tools we'll need. Now let's have a look at how to set HW2 up for modding.
Part Two - Setting HW2 Up To Accept Mods
This is fairly simple. First off, go to your HW2 folder and copy the entire "data" folder someplace safe. This is just in case, should we screw anything up we can always fix it by putting the original files back.
Next, extract the contents of that data.exe to a temporary folder somewhere. It'll contain a lot of folders, but we only need a few of those, namely the Ships, Weapons, and Scripts folders.
Copy those folders to HW2\data. Your data folder in the HW2 directory should now look similar to this:
Now as a general rule of thumb, you should only keep those files in your data folder that you plan on modifying. This is important because some of the files may cause game crashes.
Open the scripts folder and remove everything with the exception of these folders:
+Building and Research
+startingfleet
+unitcaps
and this file:
-race.lua
Your scripts folder should now look like this:
Finally, you have to tell HW2 to actually accept the decompiled data (which we will be modifying) rather than the stock data. To do this, create a shortcut to HW2 (In case you don't have a shortcut: left-click on HW2 once, keep the left button pressed, hit ctrl and shift simultaneously while moving the mouse curser to your desktop, then release everything). Then right-click on your shortcut, and select "properties".
Take a look at the "target" line. It should read something like this:
Add -overrideBigFile to that line. It should now look exactly like this (obviously you have to replace the program files\sierra part with whereever it is you installed HW2 to):"C:\Program Files\Sierra\Homeworld 2\Bin\Release\Homeworld2.exe"
."C:\Program Files\Sierra\Homeworld 2\Bin\Release\Homeworld2.exe" -overrideBigFile
The quotation marks are important, don't forget them.
There, all done. You're now ready to start modding! Ok, try launching HW2 by double-clicking on that shortcut just to make sure everything works. From now on, when you are told to launch HW2, launch it with the shortcut.
Next up: enabling the keeper race in skirmish.
Part Three - Enabling The Keepers
Another easy one. The Keeper race is already all set up and ready to go, all you need to do is tell the game that you're allowed to play with them.
Go to your HW2\data\scripts folder and find the race.lua file. Open it in notepad.
It will look like this:
LuaDC version 0.9.19
-- 5/23/2004 7:23:16 PM
-- LuaDC by Age2uN
-- on error send source file (compiled lua) and this outputfile to Age2uN@gmx.net
--
NotPlayable = 0
Playable = 1
races =
{
{ "Invalid", "Invalid", "", "", 0, NotPlayable, "", },
{ "Hiigaran", "$1100", "hyperspace_gate", "etg/special/SPECIAL_ABILITIES_HYPERSPACE_IN", 9.5, Playable, "HGN_", },
{ "Vaygr", "$1101", "hyperspace_gate_vgr", "etg/special/SPECIAL_ABILITIES_HYPERSPACE_IN", 9.5, Playable, "VGR_", },
{ "Keeper", "Keeper", "hyperspace_gate_kpr", "etg/special/SPECIAL_ABILITIES_HYPERSPACE_IN", 12.5, NotPlayable, "KPR_", },
{ "Bentusi", "$1103", "hyperspace_gate_bentusi", "etg/special/SPECIAL_ABILITIES_HYPERSPACE_IN", 18.5, NotPlayable, "BEN_", },
{ "Random", "$3226", "", "", 0, Playable, "", },
}
Change the "NotPlayable" in the "Keeper" line to "Playable". That line should now look like this:
Save the file, and you're done! Launch HW2 (remember, use the shortcut!) and start a skirmish. Besides Hiigaran and Vaygr you should now be able to select "Keeper" from the drop-down menu.{ "Keeper", "Keeper", "hyperspace_gate_kpr", "etg/special/SPECIAL_ABILITIES_HYPERSPACE_IN", 12.5, Playable, "KPR_", },
Try playing a skirmish as keeper. It should load, but you will be defeated instantly - after all, you don't have any ships to begin with, so the game thinks the enemy just blew up your entire fleet. We'll get right on that problem in the next section - but for now you can pat yourself on the back, you just managed to successfully enable a previously unplayable race in HW2!
Part Four - Starting Fleets
We need to tell the game what units our Keeper race is supposed to start with in a skirmish game. To do that, go to the HW2\Data\Scripts\Startingfleet folder. Right now you should find two files there, Hiigara00.lua and Vaygr00.lua.
You guessed it - create a new file called Keeper00.lua in that folder. Copy-paste this stuff in there first and save it, we'll go through it line-by line next.
Ok, so what did we just do? Let's take it from the top.-- LuaDC version 0.9.19
-- 5/23/2004 7:23:48 PM
-- LuaDC by Age2uN
-- on error send source file (compiled lua) and this outputfile to Age2uN@gmx.net
--
PersistantData =
{
StrikeGroups = {},
Squadrons =
{
{
type = "Kpr_Bentus",
subsystems = {},
shiphold = {},
name = "",
size = 1,
number = 1, },
},
Research = {}, }
Those lines are for all intents and purposes useless - they are comments added by the decompiler script. We can learn one important thing from those lines though. Obviously -- designates a comment.-- LuaDC version 0.9.19
-- 5/23/2004 7:23:48 PM
-- LuaDC by Age2uN
-- on error send source file (compiled lua) and this outputfile to Age2uN@gmx.net
--
This means that if you put -- in a .lua file, that whole line will be ignored by the game. You can use it to add info (short notes to yourself about what you changed, so that you can later understand why you did something to the code), or you can use it to "comment out" a line. This is useful for troubleshooting.
Let's say you just added five new lines to a file, and the game suddenly stopped working. Now one of those lines is causing it, but which one?
Instead of deleting them, you can go through them one by one, adding -- in front of them. The game will now ignore that line, it's as if you never added it - but it's still there, so you don't have to start copy-pasting again if you want to re-enable it. All you have to do in order to enable it again is delete the --.
PersistantData is where the actual game info starts. In .lua files, functions are bracketed in by {}, similar to C++. Everything between two brackets "belongs" to that one function. You can nest those brackets as deep as you'd like.PersistantData =
{
StrikeGroups = {},
StrikeGroups can be used to pre-define strike groups (I think) if you want to script more complex missions. For example, you could decide to have the mothership strafed by a group of bombers right away - you would use strike groups for that. We're not going to use this function, so just leave it empty.
Squadrons is used to define the squadrons you'll start with. In our case, this is one ship type at first, which is Kpr_Bentus - our modified Bentus mothership.Squadrons =
{
{
type = "Kpr_Bentus",
subsystems = {},
shiphold = {},
name = "",
size = 1,
number = 1, },
},
As you can see, using this function is fairly straightforward. type determines what kind of ship you want, subsystems and shiphold tell the game if the ship is supposed to have any subsystems already built and if it's supposed to have a hangar filled with ships.
I'm not sure whatsize does, so just leave it at the default value.
Finally, number determines how many ships of that type we want to start out with.
Starting the game now will result in an error - there is no Kpr_Bentus, after all! We'll see how to fix that in the next section.
Part Five - Bentus, Our Mothership
When you open your Data\Ships folder, you will see a lot of subfolders, one for each ship. Let's take a quick look at the prefixes and what they mean:
Kpr = Keeper (duh!)
Hgn = Hiigaran (more duh!)
Vgr = Vaygr (duh!)
Meg = Megalith (stuff like the Tanis shipyards, parts of the Bentus debris, etc)
Neu = neutral (transports)
SP = singleplayer campaign stuff
Right now we're looking for the folder called Meg_Bentus. Rename it to Kpr_Bentus, then open it. There should be two files inside with the meg_ prefix, which you should replace with the kpr_ prefix. Your kpr_Bentus folder should now contain these two files:
Kpr_Bentus.events
Kpr_Bentus.ship
Actually, if you had decompiled this manually, there would be a third file called Kpr_Bentus.hod. The .hod file contains texture and hardpoint data, we will work on that later. Since the file is needed though, download it here and put it in the Kpr_Bentus folder, which will now have the following contents:
Kpr_Bentus.events
Kpr_Bentus.ship
Kpr_Bentus.hod
The .events file contains all the information regarding the ship's FX animations. These animations are basicaly a series of FX that are triggered with a set delay so that they run in a sequence (although often there may onlt be a single effect).
These animations mainly include things such as damage, death animations and weapon muzzle FX as well as many other effects. Since we won't be changing any of that, we'll leave that file alone.
Finally, the .ship file is where all the information about the ship itself, such as speed, armor, weapons and much more is stored.
Double-click on the .ship file. Since windows doesn't know what to do with .ship files, a dialog will appear asking you what you want to do with the file.
Choose "I want to choose a program from a list". Then scroll down in that list until you find "notepad". Make sure the "always open with this program" option box is ticked, and press ok. From now on, when you double-click on .ship files, they will be opened with Notepad.
The .ship file is huge. We can see loads of values there, some of which are way too complex to go into right now. For now, close the window without saving and start HW2. Start a skirmish with the Keepers. You should now have a huge Bentus sitting there as your starting fleet. However, you will notice that Bentus doesn't do anything - it just sits there, it won't move, it won't Hyperspace, and it most certainly won't shoot anything. Since Bentus was never intended to do any of this, she lacks info on how to accomplish all those things. We will have to teach her how to do this!
Next up: Making our ship mobile.
Part Six - Making Bentus Move
The reason why Bentus just sits there is twofold - first off, the game doesn't really know how the ship is supposed to move, and secondly it is not set up to accept move commands. Let's remedy that.
Look for this line:
Now change that "None" to "Ship".NewShipType.controllerType = "None"
Also add this line anywhere in the file:
Finally, add these two lines:addAbility(NewShipType, "MoveCommand", 1, 0)
What did we just do?addAbility(NewShipType, "HyperSpaceCommand", 1, 10, 100, 400, 10, 15)
addAbility(NewShipType,"CanBuildShips",1,"","");
Well, the first line (I think, I'm not entirely sure here) tells the game how the ship is supposed to behave movement-wise. The second line teaches our ship to actually accept movement commands. The next line teaches Bentus how to hyperspace. Don't worry about the numbers, you can look up what they do on the Karos Graveyard.
The last line gives Bentus the ability to build ships. This is necessary because you need a build-capable ship to start with, or you will be defeated instantly. We don't have any build trees defined yet, so you won't be able to build anything at the moment - what counts is having the capability to do so.
To summarize, we have now made the following changes:
Now Bentus knows how to move! For testing purposes, let's make sure she actually moves and doesn't just slowly float along.NewShipType.controllerType = "Ship"
addAbility(NewShipType, "MoveCommand", 1, 0)
addAbility(NewShipType, "HyperSpaceCommand", 1, 10, 100, 400, 10, 15)
addAbility(NewShipType,"CanBuildShips",1,"","");
Let's find these lines:
The names are pretty self-explanatory. I'm not entirely sure why there are both thrusters and main engines, because the ship seems to use both of them.NewShipType.thrusterMaxSpeed = 50
NewShipType.mainEngineMaxSpeed = 50
NewShipType.rotationMaxSpeed = 40
NewShipType.thrusterAccelTime = 1
NewShipType.thrusterBrakeTime = 1
NewShipType.mainEngineAccelTime = 6
NewShipType.mainEngineBrakeTime = 1
NewShipType.rotationAccelTime = 0.2
NewShipType.rotationBrakeTime = 0.2
Just to be on the safe side, we will give them similar values though - set both of them to 900. Rotation controls how fast the ship can turn, a value of 90 will ensure swift turns.
AccelTime and BrakeTime control how long it takes the ship to speed up and slow down. Let's set the values for MainEngine and Thruster to 1, meaning the ship can reach full speed and come to a full stop in one second.
The last two lines control how fast the ship can accelerate to its maximum rotation speed, .2 seconds sounds about right for our purposes.
After those changes, these nine lines should now look like this:
Save the file, and launch HW2. You should now be able to issue move commands to Bentus, and she should respond pretty darn quickly. Also try hyperspacing her. Of course, those speeds are insane for a mothership, but we don't want to wait ten minutes until Bentus gets somewhere once we get into weapon testing (she does need to move closer to the stuff she's supposed to shoot, after all).NewShipType.thrusterMaxSpeed = 900
NewShipType.mainEngineMaxSpeed = 900
NewShipType.rotationMaxSpeed = 90
NewShipType.thrusterAccelTime = 1
NewShipType.thrusterBrakeTime = 1
NewShipType.mainEngineAccelTime = 1
NewShipType.mainEngineBrakeTime = 1
NewShipType.rotationAccelTime = 0.2
NewShipType.rotationBrakeTime = 0.2
Moving is all well and good, but we want to blow stuff up! We will build a weapon for her in the next section.
Part Seven - Weapons Development
No doubt about it, Bentus needs to be armed. But using one of the stock weapons would be boring, so let's build our own. We will heavily modify the weapon that is used by the Hiigaran Mothership. "Heavily modify" means "turn from sucky to wtfbbq" in our case.
Open your Data\weapon folder. Similar to the ship folder, every weapon has a folder. Create a new one called hgn_bentushulldefense. Then open the folder called hgn_mshulldefensegun, and copy the .wepn file to our new directory, and rename it hgn_bentushulldefense.wepn.
Double-click on the file. Once again, Windows won't know what the heck to do with this file - use notepad to open it.
Let's have a look at the file:
The most important stuff can be found in the first non-comment line. StartWeaponConfig has all the values for firing speed, range, weapon type, etc, etc, in it.StartWeaponConfig(NewWeaponType, "Gimble", "Bullet", "HDefense", "Normal", 2500, 2200, 0, 0, 0, 0, 1, 1, 0, 2, 0, 0, 1, 0, 0, 0, 0.1, "Normal", 0, 0, 0)
AddWeaponResult(NewWeaponType, "Hit", "DamageHealth", "Target", 20, 20, "")
setPenetration(NewWeaponType, 5, 1,
{
PlanetKillerArmour = 0,
},
{
ResArmour = 0.75,
},
{
TurretArmour = 3, })
setAccuracy(NewWeaponType, 1,
{
Fighter = 0.14,
},
{
Corvette = 0.45,
},
{
munition = 0.2, })
setAngles(NewWeaponType, 90, 0, 0, 0, 0)
As you can see that function has a lot of variables - tons of numbers in that line! Let's go through them one by one, heavily borrowing from Karos Graveyard in the process.
The following list goes through the arguments from left to right. <> denotes the argument name, [] will be the value that argument has in our example.
- <sWeaponName> [NewWeaponType]: Reference to the weapon. Generally, this will be NewWeaponType.
- <sWeaponType> [Gimble]: How the weapon tracks targets. Possible values are Gimble, AnimatedTurret, or Fixed. Gimble indicates the weapon is not in a turret but can aim at targets within a certain cone. AnimatedTurret indicates that the weapon is mounted in a visible, moving turret. Fixed indicates the weapon can only fire in a fixed (unchanging) direction, such as the ion cannon on the Ion Cannon Frigate.
- <sWeaponFireType>[Bullet]: Type of projectile, possible values are InstantHit, Bullet, Mine, Missile, or SphereBurst. InstantHit is generally used with beam weapons, and causes the weapon's damage or other effects to take place immediately upon firing. Bullet indicates an unguided projectile. Mine indicates the projectile is dropped where the ship is located, and waits to detonate when an enemy ship moves nearby. Missile indicates a guided projectile.
SphereBurst indicates an area of effect weapon. SphereBurst weapons require two ".wepn" files to be defined. The first ".wepn" file defines how the weapon is fired, while the second ".wepn" file defines the effects of a hit or miss. See "hgn_smallemp.wepn" and "hgn_smallempburst.wepn" for an example.- <sWeaponFireName>[HDefense]: The name of the weapon fire script (".wf" file) that specifies effects details.
- <sActivation>[Normal]: When the weapon is used. Possible values are Normal, Special Attack, Normal Only, or Dropped. Normal indicates the weapon is always used during any attack. Special Attack indicates the weapon is used only after being activated by research or by the special attack key, which is also active only after researching something. Normal Only indicates the weapon is used only if a special attack is not researched. Dropped indicates that the weapon fires only when the Deploy Mines key is used. This is used with mines, only.
- <fWeaponFireSpeed>[2500]: Projectile velocity. For Missile weapons, this is the initial velocity. For InstantHit and SphereBurst weapons, set to 0.
- <fWeaponFireRange>[2200]: Maximum range at which the weapon may fire. Note that this does not indicate the maximum range of the projectile.
- <fWeaponFireRadius>[0]: Only used for SphereBurst. This determines the radius of the blast, within which all specified ships are affected by the weapon.
- <fWeaponFireLifetime>[0]: Duration of the projectile, in seconds. Used for beam weapons, only.
- <fWeaponFireMisc1>[0]: For beam weapons, this is the anticipation time. The time after the firing sequence starts until the beam appears.
- <iWeaponFireAxis>[0]: For missiles only. The direction of ejection for the missile. Possible values: 0 (Forward), 1 (Left), and 2 (Up).
- <iMaxEffectsSpawned>[1]: Maximum number of hit effects to spawn over the lifetime of the weapon. If lifetime is 0, then 1 effect will be spawned.
- <iUseVelocityPred>[1]: If enabled, the weapon will lead the target. Otherwise, it fires directly at the target.
- <iCheckLineOfFire>[0]: If enabled, the weapon checks for friendlies in the way before firing.
- <fFireTime>[2]: Delay between shots, in seconds.
- <fBurstFireTime>[0]: Duration of a burst, in seconds. Divide this value by iFireTime to determine how many shots are fired per burst.
- <fBurstWaitTime>[0]: Delay between bursts, in seconds.
- <iShootAtSecondaries>[1]: If enabled, when the weapon cannot shoot the main target, it will try to shoot secondary targets.
- <iShootAtSurroundings>[0]: If enabled, when the weapon cannot shoot any of the given targets, it will scan for nearby enemies (SLOW!).
- <fMaxAzimuthSpeed>[0]: Horizontal tracking speed of the weapon.
- <fMaxDeclinationSpeed>[0]: Vertical tracking speed of the weapon.
- <fSpeedMultiplierWhenPointingAtTarget>[0.1]: When the weapon is over the target ship, its speed is modified by this. Use < 1 to make beams sweep slowly over the target.
- <sWeaponShieldPenetration>[Normal]: Possible values are Normal, Enhanced, or Bypass. This argument has no obvious effect. The chance that a weapon penetrates a defense field is set by the setPenetration function.
- <iTrackTargetsOutsideRange>[0]: If enabled, the weapon tracks targets outside of its range.
- <fWaitUntillCodeRedState>[0]: Animation hookup. With this set, the weapon cannot fire untill the Code Red Animation finishes. See the Vaygr Missile Frigate.
- <iInstantHitThreshold>[0]: If the target has less than this health, the beam will go through the target ship.
Now that's a lot of info. But we're in luck - we're not going to have to change all of them.
Before we jump into that, let's think a bit about what our weapon should look like. The Bentusi are obviously very advanced and would never build little projectile pea-shooters to protect their most important ship in their fleet! So we'll want to use a beam weapon. The game already has point-defense beam weapons - the pulsars on the Hiigaran HC for example. We'll build an improved version of those.
This is what our weapon will look like:
Now let's go through the changes.StartWeaponConfig(NewWeaponType, "Gimble", "InstantHit", "Laser", "Normal", 0, 20000, 0, 0.4, 0, 0, 1, 0, 1, 0.4, 0.0, 0.0, 1, 1, 120, 120, 0.1, "Normal", 1, 0, 300)
AddWeaponResult(NewWeaponType, "Hit", "DamageHealth", "Target", 50, 50, "")
setPenetration(NewWeaponType, 5, 1,
{
PlanetKillerArmour = 0, })
setAccuracy(NewWeaponType, 1,
{
Fighter = 0.11,
},
{
Corvette = 0.5,
},
{
munition = 0.1, })
setAngles(NewWeaponType, 90, -180, 180, -180, 180)
setMiscValues(NewWeaponType, 0, 0)
Gimble means that our weapon isn't turreted like the heavy ion beams, but can aim in all directions within a pre-defined cone of fire - we'll talk about that later. Since we don't want to start constructing a turret here, we'll be going with Gimble.
Bullet has been replaced with InstantHit. Since we're using a laser, there's no bullet - our weapon travels at the speed of light, which translates to instantaneous hits at the distances we're talking about in this game.
Laser refers to the graphics used for the weapon, in our case those pretty blue streaks of concentrated energy.
Normal means that our ship will use this weapon as a normal weapon rather than a special attack weapon which has to be activated by the user.
With those out of the way let's dive into that mess of numbers.
The speed at which our weapon travels is essentially infinite - we also showed this by using InstantHit. Since there are no weapons that stand still in this game, 0 is used to denote infinite weapon speeds.
The range for our weapon has been upped to 20000. That range is horribly unfair, but great for testing purposes.
The 0 after that is for the weapon radius - this is only used with sphere weapons such as the EMP device, so we'll leave it at 0.
Next up - weapon lifetime. 0.4 means that the beam will "live" for .4 seconds before fading. This was set to 0 with the original gun, because the bullet doesn't fade away.
The next two values don't really apply to our weapon, so we'll leave them at 0.
Again, the next value is something we won't play around with - leave it at 1.
The next value is a boolean - it can be set to 0 (off) or 1 (on). Since our beam is an instant hit weapon, we don't need to lead the target - we point at it and fire. We want this thing turned off, so we set the value to 0.
Another switch can be found at the next entry. This time we set it to "on", because we don't want to blow up friendlies when trying to defend ourselves. Setting this to 1 will mean that the ship will check for friendly ships in the line of fire before discharging the weapon.
The next three numbers essentially control how fast and how often the weapon fires. With these three numbers you can do anything from regular firing intervals (like one shot every two seconds) to salvoes (shoot three times, pause, shoot three more times...). For now, we want a steady, sustained, high rate of fire - set the first value to 0.4 (meaning one shot every 0.4 seconds) and the next two to 0 (meaning no bursts, and no pauses between bursts).
The rest of the values aren't really that important, we don't need to discuss them.
Right, now the next lines deal with accuracy, we can leave that unchanged for now. 1.0 would mean 100% accuracy, 0.11 means 11% accuracy - you can play with those values if you like.
This line
is the last line we have to worry about in our weapons file. It basically tells the weapon how far it can rotate and thereby defines the cone of fire. Since we're using a Gimble weapon, only the first value is important. It tells us how many degrees the weapon can turn in either direction from its default direction.setAngles(NewWeaponType, 90, -180, 180, -180, 180)
If set to 90 degrees like in this case the weapon can aim at anything that is on a half-sphere in front of it - 90 degrees in either direction. We don't want to give it a full 360 degree cone of fire, because it would start shooting through our ship, and that would look weird.
That concludes the weapon development phase, now we have to put that weapon on Bentus!
Part Eight - Arming Bentus
Arming the ship consists of two parts. The first part is adding a hardpoint for the weapon. A hardpoint is kind of like a weapons mount. It's invisible, but it defines where the weapon goes on the ship.
The second part is easier and involves assigning a weapon to the hardpoint.
To add hardpoints we use a nifty little tool developed by pipakin called HardEd. See Part 1 of this tutorial for instructions on how to obtain and install HardEd.
Start HardEd by double-clicking on the HardEd.exe file. A small empty window with a menu bar will appear. Click on "File", select "open", and browse to the kpr_bentus folder. Open the kpr_bentus.hod file.
After a short pause HardEd will display the hardpoint tree for that ship. Currently, all we can see is a single entry called "Root". By clicking on the little + sign next to Root we can expand it, similar to the folder navigation menu in Windows explorer. Since Bentus doesn't have any hardpoints yet, this will be very basic:
You will notice an entry called "children". Left-click on it once to highlight it, then select the "Options" menu from the menu bar and click on "add child".
A child will be added to the children entry. It will have a generic nondescriptive name, probably New_Child01 or something like that.
Left-click on the new entry once, and then do a slow double-click. You should now be able to rename this entry. The slow double-click will take a while getting used to, so don't give up if it doesn't work at first.
We'll rename our entry Weapon_HullDefense1_Position. Now expand it by clicking on the + sign next to it.
You will notice a bunch of sub-entries, some of which can be expanded again:
Now what the heck was all of that about? Let's recap what we did.
First, we created a child entry. Child in this case means that it is a part of its parent entry.
Next we gave it a new name. Weapon_ shows that this hardpoint will be used to hold a weapon rather than a subsystem for example. HullDefense1 is what we call this one because it'll hold a point defense type of weapon. Of course you can call it whatever you want, however it makes sense to choose descriptive names so you know what the heck is going on later.
Finally, _Position indicates that this entry will be used to determine where the weapon will go on the ship. The first two parts of the name are yours to choose, but the name must end in _Position.
Click on the "Children" entry of Weapon_HullDefense1_Position. Once again, select options from the menu bar, and create three more children.
Rename one of them Weapon_HullDefense1_Direction and the other two Weapon_HullDefense1_Rest and Weapon_HullDefense1_Muzzle.
The naming is important here. The first two parts of the name should be the same as for the parent, and the third parts have to be _Rest, _Direction and _Muzzle. We'll go over that in a minute. For now, make sure your entry tree looks something like this:
Return to the Weapon_HullDefense1_Position entry and expand the "Data" sub-entry. Left-click on "Position" once to highlight it. Then press "t" to open the position chooser.
The chooser displays a wireframe model of the ship and offers both a top-down view (right side) and a frontal view (upper left corner). The red x marks where the hardpoint will be. If you move the mouse around you will see the x,y,z coordinates for the mouse cursor in the lower left part of the window.
Left-clicking will move the red x. For now, try to place it on the left corner at the end of the left strut of Bentus, then click "ok":
We have now placed the weapon, but it still doesn't know where it's pointing. That's what the children we created are for. Let's have a look at our offspring!
First off, the _Muzzle thing doesn't seem to be important for us, you can simply ignore it. The other two children however, _Rest and _Direction, are quite vital. They determine which way the turret faces.
The two children are basically just vectors. Don't worry if you haven't had any vector math (yet?), this is all very easy.
A vector is basically just an arrow. Since HW2 is a three-dimensional RTS, our vectors are three-dimensional vectors as well.
Now how does this work? I'm sure you know that points in 3-D space can be expressed as a set of three coordinates, labelled x, y and z. For example, (0,10,0) is a point that is 10 meters away from the origin (that would be the point where our coordinate axis intersect) in y-direction.
Since we're talking about putting weapons on a ship, we are using coordinates that are linked to the ship. The origin is at the center of gravity (the "middle" of the ship). The directions are as follows:
Z means fore and aft, measured from the center of the ship. If our ship is 500 meters long, an z coordinate of 250 means that we're at the bow, whereas -250 means we're at the stern of the ship.
X corresponds with left and right, or port and starboard in nautical lingo. Positive x means port, negative means starboard. If our ship is 200 meters wide, an x of +100 means that we're on the port side, -100 means we're at the starboard side.
Finally, y is linked to up and down. Positive y means up, negative means down - a y of -50 indicates that we're somewhere below the centerline of a ship, and +50 means we're topside.
Now that we know all about HW2 ship coordinates, we can get back to our original problem. Using the position chooser tool we have assigned a position to our weapon - but we haven't really told the program yet how to actually attach the weapon. For all we know it could put it on that hardpoint upside-down!
The _Direction vector makes sure that the turret is put on correctly. Mathematically speaking this vector is the normal vector for our turret. This means that it is kinda sticking out of the "roof" of our turret and pointing straight up.
The other vector, _Rest, points in the same direction as the barrel of the turret when it is pointing in the default direction, i.e. it hasn't turned yet to fire at stuff.
This can be illustrated using the Hiigaran battlecruiser forward kinetic turret:
This can be a bit confusing, so I'll talk about this some more. Consider the forward kinetic turrets of the Hiigaran battlecruiser. There are two of them, one is mounted on top and one below at the bottom of the ship. What are their _Direction and _Rest values then?
We'll start with the upper turret. It is facing straight ahead, so the _Rest vector has to point straight ahead as well. This means that both the x and y coordinates are 0 - the turret is not facing up or down at all, nor is it turned to either side. This leaves us with the z coordinate. Mathematically speaking, any value you put in here would be correct - 1 would yield the same result as 10, for example. We'll be using 10, because it's a nice number.
The _Rest vector for that turret therefore is (0,0,10). If the turret were facing backwards, it would be (0,0,-10). To get a turret that is turned all the way to starboard, you would use this vector: (-10,0,0). To get one that is turned halfway to starboard, this vector would do the trick: (-10,0,10).
So what does the _Direction vector look like? Well, the "roof" of that turret is facing straight up. "Up" means positive y, so our direction vector is (0,10,0).
The lower turret faces the same way as the upper one, so its _Rest vector is (0,0,10) as well. It is however mounted "upside-down", meaning that the "roof" points straight down, so the _Direction vector is (0,-10,0).
Now we can finally get back to Bentus. We placed that hardpoint at the left side of our ship. We don't really have a turret, and since we're still on the centerline height-wise, we'll have our turret's roof vector pointing straight up. Open the Hulldefenseweapon1_Direction entry by clicking on the + sign. Once again you'll see the familiar Data and Children subentries. Expand tha Data entry, and then expand the position entry. You'll see three values, all of which are set to 0. They correspond with the x,y and z coordinates of our vector from top to bottom - the first one is x, the last one is z.
We want our _Direction vector to point straight up, which means a vector of (0,10,0). Go ahead and edit the second value, replacing the 0 with a 10. That entry should now look like this:
Now we need to think about where our turret should point. In our .wepn file we gave it a 180 degree cone of fire. Since this weapon is located at the side of the ship, we would want it to point outwards at a right angle to the hull. If it were to point forward for example, the 180 degree angle would mean that it could fire through the ship on one side.
This is where it gets a bit tricky. The right-hand side of the position picker shows the ship as seen from below, not from above. Therefore, left in the position picker actually means right.
This turret is at the right side of the ship. Right means starboard, and that means negative x.
Open the _Rest entry, expand Data and find the Position entry. Open it to find all three values set to 0.
Change the first one to -10 (remember, the first value is x, and we want it to be negative, so we'll use -10. A value of 10 would mean that the weapon would point to port).
Here's what it should look like in HardEd:
As promised, we don't have to worry about the muzzle entry. Save your work and exit harded.
Now for the second part - mounting a weapon on the hardpoint. This will be very easy, it only involves adding one line to the .ship file.
Open Kpr_Bentus.ship. Add this line (I prefer at the end, but the exact location won't matter too much):
This tells the game to add a weapon of "Hgn_BentusHullDefense" type (which we previously developed) to the "Weapon_HullDefense1) hardpoint.StartShipWeaponConfig(NewShipType, "Hgn_BentusHullDefense", "Weapon_HullDefense1", "Weapon_HullDefense1")
Bentus is now armed, but she doesn't know what to do with her weapons yet. We need to set her up so that she will accept attack orders, similar to the way we added the move command.
Add this line:
It tells Bentus what to attack, and how to attack it. Let's have a brief look at the values:addAbility(NewShipType, "CanAttack", 1, 1, 0, 0, 0.35, 1.2, "Capturer, Frigate, SmallCapitalShip, BigCapitalShip, Mothership, Utility, Corvette, Fighter", "MoveToTargetAndShoot")
<bIsActive[1]>: is the ability active by default? (0 = inactive, 1 = active)
<iNumberOfShips[1]>: the number of ships in micro formations that ships form in combat. This is useful if you have squads of ships, for example a group of six fighters. A value of 2 would cause the fighters to break up into two groups of three fighters each, a value of 3 would cause them to split up in pairs in our example, and a value of 6 would mean single-ship attack formations.
<bKamikaze[0]>: This value is obsolete, as Kamikaze attacks are not really supported by HW2.
<bInterpolate[0]>: can the ship interpolate targets? Not quite sure what that means, I think it has something to do with the way the ship aims at or switches between targets.
<fSplitDelay[0]>: the delay between formation splitting (in seconds).Not interesting in our case, since Bentus is only one ship.
<fDistanceMultiplier[0.35]>: the distance multiplier from target before attack styles get control. I'm not entirely sure about this one either. I think it tells the ship when to start switching to attack maneuvers as it approaches the target
<sAttackFamilies>: a comma-separated list of attack families, in order of highest to lowest attack priority. What ship types can it attack? We want Bentus to be able to shoot at anything, so we'll just list them all.
<sAttackStyle>: the default method (style) that the ship will use to engage all targets. This governs how Bentus will behave when attacking something. There are several pre-defined maneuvers, a straightforward "move towards the target and blow the crap out of it" approach seems most fitting for our massive mothership. After all, having it perform inverse Immelman maneuvers around a fighter that is about 1/1000th its size would look bloody ridiculous...
<tStyleException1> thru <tStyleExceptionN>: exceptions that override <sDefaultAttack> for the specified family. If you want the ship to behave differently towards certain targets, you can specify that here. For example, say you want a battlecruiser to stand still when engaging fighters, but to move around when engaging capital ships. This is where you would define those behaviour patterns.
All done! Save the ship file and fire up HW2. Start a skirmish vs CPU, with yourself as keeper and the enemy as Vaygr. Move Bentus towards the enemy, set her to agressive and issue an attack order. If you followed the steps correctly, you should be rewarded with the sight of Bentus pounding the hell out of a bunch of resourcers with its single weapon.
One weapon doesn't quite cut it though. Following the steps outlined above, let's add five more weapons. The second weapon hardpoint will be called Weapon_HullDefense2 and should be on the opposite side of the one we already created. The next pair should be approximately along the middle line of Bentus, and the final pair at the rounded part. Refer to this screenshot for position estimates:
As you can see, there are a total of six weapon hardpoints, three per side. Place them using the position chooser as described earlier. You will also have to create the three children for each of them with corresponding names.
The _Direction entry will be the same for all six hardpoints, but the _Rest values will differ somewhat. Let's think about that for a minute.
The first entry was on the starboard side of the ship, with the weapon pointing in that same direction, so the Position entry for the _Rest child was (-10,0,0).
Weapon_HullDefense2 is on the opposite side of the ship, i.e. it's at the port side and facing port. That means the _Rest vector should be (10,0,0).
The same is true for Weapon_HullDefense3, whereas Weapon_HullDefense4 is on the same side as Weapon_HullDefense1, so both of those have the same _Rest vector of (-10,0,0).
The last two weapons, called Weapon_HullDefense5 and 6, are sitting at a 45 degree angle. We want their weapons to point out at that angle as well, which means they should be turned halfway to port or starboard, respectively.
Weapon_HullDefense5 is on the starboard side and pointing both port and forward, so its _Rest vector should be (10,0,10). In a similar fashion, Weapon_HullDefense6 is on the port side, pointing starboard and forward, which means the _Rest vector for this weapon is (-10,0,10).
Your HardEd window should now look like this:
All those new weapons have to be added to the ship file, so you will have to add these five lines:
Save the .hod file in HardEd and the .ship file in Notepad, and launch HW2 again. If everything went correctly, you should now see something like this:StartShipWeaponConfig(NewShipType, "Hgn_BentusHullDefense", "Weapon_HullDefense2", "Weapon_HullDefense2")
StartShipWeaponConfig(NewShipType, "Hgn_BentusHullDefense", "Weapon_HullDefense3", "Weapon_HullDefense3")
StartShipWeaponConfig(NewShipType, "Hgn_BentusHullDefense", "Weapon_HullDefense4", "Weapon_HullDefense4")
StartShipWeaponConfig(NewShipType, "Hgn_BentusHullDefense", "Weapon_HullDefense5", "Weapon_HullDefense5")
StartShipWeaponConfig(NewShipType, "Hgn_BentusHullDefense", "Weapon_HullDefense6", "Weapon_HullDefense6")
Incidentally, this was by far the hardest part of this tutorial. The next steps won't be that difficult. In the next section we'll be developing a build tree.
Part Nine - Building Ships
Before we dive into the building fun, we'll have to adjust something in our scripts folder.
Open your Data\Scripts\Building and Research\Keeper folder. You will see four files:
.
If you do not see the file endings, e.g. if all you see is a file called "build" for example, then you have to adjust your windows explorer settings to display file extensions.
In order to correct that, you have to do these three things:
1. On the Tools menu in My Computer or Windows Explorer, click Folder Options.
2. Click the View tab.
3. Clear the "Hide extensions for known file types" check box.
Ok, back to our files. Double-click on build.lua. Since you already assigned .lua files to notepad back when you opened the race.lua file, this should result in a notepad window opening. However, the file will look like this:
That's a complete mess! What you can see here is a compiled .lua file. This is what you get when you decompress the .big archive. Remember how we talked about having to decompile files? We didn't have to do that so far, because the archive we used already contained the decompiled files.Lua@ æ[¡°¹²AC @X:\Homeworld2\Data\Scripts\Building and Research\Keeper\build.lua
Don't worry, you don't have to do anything complicated now either. The decompiled files are already in the directory, those are the ones with the .luadc file extension.
This is pretty much how a folder would look if you had decompressed and decompiled it manually.
Back to modding. Go ahead and delete the build.lua and research.lua files (the ones with the red arrows pointing at them in my screenshot). Then rename the remaining two files by simply removing the .luadc file extension.
You should now have two files in that folder, called build.lua and research.lua. Since we're talking about build trees, go ahead and open the build.lua.
Here's what it contains:
Not much info there, eh? That does make sense, after all the keeper weren't supposed to be able to build anything. Well, let's compare it to the Hiigaran build file. Go into the Hiigaran build and research folder, and open the build.lua.luadc file with notepad.Ship = 0
SubSystem = 1
build = {}
It's fairly large, I'll just post an exerpt:
Wow, lots of info there! Note that I cut out some parts because they weren't interesting. I also color-coded sections to make it easier to distinguish them.Ship = 0
SubSystem = 1
build =
{
{
Type = SubSystem,
ThingToBuild = "Hgn_C_Production_Fighter",
RequiredResearch = "",
RequiredShipSubSystems = "",
DisplayPriority = 0,
DisplayedName = "$7000",
Description = "$7001", },
{
Type = Ship,
ThingToBuild = "Hgn_Scout",
RequiredResearch = "",
RequiredShipSubSystems = "",
DisplayPriority = 10,
DisplayedName = "$7030",
Description = "$7031", },
{
Type = Ship,
ThingToBuild = "Hgn_Interceptor",
RequiredResearch = "",
RequiredShipSubSystems = "FighterProduction",
DisplayPriority = 20,
DisplayedName = "$7032",
Description = "$7033", },
{
Type = Ship,
ThingToBuild = "Hgn_MinelayerCorvette",
RequiredResearch = "GraviticAttractionMines",
RequiredShipSubSystems = "CorvetteProduction",
DisplayPriority = 52,
DisplayedName = "$7042",
Description = "$7043", },
Let's take it from the top. The first two lines appear to be the same for all races, so we'll just ignore them. Instead, we'll look at the structure of this file.
It is divided in multiple sections, each one dedicated to one buildable item, such as subsystems or ships. Each section contains these lines:
They are mostly quite easy to understand. Type tells us what kind of item we're building. This is either a subsystem or a ship.Type
ThingToBuild ,
RequiredResearch ,
RequiredShipSubSystems ,
DisplayPriority = ,
DisplayedName = ,
Description = ,
RequiredResearch and RequiredShipSubSystems show what requirements have to be met so that this item will be buildable.
DisplayPriority is a little tricky. I think it has something to do with the way the list of ships in your build menu is organzied, e.g. making sure that the carrier is displayed above the shipyard, for example. The only important thing for us to know here is that no two items should ever have the same priority.
DisplayedName and Description are the name of that ship type and the short description telling us what the ship is good against - basically the stuff you get when you hover over that little arrow icon in the build menu.
You will notice that there is no real text here, but rather some weird number string. That is because all this info is stored in a large table somewhere, and $5676 tells the program where to look for that info.
We don't have to mess with that table however - you can just put normal text inside those quotation marks.
Now let's look at a few examples. The red part is a subsystem. Since we won't be using any of those, we don't have to spend time with it, I included it mainly for reference purposes.
The blue section is the build entry for the Hiigaran Scout. The scout is obviously a ship, which is why Type is set to ship. You can build it right away, so there are no requirements at all.
You do however need a fighter facility to build an interceptor. Looking at the green section we can see that the RequiredResearch field is still empty, which makes sense, because you don't have to research anything to get the interceptor. The RequiredShipSubSystem field now reads "FighterProduction", which is the name of the fighter production subsystem that is needed to contruct these ships.
An example of required research would be the minelayer corvette, shown in black. The RequiredResearch field reads "GraviticAttractionMines", the name for that research. We will see it in the research.lua in our next chapter. The corvette also requires a corvette production facility, which is stated in the next line.
That seems simple enough, doesn't it? Now we can start designing our own build menu. Before we do that, we should think about what ships we are going to build though.
The keeper have the following ships:
Fighter-class: Attack Drone
Corvette-class: Mover
Frigate-class: none
Destroyer-class: Keeper Destroyer
Battleship-class: Dreadnought
Civilian-class: none.
That last thing is going to be a problem - they have no resourcers! Not to worry though, we'll just steal some from the Hiigaran. However, they still wouldn't have a place to drop off the resources.
Now we could add a resource dropoff point to Bentus, but I'm not quite sure how to do that, and I think you have to screw around with docking paths and other evil stuff for that. I'm going to ask around, otherwise we'll just use a resource controller.
More to come eventually. In the meantime, here's a short tutorial on how to get the AI to actually build ships, written by Classicthunder. Thanks for letting me incorporate this!
Step 1: Preparing the ships to be used in multiplayer.
Okay now we are going to set up the kpr_mover, the kpr_capture_mover, the kpr_attackdroid, kpr_sajuuk, and the kpr_Destroyer for use in multiplayer.
To do this we need to change the unit caps family and the display family for each craft.
_____Fixing the unit cap.
So open kpr_mover in the ships folder and change the below line
to this.Code:NewShipType.UnitCapsFamily = "SPMovers"
There now the Mover has a usable max ship capacity number. If we hadn’t changed this line the mover would have a unit cap of 0.Code:NewShipType.UnitCapsFamily = "Corvette"
_____Fixing the Display Type
The other line that will need to be changed sometimes is this one.
This line tells what class the ship is under in the build manager. Example a ship set to “Capital” will show up under the Capitalship build menu. For the mover we can leave the line as NewShipType.DisplayFamily = “Corvette”.Code:NewShipType.DisplayFamily
Now repeat this for all of the ships making it so that those lines look like this for each type of ship.
For the Attackdroid:
Capture Mover:Code:NewShipType.DisplayFamily = "Fighter" NewShipType.UnitCapsFamily = "Fighter"
Sajjuk:Code:NewShipType.DisplayFamily = "Corvette " NewShipType.UnitCapsFamily = "Corvette "
Destroyer:Code:NewShipType.DisplayFamily = "Capital" NewShipType.UnitCapsFamily = "Capital"
Code:NewShipType.DisplayFamily = "Capital" NewShipType.UnitCapsFamily = "Capital"
Step 2: Adding the Ships to the Build Manager.
Okay now go to scripts\building and research\keeper and open up build.lua. It should look like this.
-- LuaDC version 1.0.1
-- 6/1/2006 2:57:06 PM
-- LuaDC by Age2uN
-- on error send source file (compiled lua) and this outputfile to Age2uN@gmx.net
--
Ship = 0
SubSystem = 1
build = {}
Okay now lest fill it in with our ships. First move the second bracket down two rows and then indent it until the build.lua looks like this.
-- LuaDC version 1.0.1
-- 6/1/2006 2:57:06 PM
-- LuaDC by Age2uN
-- on error send source file (compiled lua) and this outputfile to Age2uN@gmx.net
--
Ship = 0
SubSystem = 1
build = {
}
Copy this into the gap between the brackets and then fill in where I have text for each ship.
Now open up the hiigaran\build.lua and copy out the recoursecontroller and the recoursecollector build info and add it into your keeper\build.lua.Code:Type = Ship, ThingToBuild = "Ship Name Here ", RequiredResearch = "", RequiredShipSubSystems = "", DisplayPriority =The lower the number the higher up it appers on the build manager, DisplayedName = "Enter The Name that the Build Manager Should Show Here", Description = "<b>Description:</b> Add Text Here. \n\n<b>Prerequisites:</b> Add Text Here.", },
Great job our build.lua is complete and it should look something like this.
Build.lua
Code:Ship = 0 SubSystem = 1 build = { { Type = Ship, ThingToBuild = "Kpr_AttackDroid", RequiredResearch = "", RequiredShipSubSystems = "", DisplayPriority = 60, DisplayedName = "Keeper Attackdroid", Description = "<b>Description:</b> Advanced Multi-Purpose Fighter. \n\n<b>Prerequisites:</b> None.", }, { Type = Ship, ThingToBuild = "Hgn_ResourceCollector", RequiredResearch = "", RequiredShipSubSystems = "", DisplayPriority = 120, DisplayedName = "$7066", Description = "$7067", }, { Type = Ship, ThingToBuild = "Hgn_ResourceController", RequiredResearch = "", RequiredShipSubSystems = "", DisplayPriority = 130, DisplayedName = "$7068", Description = "$7069", }, { Type = Ship, ThingToBuild = "Kpr_Destroyer", RequiredResearch = "", RequiredShipSubSystems = "", DisplayPriority = 116, DisplayedName = "Destroyer", Description = "<b>Description:</b> Multipurpose Light Destroyer and Build Capable Ship. \n\n<b>Prerequisites:</b> None.", }, { Type = Ship, ThingToBuild = "Kpr_Mover", RequiredResearch = "", RequiredShipSubSystems = "", DisplayPriority = 116, DisplayedName = "Mover", Description = "<b>Description:</b> Keeper Attack Corvette. \n\n<b>Prerequisites:</b> None.", }, { Type = Ship, ThingToBuild = "Kpr_Mover_Capture", RequiredResearch = "", RequiredShipSubSystems = "", DisplayPriority = 150, DisplayedName = "Infiltration Mover", Description = "<b>Description:</b> Keeper Infiltration Corvette. \n\n<b>Prerequisites:</b> None.", }, { Type = Ship, ThingToBuild = "Kpr_Sajuuk", RequiredResearch = "", RequiredShipSubSystems = "", DisplayPriority = 150, DisplayedName = "Sajuuk", Description = "<b>Description:</b> The Ultimate Battle Ship. \n\n<b>Prerequisites:</b> None.", }, }
Step 3: Adding the Keeper ships into the classdef.lua:
You should have downloaded Evillejedi’s ai and script files but if you haven’t you need them now. As soon as you get them open up the classdef.lua in the ai folder, now go through it and when ever you come to a class in which you ship fits nicely add it in. Remember to add commas after all of your ships.
The final result should look something like this.
Classdef.lua
Code:-- -- classdef.lua -- -- This file only contains ship classfication lists that allow the AI script writer to seperate each ship -- into different subclasses (fighters, corvettes, anti-fighter, fast, slow,...) This is done to make it easier -- (and faster) to refer to a ship based on its generalized properties. -- -- Custom classes can be added at the end but have to be added in a very specific way. -- aitrace("CPU: CLASSDEF LOADED") -- table of all squadron class lists squadclass = {} -- is mothership squadclass[eMotherShip] = { HGN_MOTHERSHIP, VGR_MOTHERSHIP, VGR_MOTHERSHIP_MAKAAN, } -- can harvest squadclass[eCollector] = { HGN_RESOURCECOLLECTOR, VGR_RESOURCECOLLECTOR, } -- is a good scout/explorer squadclass[eScout] = { HGN_SCOUT, HGN_SUPERSCOUT, HGN_PROBE, HGN_PROXIMITYSENSOR, HGN_ECMPROBE, VGR_SCOUT, VGR_PROBE, VGR_PROBE_PROX, VGR_PROBE_ECM, KPR_ATTACKDROID, } -- is a refinery squadclass[eRefinery] = { HGN_RESOURCECONTROLLER, VGR_RESOURCECONTROLLER, } -- can build ships squadclass[eBuilder] = { HGN_MOTHERSHIP, HGN_CARRIER, -- will need subsystem HGN_SHIPYARD, VGR_MOTHERSHIP, VGR_MOTHERSHIP_MAKAAN, VGR_CARRIER, -- will need subsystem VGR_SHIPYARD, KPR_BENTUS, KPR_DESTROYER, } -- can be used as a resource dropoff squadclass[eDropOff] = { HGN_MOTHERSHIP, HGN_CARRIER, -- will need subsystem HGN_SHIPYARD, HGN_RESOURCECONTROLLER, VGR_MOTHERSHIP, VGR_MOTHERSHIP_MAKAAN, VGR_CARRIER, -- will need subsystem VGR_SHIPYARD, VGR_RESOURCECONTROLLER, } -- can be used as a salvage dropoff squadclass[eSalvageDropOff] = { HGN_MOTHERSHIP, HGN_CARRIER, HGN_SHIPYARD, VGR_MOTHERSHIP, VGR_MOTHERSHIP_MAKAAN, VGR_CARRIER, VGR_SHIPYARD, } -- is a fighter squadclass[eFighter] = { HGN_INTERCEPTOR, HGN_ATTACKBOMBER, HGN_ATTACKBOMBERELITE, VGR_INTERCEPTOR, VGR_BOMBER, VGR_LANCEFIGHTER, KPR_ATTACKDROID, } -- is a corvette squadclass[eCorvette] = { HGN_ASSAULTCORVETTE, HGN_PULSARCORVETTE, HGN_MINELAYERCORVETTE, VGR_MISSILECORVETTE, VGR_LASERCORVETTE, VGR_MINELAYERCORVETTE, VGR_COMMANDCORVETTE, KPR_MOVER, } -- is a frigate squadclass[eFrigate] = { HGN_ASSAULTFRIGATE, HGN_DEFENSEFIELDFRIGATE, HGN_IONCANNONFRIGATE, HGN_MARINEFRIGATE, HGN_MARINEFRIGATE_SOBAN, HGN_TORPEDOFRIGATE, HGN_TORPEDOFRIGATEELITE, VGR_ASSAULTFRIGATE, VGR_HEAVYMISSILEFRIGATE, VGR_INFILTRATORFRIGATE, } -- can capture other ships squadclass[eCapture] = { HGN_MARINEFRIGATE, HGN_MARINEFRIGATE_SOBAN, VGR_INFILTRATORFRIGATE, KPR_MOVER_CAPTURE, } -- has shields squadclass[eShield] = { HGN_DEFENSEFIELDFRIGATE, } -- is a platform squadclass[ePlatform] = { HGN_GUNTURRET, HGN_IONTURRET, VGR_WEAPONPLATFORM_GUN, VGR_WEAPONPLATFORM_MISSILE, VGR_HYPERSPACE_PLATFORM, } -- good at attacking fighters squadclass[eAntiFighter] = { HGN_INTERCEPTOR, HGN_ASSAULTCORVETTE, HGN_ASSAULTFRIGATE, HGN_GUNTURRET, VGR_INTERCEPTOR, VGR_ASSAULTFRIGATE, VGR_WEAPONPLATFORM_GUN, KPR_ATTACKDROID, } -- good at killing corvettes squadclass[eAntiCorvette] = { HGN_PULSARCORVETTE, HGN_TORPEDOFRIGATE, HGN_TORPEDOFRIGATEELITE, HGN_DESTROYER, VGR_LANCEFIGHTER, VGR_LAZERCORVETTE, VGR_DESTROYER, KPR_MOVER, } -- good at killing frigates squadclass[eAntiFrigate] = { HGN_IONTURRET, HGN_ATTACKBOMBER, HGN_ATTACKBOMBERELITE, HGN_IONCANNONFRIGATE, HGN_MARINEFRIGATE, HGN_MARINEFRIGATE_SOBAN, HGN_DEFENSEFIELDFRIGATE, HGN_DESTROYER, HGN_BATTLECRUISER, VGR_BOMBER, VGR_HEAVYMISSILEFRIGATE, VGR_INFILTRATORFRIGATE, VGR_DESTROYER, VGR_BATTLECRUISER, VGR_WEAPONPLATFORM_MISSILE, KPR_DESTROYER, } -- is a capital ship squadclass[eCapital] = { HGN_CARRIER, HGN_MOTHERSHIP, HGN_SHIPYARD, HGN_DESTROYER, HGN_BATTLECRUISER, HGN_DREADNAUGHT, VGR_CARRIER, VGR_MOTHERSHIP, VGR_MOTHERSHIP_MAKAAN, VGR_SHIPYARD, VGR_DESTROYER, VGR_BATTLECRUISER, KPR_DESTROYER, KPR_SAJUUK, } -- eCollector + eScout (maybe refineries - but those things are pretty tough?) -- this is currently only used to count the number of 'military units' the player/enemy has squadclass[eNonThreat] = { HGN_RESOURCECOLLECTOR, VGR_RESOURCECOLLECTOR, HGN_RESOURCECONTROLLER, VGR_RESOURCECONTROLLER, HGN_CARRIER, HGN_MOTHERSHIP, HGN_SHIPYARD, VGR_CARRIER, VGR_MOTHERSHIP, VGR_MOTHERSHIP_MAKAAN, VGR_SHIPYARD, KPR_BENTUS, HGN_SCOUT, HGN_SUPERSCOUT, HGN_PROBE, HGN_PROXIMITYSENSOR, HGN_ECMPROBE, VGR_SCOUT, VGR_PROBE, VGR_PROBE_PROX, VGR_PROBE_ECM, VGR_HYPERSPACE_PLATFORM, } -- is a hyperspace gate squadclass[eHyperspaceGate] = { VGR_HYPERSPACE_PLATFORM } -- good at killing subsystems squadclass[eSubSystemAttackers] = { HGN_ATTACKBOMBER, HGN_ATTACKBOMBERELITE, VGR_BOMBER, } -- non critical subsystems squadclass[eNonCriticalSubSys] = { CLOAKGENERATOR, FIRECONTROLTOWER, HYPERSPACEINHIBITOR, ADVANCEDARRAY, CLOAKSENSOR } -- good at killing repairing collectors squadclass[eGoodRepairAttackers] = { HGN_INTERCEPTOR, HGN_ASSAULTFRIGATE, HGN_IONCANNONFRIGATE, HGN_DESTROYER, HGN_BATTLECRUISER, VGR_INTERCEPTOR, VGR_MISSILECORVETTE, VGR_ASSAULTFRIGATE, VGR_DESTROYER, VGR_BATTLECRUISER, } ------------------------------------------- -- CUSTOM classes -- do not exceed eMaxUserCount(32) eUselessShips = eMaxCount eBattleCruiser = eMaxCount + 1 -- this number should be one greater then the highest class sg_maxClasses = eBattleCruiser+1 -- ships that the AI should not build because they are not used properly squadclass[ eUselessShips ] = { HGN_MINELAYERCORVETTE, VGR_MINELAYERCORVETTE, VGR_COMMANDCORVETTE, } -- is a battlecruiser squadclass[eBattleCruiser] = { HGN_BATTLECRUISER, VGR_BATTLECRUISER, KPR_SAJUUK, } -- -- FUNCTIONS TO ADD SQUADRON TYPES TO CLASS SYSTEM -- function FastAddToClass( tbl, classid ) for a,b in tbl do AddToClass( b, classid ) end end function ClassInitialize() for i=0, sg_maxClasses do if (squadclass[i]) then FastAddToClass( squadclass[i], i ) end end -- debug: name all the classes to be displayed on screen AddClassName( eMotherShip, "Motherships") AddClassName( eCollector, "Collectors") AddClassName( eDropOff, "DropOffs") AddClassName( eFighter, "Fighters") AddClassName( eFrigate, "Frigates") AddClassName( eCorvette, "Corvettes") AddClassName( eCapital, "Capital") AddClassName( eAntiFighter, "AntiFighter") AddClassName( eAntiCorvette, "AntiCorvette") AddClassName( eAntiFrigate, "AntiFrigate") AddClassName( ePlatform, "Platform") AddClassName( eRefinery, "Refinery") AddClassName( eHyperspaceGate, "HypGates") AddClassName( eShield, "Shields") AddClassName( eCapture, "Capture") AddClassName( eSubSystemAttackers, "SubSysKillas") AddClassName( eBattleCruiser, "BattleCruiser") end
Step 4: Adding Keeper into the AI.
Last but not least we need to work on the cpubuild.lua. Again this is the file Eviljedi’s that I asked you to download.
Were about done open up cpubuild.lua and take a look over it. Looks pretty scary doesn’t it? Luckily you only have to add a few lines in function CreateBuildDefinitions.
Now delete function CreateBuildDefinitions() including the end on the same indention level near the bottom.
Now where that function used to be add in this block of text.
You should notice we have a lot of ships being used for many different roles. So your next job is to make variants of the usable Keeper ships then add them in here. However, that can wait run your mod and watch as the Keeper race builds ships.Code:function CreateBuildDefinitions() if (s_race == Race_Hiigaran) then kCollector = HGN_RESOURCECOLLECTOR kRefinery = HGN_RESOURCECONTROLLER kScout = HGN_SCOUT kInterceptor = HGN_INTERCEPTOR kBomber = HGN_ATTACKBOMBER kCarrier = HGN_CARRIER kShipYard = HGN_SHIPYARD kDestroyer = HGN_DESTROYER kBattleCruiser = HGN_BATTLECRUISER elseif (s_race == Race_Vaygr) then kCollector = VGR_RESOURCECOLLECTOR kRefinery = VGR_RESOURCECONTROLLER kScout = VGR_SCOUT kInterceptor = VGR_INTERCEPTOR kBomber = VGR_BOMBER kCarrier = VGR_CARRIER kShipYard = VGR_SHIPYARD kDestroyer = VGR_DESTROYER kBattleCruiser = VGR_BATTLECRUISER else kCollector = HGN_RESOURCECOLLECTOR kRefinery = HGN_RESOURCECONTROLLER kScout = KPR_ATTACKDROID kInterceptor = KPR_ATTACKDROID kBomber = KPR_MOVER kCarrier = KPR_DESTROYER kShipYard = KPR_DESTROYER kDestroyer = KPR_DESTROYER kBattleCruiser = KPR_DESTROYER end end
Any suggestions or comments are very welcome, as are cries for help.![]()



















.


Can some body help me? i carn't get the overide big file thing to work. i start form the short cut and i just quits stright to the desktop. is like a frigt with a computer.:fight:
ing because I updated it. Did I miscount again somewhere?

)
