Starpoint Gemini 2

Starpoint Gemini 2

63 ratings
[WIP] The Basics of Modding
By MrHellhound1
A guide on how to modify and alter Starpoint Gemini 2 (Alpha)
   
Award
Favorite
Favorited
Unfavorite
Introduction
Welcome all to my guide on modding. It's a learning process for everyone, even me, and so I'll be adding bits and peices to this guide as I learn more myself.

/*DISCLAIMER*/
This guide is very long. I have no idea how long it will take you to complete it. I sometimes forget to spell. Because of the alpha state of this game, things might go wrong.If you follow this guide, you shouldn't mess too much up. You should always back up all your files first though. You should always undo the changes made when you're not using them.
If anything does go wrong, you can use the Steam "Verify Integrity Of Game Cache" option to reset your game to default.
/*EndDisclaimer*/

About Me

I'm Hellhound1.

I have a website.
http://www.hellhound1.com

I'm a sort-of programmer. I have programmed some stuff. I have been scripting for a few years. My first ever released script now has just under 60 thousand downloads. I have been modding games for quite a few years. Some of the stuff i have worked on:
RS2 (RTW Mod)
MERP (Oblivion/Skyrim Mod)
Kenshi (I have both modded for Kenshi, and I programmed Kenshi Mod Manager)
Mount and Blade Warband
Fallout New Vegas
Skyrim (my own stuff)
Oblivion (my own stuff)
Shogun 2 (I created the second ever custom map :D )
The X series (specifically X3:R and X3:AP)
A few other things but nothing else of note.

These are my credentials, hopefully you'll trust that i kind of know what I'm doing.
(I don't)

Modding
Modding allows the user the possibility to create anything, from something as small as a new type of food, to as large as a whole new galaxy, with new factions, ships, planets and stories.

Because SPG2 is in Alpha, a lot may be added/changed/removed, so this isn't (yet) the definitive guide. But it should teach you enough to allow you to start creating yourself.

Tools
You'll need, at the simplist, notepad.

If you want to do this properly, I suggest Notepad++

The lovely developers of this game have a modding section to their website, with an overlay of the basic functions and scripting techniques you'll need. They also have a custom plugin for Notepad++ that will autocomplete words and recognize scripting functions. I highly reccomend you download and use it.

Official Modding Website[modding.starpointgemini.com]
Chapter 0 - Setting Up and Safe Modding Practices
Rather than messing with people's main files, we can use the "Mods" folder to store our mods so that the game loads them with any danger to editing a player's files.

This is really easy to set up.

First, you should go to the "Mods" folder, and create a new Folder. Call it whatever you want. For the rest of this guide, I will call mine "MyMod", and will automatically refer to it as such.

You should then Copy "NewGame.sgs" from SPG2/NewGame to the "Mods" folder (NOT Mods/MyMod)

Rename it to the same name as your mod folder. You should now have a file called MyMod.sgs, and a folder called MyMod

Open MyMod.sgs. You need to INSERT a line of code.

Underneath the "txt" bit at the top, you need to add
FileBypass: Spg2 Mods\MyMod
This tells the game to use the files inside "MyMod" over the game's original files.

It should look like this:
txt FileBypass: Spg2 Mods\MyMod Version: 1000

From now on, if you want to create or edit a file, create the exact same location inside your MyMod folder, and paste or create your file there.

Remember, any mod file will overwrite the main game file, so if you're editing a main script created by the devs, you'll need to copy the WHOLE script over, otherwise it will be ignored for your script and that could crash the game.

To load a mod into the game (at the moment you can only have 1 at a time!) open "StarpointGemini2Configuration.cfg" in the root folder and change the StartScene. For example:

StartScene: Mods\MyMod.sgs

You're now ready to create and play your mod!
Chapter 1 - The Filesystem
The Filesystem

SPG2 is mainly text file driven. Which is great for modding, because we can tweak and alter almost anything.

Inside your main Starpoint Gemini 2 folder is another folder, simply called "SPG2", and this is where the magic takes place.


Exploring the Filesystem

Before we start creating, we should get familiar with the Filesystem, what is inside each folder and how they relate to the game.

We'll start at the top and work our way down.
(If I miss one, its because it's either not important or I'm not sure)

Ambients
This folder contains the script files for the sky. Or in this case, the space beyond the game (all the stars in the distance).


These are configuration files that the game reads to set up and display the skybox. They point to where the textures for the skybox are kept, and how the game engine should display these textures to the player.


Base
This folder is one of the most important folders. It contains "databases" for the configuration and set up of just about everything in the game. For example, ships.wdt contains a list of every ship, its model, its price, its icon, and a bunch more stuff.


I'll go into depth about this folder in a later chapter.


Dialogues
This folder contains every piece of written dialogue for missions.


Each folder relates to a mission, and contains the dialogue files for each option. Again, Ill go over this folder later, and make some comments on how this could be done better.


Models
This folder contains every model for every item in the game, as well as most scripts for each item (for example - the ships folder contains the ship models, and the scripts that control how a ship explodes)


If you're looking to edit the ships, stations etc then this is where you'll be!


NewGame
This folder contains the information that controls a new game for the player.


It's one of the easiest mods to make, so we'll start there in the next chapter.


Panels
This folder contains the config files for the panels you see in the game, with the information on.


I've yet to use this folder.


Scripts
This folder contains all the scripts used in the missions, and probably more as the game progresses.


For some reason, the devs chose to place the end dialogue scripts in with these scripts, rather than the dialogue folder :/ I see why, but still...


Sound
This is where the sound files are kept.


SpecialEffect
This is where the scripts and textures relating to special effects are kept.


That includes things like Explosions, TDrive effects, shield hit effects..


Texts
This is where every piece of text is stored. It includes log messages, conversations, descriptions of items. All items start at 0, so the first line of the file has an ID of 0



Textures
This is where the textures are kept, excluding ships and stations.



Weapons
This is the folder responsible for the configuration of weapons. It lists each weapon, and has some config files for the game to read, as well as some custom scripts for certain weapons.



World
This folder contains the config files for each region, sector, and the galaxy as a whole.


So thats a quick overview of the file system. In the next few chapters I'll go into them in more depth, to show you what each folder lets you change.


Chapter 2 - A Simple Mod (Part 1)
So, we'll start our first mod!

The Plan
The plan for this mod is to give the player a stupid amount of money when they start a new game. Simples.


How To Do It
Open your Mods folder, and head to MyMod.sgs (The name of the file we created in Chapter 0)

Lets take a look inside. Assuming you have Notepad++ installed (and i will assume this!), right click and select edit with Notepad++.

Your file will look the same as this:


Lets run through each option.

The first line is just "txt". Its there to let the game know that this is a text file, not a database file. When creating your own versions of these, it's important to have this line first.

The second line is the bypass line so the game knows which mod we're using.

The third line is "version". As of yet, it's not important, so leave it as is.

Line 4 is the description. This is a brief overview of the new start. One thing you'll notice is that there are NO SPACES! The game engine doesnt use spaces. Instead, it uses _ as a space.

Now start the declarations.
World: { CurrentSector: 0 }

This doesn't actually have any noticeable effect on the game. Rather, it forces the game to start loading at sector 0.

Notice how each section starts with an Object (in this case "world:") then opens and closes with { and }

Camera: { CameraSort: 0 Distance: 28.00 }

This sets up the starting camera. CameraSort is the "type" of camera used e.g turret view, freeview.
"Distance" is how far away the camera is from the ship.

Player: { Name: Adrian_Faulkner Skills: 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Credits: 15000 Experience: 0 Reputation: 1750

This code inializes the player. Up to now, the "name" is hard coded, so doesn't change in game no matter what you change it to.

"Skills:" sets up the points the player starts with in each catagory. I will go into this more later on, but each number is linked to a skill, as defined in "SPG2/Base/Skills.wdt"

"Credits:" defines how many credits the player starts with

"Experience:" defines how much experience the player starts with

"reputation:" defines the players global rep. If you want them to start as a pirate, set it to a minus number. I'll go over reputation later on.

For this little mod, we just want to change the credits. So go ahead, add a couple of zeros onto the end of the credits number. And another one. And another. You know, I'm feeling a bit crazy today, so add yet another one!

When you're bored of adding zeros, save this file, start the game, and select "New Game". Look how rich you are!
Chapter 2 - A Simple Mod (Part 2)
Now that you're bored of all that money, you're back to learn some more! Woohoo! My plan here is to go indepth, so that you've always got somewhere to come back to if you want more info on some particular files. Also, because I dont wanna go over this again :P

Lets continue where we left off, so open MyMod.sgs back up, and lets continue.

Ship: { Id: 25 Position: 28860.88 691.17 69655.13 Orientation: -0.26 -3.02 0.15 Rotation: -0.90 0.00 0.44 0.00 -0.02 1.01 -0.07 0.00 -0.43 -0.06 -0.90 0.00 0.00 0.00 0.00 1.00 Name: Myrmidon Hull: 1500.00 PowerToEngines: 1

Ok, so thats quite a large bit of code, but lets work through it again.

"Ship:" tells the engine the follow bit of code is setting up a ship.

"ID:" is the ID of the ship, as defined in "SPG2/Base/Ships.wdt"

(from here on, ill just refer to these base files as "database files")

"Position:" is the exact location of the ship. I'd like to point out here that the devs placed all this using the World Editor, which is what we'll get at some point, so I wouldnt worry too much about their accuracy at placing ships!

"Orientation" is the direction the ship starts at. If they're all 0, then the ship is pointing to 0 degrees.

"Rotaion:" is the angle the ship starts at. Theres a lot of numbers, and without the world editor im not sure what they're all there for. It's safe to have them all at 0.

"Name:" You can name your ship here. Woo.

"Hull:" Is how much hull your ship starts with.

"PowerToEngines:" is the percentage of power going to your ship's engines.

Keeping up so far? Good.




Chapter 2 - A Simple Mod (Part 3)
I hope you realise im trying to be very thorough here. Theres nothing worse than being told to do something, but not know how or why you're doing it.

So we're going to mod some more now. We're going to turn OFF the FOW (Fog Of War). This means that when a player starts a new game, a sector, or all sectors, will be viewable.

Sectors: { SectorsNo: 340

This initiates the sectors part of this setup file. (it's about half way down!)
There are 340 sectors in game. Probably going to be a hardcoded amount. Thats 0 - 339 inclusive.

Sector: { Id: 0 FOW: 1 }

For each sector, you have this basic initialisation code.

"ID:" is the unique ID of the sector
"FOW:" is whether or not Fog Of War is turned on or off.

For this mod, we want to turn it off.

From this, we can gather that having it set to "1" means it on. Setting it to "0" will turn it off.

Try it now, by changing sector 0's FOW to off. Save the file, start a new game, and notice down the bottom left of the map you can see the uncovered sector.

Using the "replace" function in Notepad++, you can have it automatically change "FOW: 1" to "FOW 0". Notice that they're tabs, not spaces, between the variable name and the value.

If you do this for every sector, save the file and start a new game, you'll notice you can now see the whole map. Congratulations :)
Chapter 3 - Bases (Part 1)
Databases. Awesome!

Here's a refresher of the Base folder.

Yes, the bases folder contains the databases for the the game. Each file inside is used, for example, as reference for setting up unique IDs for each object in the game, or creating a list the game uses.

It ties in very closely with the next chapter - Scripting, so we'll take an indepth look at each file and how it relates to the game.

Base.wdb
Those of you with eagle eye vision will notice the unique extension of this file, which is why i've started with it. It contains a list of every other database file the game uses. If you create your own custom one, you must add it to this list for the game to read it.

Accidents.wdt
Contains a list of each type of possible accident in game.

Id Name 0 Engine_malfunction

Notice, how the top of the file defines how many columns are in the file. Also notice how there is no "txt" at the top. This is how the game knows the type of info in the file. Be wary of this.

Achievements.wdt
Contains the list of unlockable steam achievments.

Alignment.wdt
Defines the types of alignments possible in the game.

Colum: 2 Id Name 0 Hostile 1 Neutral 2 Allied


AreaEffects.wdt
Defines the types of areas effects you can have.

Id Name 0 Radiation 1 EMP_field 2 Ion_storm


Beams.wdt
Defines how beams will look in the game.


Bonuses.wdr
This is a tricky one.

Id DescriptLine Filter 0 396 0 1 397 0 2 398 0 3 399 0 4 400 0

The ID is the unique id of the bonus.
I'm pretty sure that DescriptLine defines which line in SPG2/Texts/Descriptions.txt the game refers to for the bonus.
I'm yet to discover what the filter is or does. It's 0 all the way down so it's hard to tell.


Cloak.wdt
A list of all the possible upgrades to your ship's cloak in game.


CombatAI.wdt
Refers to the types of AI that the game can handle. I'm pretty sure it's not yet implemented.


Commoditites.wdt
Refers to each purchasable or collectable item in the game, defines its price etc.


CommodityType.wdt
Refers to each type a commodity can fall under.


Debris.wdt
Sets up each different type of debris.


EditorAnomalies.wdt
Sets up each type of anomoly in game.


EditorAsteroids
Sets up each type of asteroid in the game


EditorDerelicts.wdt
Sets up each type of derelict structure in the game


EditorJunkyard.wdt
Sets up the junkyards in the game


EditorNebulas
Sets up the types of nebulas in the game


EditorPlanets
Defines each planet in the game.


EditorPlatforms.wdt
Defines each Platform in the game e.g Prisons, hangars


EditorScenery
Sets up each type of possible scenery in the game


EditorStations.wdt
Defines each type of station in the game.


EditorStructures.wdt
Defines each type of structure.


Encounters.wdt
Sets up each different type of encounter you'll find in game.


EnhancementType.wdt
Sets up each type of enhancement.


Events.wdt
Defines each type of global event in the game.


Experience.wdt
I think this file sets at how much experience you'll level up at.


Explosion.wdt
Sets up the files for each type of explosion.


FactionAlign.wdt
This is a table for each faction and sets up which faction likes (1) and dislikes (0) eachother. You need to see this file for yourself to understand. The IDs run down the side and along the top. The value of 2 defines an empty square.


Faction.wdt
Defines each faction in the game

Id Name Type HostileA HostileB NeutralA NeutralB AlliedA AlliedB

Name: Name of the faction
Type: Type of faction as defined in FactionType.wdt
HostileA: The minimum value at which a faction hates you.
HostileB: The maximum value at which a faction hates you.
NeutralA: The minimum value at which a faction is neutral towards you.
NeutralB: The maximum value at which a faction is neutral towards you.
AlliedA: The minimum value at which a faction is allied with you.
AlliedB: The maximum value at which a faction is alled with you.

Let's look at some examples:
0 Iolian_pact 0 -2500 -251 -250 1900 1901 2500
This is a fairly standard faction. If your reputation is anywhere from -2500 to -251, the faction won't like you.
If your reputation is between -250 and 1900, the faction will be neutral towards you.
If your reputation is between 1901 and 2500 then the faction will be allied towards you.

Notice how you can't miss any numbers. It must be a full range.

Let's take a look at another faction:
2 Nyxian_Consortium 0 -2500 2500 2501 2502 2503 2504
These guys will always hate you. They will be your enemies no matter what your reputation is. (your rep can't exceed -2500, 2500). However, we must give a value for each column. So, we use the next number along as a place holder.

Another one:
9 Niners 2 2500 51 50 -2300 -2301 -2500
Notice how this one is backwards?
So if you have a positive rep, they won't like you.
Anything 50 and below, they'll be neutral.
If you become really hated, then they'll be your allies.


FactionType.wdt
This defines the types that a faction can be.


Fighters.wdt
I think these are the purchasable fighters you can have to fight along side you.


FreeModels.wdt
This contains a misc collection of meshes for special effects.


GlobalObject.wdt
Defines all the global objects in the game, such as stations, hangers etc.
What is really important is the "KeyName". This is how you refer to certain objects through scripts.


Grappler.wdt
A list of upgrades possible for the grappler in game.


Hangar.wdt
I think these are the purchasable upgrades for your ship's hangar.


HeavyWeapons.wdt
These define all the heavy weapons in the game, their names, their damage files, prices etc.


HeavyWEnhancements.wdt
This defines all the purchaseable enhancements for heavy weapons in the game.


Items.wdt
This defines all the purchasable upgrades for your ship.


Licences.wdt
Contains a list of every obtainable licence in game. Gotta collect 'em all!


LightWeapons.wdt
These define all the light weapons in the game, their names, their damage files, prices etc.


HeavyWEnhancements.wdt
This defines all the purchaseable enhancements for light weapons in the game.


Logs.wdt
I think this has something to do with matching up logs to missions to markers. It's hard to tell because this part isn't fully open yet.


LootDrop.wdt
Not yet implemented.


ModelSpecialEffect.wdt
I think this links models to special effects.


News.wdt
I think this is yet to be implemented and will link in between getting news and waypoints.


OfficerClass.wdt
Defines the different types of officers.


Officers.wdt
Contains all the information on the officers in game.


Options.wdt
Contains a list of the options in the game. I wouldn't reccomend editing this file.


Particles.wdt
Contains info on the set up of particles in the game.


Perks.wdt
Contains a list of the possible perks in the game


Portraits.wdt
Contains a list of portraits for the game.


PowerCore.wdt
Contains a list of purchasable upgrades for the power core of your ship.


Professions.wdt
Contains a list of possible professions (I think just for the AI)


Propulsion.wdt
Contains a list of upgrades for your ship's engines.


QuestItems.wdt
Contains a list of collectable items for quests.

Chapter 3 - Bases (Part 2)
So i err.. ran out of space. Onwards!

QuestMain.wdt

Id Main Parent StartScr EndScr Waypoint 1 1 1 Spg2\Scripts\M01\MainQuest01Start.sal - m01marker

This is where you set up quests with their scripts. You can see here that each quest is linked to a start scripts and an optional end script. We'll go into those later.


QuestSide.wdt
Much the same as above, just for side quests.


RandomMission.wdt
A list of random missions in the game


Rank.wdt
A list of ranks in the game. Not sure if they're just for the AI or the player as well.


Region.wdt
A list of the regions in the game.


RndCaptianNames.wdt
A list of random captain names. Go ahead, add yours in ;)


RndShipNames.wdt
A list of random ship names.
Nothing too rude please!


Sectors.wdt
A list that links sectors to regions by SectorID

Id RegionId 0 53 1 53 2 53 3 53 4 52 5 57 6 57 7 57 8 58 9 58 10 58


Sensors.wdt
A list of possible upgrades for the sensors on your ship.


Shields.wdt
A list of possible upgrades to your shields.


ShipClass.wdt
A list of the types of ships in the game

Id Name Rank 0 Fighter 0 1 Freighter 2 2 Freightliner 5 3 Gunship 0 4 Corvette 1 5 Frigate 2 6 Destroyer 4 7 Cruiser 5 8 Battleship 6 9 Dreadnought 7 10 Carrier 8

"Rank" i think is the rank you need to be to purchase or the rank the AI is when they spawn them.


Ships.wdt
A list of every ship in the game. It includes it's model file, price, icon etc.

Id Name ShipFile IconFile IconId Price IconSmallFile IconX IconY IconW IconH SchemT SchemL 0 Pegasus Spg2\Models\Ships\Pegasus\pegasus.shp Spg2\Textures\GUI\shipIcons.dds 0 343580 Spg2\Icons\ShipIconsSmall.dds 0 52 0 52 Spg2\Models\Ships\Pegasus\schemT.dds Spg2\Models\Ships\Pegasus\schemL.dds
(A bit tricky, it's best looking at the file yourself)


ShipSystemType.wdt
The type of systems on board a ship.

Id Name BaseId IconFile IconColumn PriceColumn NameColumn 0 Light_weapon 11 18 19 4 1 1 Heavy_weapon 8 4 4 5 1 2 Fighter 32 3 4 4 1


SkillClasses.wdt
I think it's the ranks you can have for each skill.

Id Name 0 Commander 1 Engineer 2 Gunner


SkillModifiers.wdt
A list of upgrades possible for each skill

Id Name Skill BonusId Lvl1 Lvl2 Lvl3 Lvl4 Lvl5 0 Fleet_leader 0 58 20 15 10 5 2

Notice here you have BonusID?
That links in with Bonuses.wdt from earlier.


Skills.wdt
A list of the possible skills in the game


Sound.wdt
Links each sound to an id.


SoundType.wdt
A list of the types of sound in game


Stations.wdt
A list of station types in the game


Statistics.wdt
I'm not sure if this file is actually written to by the game. It has a list of all actions in the game, and looks like it counts how often you've done them. A very useful tool.


StructureSort.wdt
Breaks down each type of structure.


Transporter.wdt
A list of possible upgrades for the troop transporter.


Triggers.wdt
A list of the types of triggers.


Turrets.wdt
A list linking all turrets to their mesh files.


Waypoints.wdt
A list of the waypoint types.



Phew. Thats a long list. I very highly recommend you look at each file and take the time to learn what's in it. You'll be refering to these files by keynames and IDs, so its very important you know what you're linking to!
Chapter 4 - Scripting (Part 1)
This is the core of game modding. If you really want to develop more than just little cheats, you'll need to learn how to script.

Scripting is the act of using built in functions to manipulate the game data.

Before we start, here is a list of warnings, things to remember, before we begin.

1) Scripts are saved as *.sal (Script Assembly Language) files
2) Declaring a variable before using it is highly advised
3) SPG scripts aren't compiled, they are run as is
4) Each segment of a declaration (variables, functions, keywords etc.) is separated by either space or tab
5) Each declaration ends in a semicolon [ ; ] (also preceeded by a space or tab)

So what do they mean?

Each script file must end in .sal NOT .txt. You can change this simply by just renaming the file or saving it again with the extension changed.

"Declaring a variable" means telling the game engine that a variable exists. A variable is a point we use to store certain data. For example, I could have the variable "X" store the value of 1. I could then have the variable "Y" store the value of 2.

X + Y = 3
(1 + 2 = 3)

Even better, I could, using the same variables, do this:

X + Y = Z Z = 3

"scripts arent compiled" basically means that the script is run by the game without checking it first. This means if theres any errors the game won't know until it runs into these errors. This is both good and bad. We just have to be careful is all.

We must seperate a variable and it's value by a space or tab.

The end of each line of our script (excluding IF statements) must end with a semi colon ;

The same rules about no spaces still applies.

Let's quickly look at an example script:

/* START anomaly randomization */ int A = 1 ; int B = 4 ; int C = 1 ; math C = Rnd A B ; if C == 1 anomaly GetByKeyName ANO_0_0 SetEnabled 1 ; endif

Ok, that's a lot to take in. But, lets start slowly.

The first line is a comment. It isn't run by the engine, but is instead there to remind the developer what this script is doing, and to help potential modders like us.

Notice those "int"? Thats how you "declare" a variable. In this case, we have declared the variables A, B and C, and given them a value of 1, 4, and 1.

"math C = Rnd A B ;" - this looks complicated, but it isnt.
"math" is telling the game engine that this is a mathematical equation to work out.
"Rnd" is the function we use to calculate a random number between two values.
The two values here are A (1) and B (4).
So now we know that we're asking the game engine this question:
Choose a number between the value of the variable A, and the value of the variable B, and give it to C.

"C" now has a value of somewhere between 1 and 4.

Before we go any further, we need to laern the "IF" statement.
We can use this to determine IF a variable has a certain value.
An if statement basically says this:
If "X" = "Y" "DoSomething" Else "Don'tDoSomething" EndIf

Hopefully, you now understand what the IF statement in the code is saying.
(An IF must always be followed by an ENDIF.)

If the value of C is equal to 1 "DoThis" EndIf

So, let's assume the value of C in the script is randomly chosen as 1.
We then execute the code inside the statement:
anomaly GetByKeyName ANO_0_0 SetEnabled 1 ;

Now, each script is linked to an "object". In this game, an object can be "player" (the player), "ship" (the ship), and a whole bunch of other things. In this example, it's an anomaly. The game now knows that we're asking it to perform the action on an anomaly.

GetByKeyName
I've mentioned this earlier. KeyNames are unique names given to objects so that the game knows where they are. This objects are usually static, like stations or, in this case, anomalies.

The key name in this example is:
ANO_0_0
(The key name for an anomaly is defined by each sector, which you can find in spg2/world/sectors)
The devs have kindly used a handy naming system here. We can tell from the name that this is an anomaly from Sector0, and it's the first anomaly (ID0)

So the game now knows we want an Anomaly called ANO_0_0.

"SetEnabled" is a "Function". Functions allow us to control and manipulate the game. There is a list of functions here[modding.starpointgemini.com].

SetEnabled allows us to "Activate or deactivate an object" and "Can be set either to 0(disabled) or 1(enabled)".

Can you understand the script now?

The value of C = a random number between A and B If the value of C = 1 Enable the anomaly "ANO_0_0" endif.


(I apologise if you already know this, this guide is user friendly and should help everyone get into modding.)
Chapter 4 - Scripting (Part 2)
We're now going to edit a script, just for a bit of fun.

Head to SPG2/Scripts/Sectors/EnterSector184.sal
Copy it to Mods/MyMod/Scripts/Sectors

You'll need to have your Mod set up as explained in Chapter 0 before any of this will work. Remember you must only edit the files that you paste to your Mod folder, and never modify the original base files.

I've chosen this sector because it's the sector you start in.

Open up the pasted file.

You'll notice here is the anomaly randomization script from earlier. This script is used in each sector so you get a feeling of difference each time you enter a sector.

You'll notice at the end of the file we have this code:

/* END derelict randomization */ End

We're going to insert some code between these two lines.

Very simply, we're going to write a message to the game log. This is a great way to check whether or not your script is working.

The function for writing a message is
PrintMessage

So we want to add to our code this:
PrintMessage Sector_184_Entered_This_Is_A_Message ;

Notice here how there are no spaces, and notice the ; at the end of the line.

You code should look similar to this now:
/* END derelict randomization */ PrintMessage Sector_184_Entered_This_Is_A_Message ; End

Go ahead, start up the game, fly out of the sector, then fly back in again. You then need to open log.txt, in the main folder of the game. Near the bottom you should have something similar to this:


Woo. Your first script edit.

Let me deviate quickly to explain HOW this was called, in case you're wondering.

In SPG2/World/Sectors there is a sector_#.ics file for each sector. This "defines" the layout of the sector. At the bottom of the file, there is an "events" section.

Events are things that can take place given certain parameters. In each file, there is this code:

Events: { OnEnterScriptId: Spg2\Scripts\Sectors\EnterSector184.sal }

So, in this case, each time you enter a sector "OnEnterScriptID" is called. Using the mod overwrite system, that's the script we just edited. Hopefully, it's starting to come together a bit more now.


Chapter 4 - Scripting (Part 3)
Now we're going to use some more functions and practice with them.

A few things to quickly point out when declaring variables. "Int" is short for Integer - a whole number "float" is short for floating point - a decimal number "float3" is short for a series of 3 floating points - an XYZ position. We don't declare strings.

To start, create a folder inside your Mods/MyMod/Scripts folder. Call it "CustomScripts".

Inside, create a file called "MyScript.sal". It's very important here that you make sure the extension on the file is ".sal"

Open it up.

What we're going to do is, each time the player enters sector 184, have our script write to log.txt with some information on the player. The first thing we want to do is decide what information we want to write to the file.

This is tied up with the "Get" functions found here[modding.starpointgemini.com]

The ones we'll use in this script are:
GetCommoditiesCount
GetCredits
GetExp
GetHP
GetPosition
GetReputation

Lets take a deeper look at these functions first:


GetCommoditiesCount
int commodityId = 15 ;[->commodities.wdt] int howMuch = 0 ; player GetCommoditiesCount commodityId howMuch ;

We have two items to declare here, commodityId and howMuch. CommodityId automagically links in with commodities.wdt (yay its all coming together!). howMuch is a count for that will be updated with the amount of commoditites the player has of the commodity with the ID 15.


GetCredits
int credits = 0 ; player GetCredits credits ;

Just need to declare credits in this one.


GetExp
int exp = 0 ; player GetExp exp ;

Just need to declare exp in this one


GetHP
float shipHP = 0.0 ; ship GetByKeyName ship0 GetHP shipHP ;

We use "float" here instead of "int" because health doesn't have to be a round number. It can be 1.5 instead of just 1.


GetPosition
float3 position ; ship GetByKeyName ship0 GetPosition position ; ship GetPlayer GetPosition position ;

We use "float3" here because there are 3 positions the ship has at any one time. You have the X axis, the Y axis AND the Z axis.


GetReputation
int rep = 0 ; player GetReputation rep ;

Just need to declare "rep" here.

Note that you don't HAVE to use those names for the variables, you can use any name you want UNLESS you're linking to a database file (like commodityId).

Ok, thats a quick look at the functions and how they work.

Let's put them into practice! We need to first declare all the variables for the functions. So add them all in.

int commodityId = 0 ; int howMuch = 0 ; int credits = 0 ; int exp = 0 ; float shipHP = 0.0 ; float3 position ; int rep ;

Your code should look similar to that. You should set commodityId to be 0, because we're going to work through loops as well.

Another function we need to learn to use is "PrintMessageVar". It's very similar to PrintMessage, but will instead print the value of a variable instead of predefined text.
An example looks like this:
float distance = 500.0 ; PrintMessageVar DistanceToObject: FLOAT distance ;

Notice how, when we want to display the variable, we must choose if it's an integer or a float etc. The choice must also be in CAPITALS. Int becomes INT, float becomes FLOAT etc, otherwise the script crashes.

Now all we want to do is simpy look up the values and write them to the log.txt. For commodityId it would look like this:

player GetCommoditiesCount commodityId howMuch ; PrintMessageVar commodityID INT commodityId ; PrintMessageVar commodityValue INT howMuch ;

Try doing the rest yourself, so you can get the hang of how it works.

Not all the answers are in the examples above, although they give you a good idea of what code you'll need to use.

The answers, if you get stuck, are here[www.hellhound1.com].

To actually call the script, we need to edit another pre-created script.

Head to SPG2/Scripts/Sectors/EnterSector184.sal and copy it to the same location in your Mod folder. (Mods/MyMod/Scripts/Sectors)

If you have already completed Chapter 4, Part 2, then you'll already have this file. Just add the following line of code beneath the line we modded last time, or replace it.

If you havent come from Chapter 4, Part 2, open up the file.

We need to edit this file to call our CustomScript.sal when this script is finished.

There is a function called "script" that allows you to point to another script when the current script has finished executing. Lets add it in.

/* END derelict randomization */ script Mods\MyMod\Scripts\CustomScripts\MyScript.sal End

I've put the code there so that it's called before the end of the script, but after the script has completed. You need to add the full path to the script file, as above.

And that's it. Done.

You can test your script by starting a new game, then immediately exiting the game, and looking in the log.txt. It'll point out any script errors.

A quick point on script errors:
Error! ScriptError: wrong Function <GetSpeed> in line 21!
That's an example of what a script error might look like. It tells you which function is wrong, and on which line. Lines start at 0, so line 21 is actually line 22 to a normal person ;)


You should now have something similar in your log.txt:
Chapter 4 - Scripting (Part 4)
Loops!

(If you're already confident on how loops work, you can skip to Part 5.)

Notice how we're only checking the amount of a commodity for the commodity with id 0?

What if we wanted to check all the commodities?

There is a function we can use, called a "For Loop". A loop allows us to cycle through some code, increase a number, and cycle through the code again, increasing the number each time until we're happy.

for i = 0 < 10 step 1 math count = count + i ; endfor

Thats the example the devs give us, so i'll break it down now and try to explain it a bit better.

I is a variable declared as an integer
count is also a variable declared as an integer

for i = 0 < 10 step 1
This basically means that
For the value of I, starting at 0 and having a maximum of 9, loop through and each time + 1 to the value of I.

Notice the < symbol. This means less than 10. So it will stop at 9. If you wanted to include 10, you'd need to set it to <= 10. This symbol means less than or equal to. It will include 10.

Step 1 literally means take a step of 1 each time.

So with each loop we add 1 to the value of I until it's 10.

math count = count + i ;
This basically adds the value of "i" to the variable "count" each time it goes round.

endfor
Lets the engine know the end of the loop. After exiting the loop, it will carry on from here.




Chapter 4 - Scripting (Part 5)
Now we're going to implement this code into our script from part 3.

We left commodityId as 0, so the code will only check the first commidity. What if we wanted to check the first 20 commodities? Would we have to copy and paste the code 20 times and each time increase the Id? Nope. We use the loop.

for I = 0 <= 20 step 1

is the first line we want. We should already have out GetCommoitiesCount expression, and the two PrintMessageVar statements.

We need to surround those two statements by the loop, so that we get a print out of each ID and it's value.

for I = 0 <= 20 step 1 player GetCommoditiesCount commodityId howMuch ; PrintMessageVar commodityID INT commodityId ; PrintMessageVar commodityValue INT howMuch ;

Thats how it should look.

We then want to increase commodityId by 1 each time, so we add
math commodityId = commodityId + 1 ;

Notice here that case matters. CommodityId is NOT the same as commodityId which is also NOT the same as commodityID. Case matters.

Don't forget your:
endfor
otherwise it'll crash.

Thats it. Save the file, load a new game. Quit it, and take a look at the log.txt. You'll notice now there is an entry for each commodity. It'll look similar to this:


Your code should look something similar to this:
for I = 0 <= 20 step 1 player GetCommoditiesCount commodityId howMuch ; PrintMessageVar commodityID INT commodityId ; PrintMessageVar commodityValue INT howMuch ; math commodityId = commodityId + 1 ; endfor
You can look inside commoditites.wdt for the full list, and to see how many there are. Play with the loop a bit and see what else you can loop!

Full code up to this Chapter can be found here[www.hellhound1.com].

Done! Thats how easy a loop is to implement.
Chapter 4 - Scripting (Part 6)
We're going to go a little bit further with loops now, and only display commodities that have a value bigger than 0. This can be done through a simple IF statement.

If howMuch > 0 *execute code* endif

So lets take a look at our current code.

for I = 0 <= 20 step 1 player GetCommoditiesCount commodityId howMuch ;

We need these two to be called first so that we get the loop working, and we get the value of howMuch.
We only want the code to be printed if the value is greater than 0, so this is where we start our IF statement.

if howMuch > 0
We dont use the semicolon ; on an if statement.

Underneath the two print message statements, we need to add our endif. Your code should now look something like this:
for I = 0 <= 20 step 1 player GetCommoditiesCount commodityId howMuch ; if howMuch > 0 PrintMessageVar commodityID INT commodityId ; PrintMessageVar commodityValue INT howMuch ; endif math commodityId = commodityId + 1 ; endfor

If you start a new game and run this code, you'll notice there are no printouts for commodityID and value. It's worked.

What I am going to quickly deviate to show you, is how to keep your code tidy. So far we haven't used many complicated functions, but as we get deeper and deeper the code will get harder to understand.

If i take the above code, the best way to lay it out would be like this:
for I = 0 <= 20 step 1 player GetCommoditiesCount commodityId howMuch ; if howMuch > 0 PrintMessageVar commodityID INT commodityId ; PrintMessageVar commodityValue INT howMuch ; endif math commodityId = commodityId + 1 ; endfor

When using a function you return from, like FOR or IF, it's best to indent the code inside that statement so you can see where to code ends and starts. From now on, you'll see I correctly indent my code. Try and learn how to indent yours, so when you come back to it, it's easier to read. Code is usually indented with a tab.


OK so now we've got a nice little script running, but it doesn't really do anything.

Let's start implementing a script that can be used in game.

We're going to make it so that when the player docks at a space station, theres a 1 in 20 chance that they lose all their credits. It might not be the kindest idea, but there is some great scripting behind it, so we'll roll with it ;)





Chapter 4 - Scripting (Part 7)
We'll need to start by creating a new Mod, called StationThief. Make sure that the file bypass is pointing to the correct place, and make sure the StartScene in the root folder is set correctly.

We then need to set up the correct folder structure, so create the "Scripts" folder.

Then create a script file called "StationThief.sal" either in the main folder or create a sub folder of your choice and create it there.

Open it, and start by declaring three Variables (I'm using A, B and C) as integers. Have your first Variable as 0, your second as 20, and your third as zero.

We also want to remove any credits a player has when they land on the station if they're unlucky, so we need to declare the variable for SetCredits (Check here[modding.starpointgemini.com] for the function). For simplicity, im using "credits" as my variable name, with a value of 0.

Our first function is similar to the "random" script that we looked at earlier.

In my case, that's
math C = Rnd A B ;
but switch the variable names for yours.

It might be worth, for debug purposes, adding a message to the log so you can see the outcome of the random function, but it's entirely optional.

We then need to use an IF statement so that the removal of the credits is only called if a certain number is randomly picked. I've used the value of 1, but you can use any number between 1 and 20 you like.

Add in the function for SetCredits using your variable. Optionally add in a log message to notify yourself it's worked. Add an endif.

Don't forget to put End at the end of your script.

Done.

Simple, right?

Now we need to call the correct code for when a player docks on a station. Again, for ease, ill be using the station Vigo in sector 184.

So copy over Sector184.ics from the world/sectors folder to the same location in your mods folder.

Open it up, and scroll down until you see the station in the code, and beneath that there should be an empty events declaration.
Events: { }

Here is where we want to add a link to our script. We want to do this when the player has landed.
Look on the modding website[modding.starpointgemini.com] for the station object. You can see the code is
OnDock
So between the two { } add OnDock: and then the full path to the script. Remeber theres a tab after the colon.

Mine looks like this:
{ OnDock: Mods\StationThief\Scripts\Hellhound1\StationThief.sal }

That's it.
Save your scripts, run your game. Dock at Vigo, then check how many credits you have. If it's 0, then well done, you're super unlucky! If it's not, then exit the game and check your log.txt. It will show any script errors. If you put in any custom messages, they'll show here as well.

If everything looks ok, well done! You've now made a difference, albeit a small one, in the game itself. There are other options you can explore, like adding a message to the in-game log to say you've been robbed if you're unlucky, or you could go as far as creating a side mission to get your money back... All through the power of scripting :)

You can take a look at my scripts here:
http://www.hellhound1.com/downloads/spg2/tutorial/answers3.txt
http://www.hellhound1.com/downloads/spg2/tutorial/answers4.txt (cut down to important bit)

Or you can download the complete solution here[www.hellhound1.com]


Chapter 4 - Dynamic Scripting (Part 1) [WIP]
Dynamic Scripting isn't really a thing. I made it up. But, it differs from normal scripting in that we get all our variables from values already stored in the game, rather than creating our own.

Take our previous script for example. We're forcing the player to have 0 credits after they get robbed. What if the robber didnt manage to get all of your credits and you're left with half? How do we calculate that? It's unfair to take half of a new players credits, but its not unfair to steal half of an experienced players credits, so how do we work that into it? What if the player can use troops kept on their ship as bodyguards, decreasing the chance of a robbery taking place?

They're all examples of scenarios in the game a good modder will take into account when making a mod. It's no good to arbitrarily say that a player is going to lose all of their credits when they dock regardless of that massive army they have on board. It doesn't make sense.

So we're going to look at how you solve that. Theres no trick to it. If you're thinking "Well I'll just get that value from GetTroops" thats exactly what we'll do.

So the rest of this chapter is about just that. Making your scripts smarter and dynamic so they're not the same for everyone.

Lets go back to our previous script and open it up.


We're going to take a random percentage of a player's money, depending upon how much money they have. The more they have, the more they've got to lose.

We'll also lessen the chance of this happening based on the exp of the player.

We start by declaring all our variables as 0. It forces them to be 0 if the game has remebered similar variables from a previous script or if it's a loop, and plays on the safe side.

int A = 0 ; int B = 0 ; int C = 0 ; int exp = 0 ; int credits = 0 ;

The first value we want to get is the chance of this happening.
To do so, we need to use lots of if statements to match the players experience to the chance of this happening. (You could use else-if statements, but they don't work at the time of writing)

You can get the experience levels from the experience.wdt base file. I've done one for every 10 levels.

Heres an example:
if exp > 1001 && exp <= 20000 B = 20 ; PrintMessageVar B: INT B ; endif

Theres some new stuff i've introduced here, so lets take a look:
if exp > 1001 && exp <= 20000
This is a standard if statement with an "AND" in the middle, to compare two values.
The AND is displayed as two & symbols.

I've also used <=
This symbol means less than or equal to. You can use this in a combination with >= which means greater than or equal to. It's a mathimatical symbol to compare a value.

What this code basically says is
If exp is greater than 1001 AND experience is less than or equal to 20000

So the code will ONLY accept this if BOTH conditions are true.

B = 20 ;
All this does is change the value of B to 20.

You can repeat the if/endif block as many times as you want to get the values you want.

Don't forget to get the player experience first!

You can see my code here[www.hellhound1.com].

You can also see that I've done this in such a way that every value has been taken into account.

Look back at it a few times, and make sure you can understand it! Any questions just ask in the comments :)
Chapter 4 - Dynamic Scripting (Part 2) [WIP]
So now we're going to be adding in the random percentage calculation thats based on a player's current money.

This only needs to take place if the random code from the previous part actually happens.


Chapter 5 - An Intermediate Mod (Part 1) [WIP]
Walkthroughs
From here, is a list of walkthroughs you can follow independant of the Chapter system, that can give you a crash course in editing the game. However, a lot of the content will reference the Chapters, so it's still worth a read through them first.
Lord Of The (Planetary) Rings [Walkthrough 1]
Lets, for the sake of it, add another ring to Trinity (the planet you start at)

Start by creating a new Mod folder and .sgs file in the /Mods section (Instructions in Chapter 0) and call them both TrinintyRing



Theres one I made earlier. Lets copy it.

Go to Models/Planets/Trinity

Inside is a file called Planet_Trinity.asb

This is the file we want. Copy and paste it to Mods/TrinityRing/Models/Planets/Trinity

Open it up (with notepad++, naturally.)

It'll look similiar to this:


What we're looking for is an indication of a "ring" mesh. Notice in the main Trinity folder theres a file called ring.mdl? That's the mesh file.

Planet_trinity.asb is basically a config file that tells the engine what the planet is meant to look like.

StaticMesh: { MeshName: Spg2\Models\Planets\Trinity\Planet_Trinity.mdl Position: 0 0 0 Rotation: 0 2 0 Scale: 1 1 1 AngularVelocity: 0.00 0.0076 0.00 }

It's made up of these statements, defining each part of the mesh.

Look further down, and you'll find one for the ring. It looks like this:

StaticMesh: { MeshName: Spg2\Models\Planets\Trinity\ring.mdl Position: 0 0 0 Rotation: 0.00 0.00 0.30 Scale: 1 1 1 AngularVelocity: 0.00 0.00 0.00 }

So thats what the default ring looks like in code.

Let's add another!

At the bottom of the file, copy and paste the ring statement again, being careful to include the { } at the start and finish.

Now, lets alter it. The ring is already centered around 0, as definied by positiion.
Scale is how big the ring will be. A scale of 1 is normal size. A scale of 10 would be 10 times the normal size. A scale of 0.5 would be half the normal size. Get it?

AngularVelocity is.. well, i don't know. It's not important. Mess with it if you want, see if you can get anything interesting to happen with it. I think it'll make the ring spin.

Rotation is the one we want to change, so that the ring isn't just sat on top of the original.

Rotation is measured in Radians, and there's a nice complicated formula you can use to work it out. Or just google it! We want to set it to 180 degrees.

So edit all 3 rotations to 180.00. Your code should look like this:

StaticMesh: { MeshName: Spg2\Models\Planets\Trinity\ring.mdl Position: 0 0 0 Rotation: 180.00 180.00 180.00 Scale: 1 1 1 AngularVelocity: 0.00 0.00 0.00 }

That's it. Save the file, change the config file to point towards this new mod, start a new game, and admire your new found ring creation powers!

Remember, it's best to mess with the file as much as possible, so you can see for yourself what changes editing those values will make!
25 Comments
Galameth 21 May, 2023 @ 2:23pm 
Fighters are the carrier hanger fighter craft groups. Dropping this here for those of us who are nostalgic and still play.
SpawnCap 8 Nov, 2020 @ 2:23pm 
I know this is old, but thank you. I use to do programming about 30 years ago so I do understand the loop, variables, etc.
Vanacutt 6 Sep, 2018 @ 1:30pm 
Thanks! I managed to make a Licenses mod.
Raynor 5 Apr, 2016 @ 4:33pm 
I've done it before but I can't for the life of me remember. But how do you mod ship stats? I wanna increase the cargo on a few ships.
Parzival 23 Dec, 2015 @ 3:34pm 
Unlimited mercenary mod anyone?
Jack Burton 30 Oct, 2014 @ 11:33pm 
Top shelf Hellhound. Well played sir!
glenflet 10 Oct, 2014 @ 3:57am 
Oh also if you set credits to high you may find you lose some when you get income, most games set a hard currency/resource limit, so that it never roll around, this will mostly mean if the sume of your credits and the income exceds this limit your credits would be set to the limit automatically.
glenflet 10 Oct, 2014 @ 3:53am 
I belive the credits is would be stored as a 32 bit signed integer, i.e. at 2 147 483 647 it rolls around to -2 147 483 648. Hence probably shouldn't do more than 2 000 000 000 to be safe.
MrHellhound1  [author] 9 Oct, 2014 @ 3:09am 
Yeah, i think thats what happens if theres too many zeros.
I will at some point update this when the new xml stuff is released, or if i get a day or two to put it together properly
johnrob 8 Oct, 2014 @ 8:08pm 
Ok so I tried to follow this tutorial, but it's out of date as you said in the comments.

I don't know what I ended up doing as I only changed the one line of text for starting money, but somehow I ended up with -1,502,660,702 credits. (yea that's negative)

I tried to buy troopers on trinity and ended up with -61543953 troops.

I clearly modified <i>something</i> and it did effect the credits which is what I was going for, I just don't know if I added too many zeros? or if this particular method just doesn't work anymore? I guess I'll play around with it more and try to get something to work