SQL modding for dummies! (specially those that still use XML)

Leugi

Supreme Libertador
Joined
Jan 25, 2013
Messages
1,675
Location
Bolivia
So, I've finally made some mods using SQL, and I must say, it certainly has its advantages. After learning the workflow the work gets far faster than XML, and it's easier to spot errors in syntax as the syntax is more forgiving.

That being said, I see many people with fear of moving from XML to SQL (I'm looking at you Viregel). I understand because its odd to change something you've already been doing for a while to something that seems very different; however, the truth is that XML and SQL are not at all that different, and that SQL certainly has its advantages over XML.

So, this little tutorial is going to help you guys move from XML to SQL if you're willing (or else :p) ... Before starting, I must say I learned SQL for Civ5, so I'm nowhere near a master of sql or anything. All that will be said will be related to Civ5 Modding by itself.

1. What's with all the Caps! :cry:

Time to look at the first glance differences between XML and SQL... For this, we'll have a simple example of each.

XML (or, what you're accustomed of):
Code:
<GameData>
<Civilization_UnitClassOverrides>
		<Row>
			<CivilizationType>CIVILIZATION_LEUGI_PHILISTINE</CivilizationType>
			<UnitClassType>UNITCLASS_SPEARMAN</UnitClassType>
			<UnitType>UNIT_PHILISTINE_PELESET</UnitType>
		</Row>

	</Civilization_UnitClassOverrides>
</GameData>

SQL (or, what you're afraid of):
Code:
INSERT INTO Civilization_UnitClassOverrides 
		(CivilizationType, 			UnitClassType, 		UnitType)
VALUES		('CIVILIZATION_LEUGI_PHILISTINE', 	'UNITCLASS_SPEARMAN', 	'UNIT_PHILISTINE_PELESET');

Scary, huh? Well, both codes do exactly the same thing (Making the Peleset be the UU of the Philistines).

The first diference you'll notice is that the SQL thing doesn't have <GameData>, <Row> or brackets for that matter. The second thing you'll notice are the scary caps at INSERT INTO, and VALUES...

The way Civ works, you're adding "Rows" into database tables, by using the Row thing. To make sure you're adding Rows in the right table, you must also say <Civilization_UnitClassOverrides> and <GameData>... That's what you've been doing for a while by now, most likely ;)

SQL is far more direct. Instead of nesting stuff vertically it simply needs INSERT INTO 'table name' to know you're adding whatever you want to the right table. That's simply it, Insert into means, add this into that table (in this case, Civilization_UnitClassOverrides)... What you usually put under "Row" is what goes on the VALUES part, you're saying what you want to insert into the specified table.

Now, now, some of you probably have this: :confused: face... Well, let's look at our codes again, but instead of looking at the scary differences, let's look at the nice similarities :) (with colours!)

XML :
Code:
<GameData>
<[COLOR="Red"]Civilization_UnitClassOverrides[/COLOR]>
		<Row>
			<[COLOR="Blue"]CivilizationType[/COLOR]>[COLOR="Navy"]CIVILIZATION_LEUGI_PHILISTINE[/COLOR]</[COLOR="Blue"]CivilizationType[/COLOR]>
			<[COLOR="YellowGreen"]UnitClassType[/COLOR]>[COLOR="SandyBrown"]UNITCLASS_SPEARMAN[/COLOR]</[COLOR="YellowGreen"]UnitClassType[/COLOR]>
			<[COLOR="Lime"]UnitType[/COLOR]>[COLOR="SeaGreen"]UNIT_PHILISTINE_PELESET[/COLOR]</[COLOR="Lime"]UnitType[/COLOR]>
		</Row>

	</[COLOR="Red"]Civilization_UnitClassOverrides[/COLOR]>
</GameData>

SQL:
Code:
INSERT INTO [COLOR="Red"]Civilization_UnitClassOverrides[/COLOR] 
		([COLOR="Blue"]CivilizationType[/COLOR], 			[COLOR="YellowGreen"]UnitClassType[/COLOR], 		[COLOR="Lime"]UnitType[/COLOR])
VALUES		('[COLOR="Navy"]CIVILIZATION_LEUGI_PHILISTINE[/COLOR]', 	'[COLOR="SandyBrown"]UNITCLASS_SPEARMAN[/COLOR]', 	'[COLOR="SeaGreen"]UNIT_PHILISTINE_PELESET[/COLOR]');

As you can see, there are more similarities than differences! Yay! So, the difference is just the layout, the syntax. The logic you've been using for now still works, you just put things in a different (and faster) way. Don't Panic!

2. Basic SQL syntax :D

So, now let's just look at a fake SQL code:
Code:
INSERT INTO Table_A
		(Tag_A, Tag_B,  Tag_C)
VALUES		('A',	'B',	24);

What you're doing is assigning 'A' into Tag_A, 'B' into Tag_B, and '24' into Tag_C... if you want to see it in XML, it would be something like this:

Code:
<GameData>
	<Table_A>
		<Row>
			<Tag_A>A</Tag_A>
			<Tag_B>B</Tag_B>
			<Tag_C>24</Tag_C>
		</Row>
	</Table_A>
</GameData>

In SQL, the code is actually a bit shorter. You don't have to open and close the Table name or Rows... Its not needed at all!, you only have to put the tag names once and done. Now, it does require some few things to work, or else.

After saying INSERT INTO Table_A you must write all tags you want to change/add between these (----), and to sepparate each you just use some comas ',' (except for the last one, as there's nothing left afterwards).

Like this: INSERT INTO Table_A (Tag_A, Tag_B, Tag_C) ... As you can see, it doesn't matter if they are on the same row in the text, you can press enter once, twice, or more, depending what looks better for you. You can also add spaces between Table_A and (...) as much as you want, so you can give it the shape you wish (in XML a space or an enter is going to kill the whole document).

After saying "INSERT INTO Table_A (Tag_A, Tag_B, Tag_C) you need to say what VALUES you want to give to each of your tags. Now, there's something important here, text values (like UNIT_MUSKETMAN) must go between these ''. Number values need nothing in particular (because they are numbers and not text)... and finally boolean (true/false) become numbers (1/0 respectively)... Also at the end of VALUES you must put a semicolon ";" to end the thing properly... So like this:

If it is UNIT_MUSKETMAN it goes like 'UNIT_MUSKETMAN' (notice the fancy quotes)
If it is 100, it goes like 100 (no quotes)
If it is true, it goes 1
if it is false, it goes 0

Like this: VALUES ('A', 'B', 24)... Again, spaces and enters don't matter much.

These three codes work even if they have different spaces and enters:

Code:
INSERT INTO Table_A
		(Tag_A, Tag_B,  Tag_C)
VALUES		('A',	'B',	'C');


INSERT INTO Table_A (Tag_A, Tag_B,  Tag_C)
VALUES ('A',	'B',	'C');


INSERT INTO Table_A (Tag_A, Tag_B,  Tag_C)
VALUES ('A','B','C');

So, the thing with SQL is that you can move around things so they fit with each other nicely :) (using Tab, for example)

Code:
INSERT INTO Table_A 	(Tag_A, Tag_B,  Tag_C)
VALUES			('A',	'B',	'C');

This way, it's very hard to get lost, and you know fastly what value corresponds to what tag. :goodjob:

3. But, Civ5 files are all in XML, how will I know what tag to use? :sad:

Don't worry! It might seem easier just to copy a tag like <CultureFromKills>100</CultureFromKills> for your trait in XML... but in SQL it isn't that different at all... Case in question:

We have a Trait for our Civ, to put it in XML we do something like this:

Spoiler :
Code:
<GameData>
	<Traits>
		<Row>
			<Type>TRAIT_GENERIC</Type>
			<Description>TXT_KEY_TRAIT_GENERIC</Description>
			<ShortDescription>TXT_KEY_TRAIT_GENERIC_SHORT</ShortDescription>
		</Row>
	</Traits>
</GameData>

To do the same in SQL we do this:

Code:
INSERT INTO Traits
	(Type,			Description,			ShortDescription)
VALUES	('TRAIT_GENERIC',	'TXT_KEY_TRAIT_GENERIC',	'TXT_KEY_TRAIT_GENERIC_SHORT');

Now, let's say we want to give this Generic trait the same Culture from Kills as the Aztecs. By searching the game's files we know that <CultureFromKills>100</CultureFromKills> does it... In XML we simply copy it, right?

Spoiler :
Code:
<GameData>
	<Traits>
		<Row>
			<Type>TRAIT_GENERIC</Type>
			<Description>TXT_KEY_TRAIT_GENERIC</Description>
			<ShortDescription>TXT_KEY_TRAIT_GENERIC_SHORT</ShortDescription>
			<CultureFromKills>100</CultureFromKills> 
		</Row>
	</Traits>
</GameData>

Easy! Well, in SQL it isn't that hard either:

Code:
INSERT INTO Traits
	(Type,			Description,			ShortDescription,		CultureFromKills)
VALUES	('TRAIT_GENERIC',	'TXT_KEY_TRAIT_GENERIC',	'TXT_KEY_TRAIT_GENERIC_SHORT',	100);

Might not be as straightforward as copy-pasting it, but you're still simply adding the Tag at the end of the line and then putting the 100 there too. It's still very easy and it's easier too look at, if you comitted a mistake it will be fairly easy to see where it was (specially in long civ tables, like Units or Buildings)

4. Advantages of SQL :king:

So... now that you know your basics, let's see what's easier on SQL than it is on XML. We'll go little by little.

4.1. Easy Comments!

Comments are things you can put on code that are not going to be executed, they are useful as you can point out things of your code, or also useful to temporabily disable some part of it.

Comments in XML are like this: <!-- Comment --> ... As you can see you need to open and close (pretty much like everything in XML), using this <!-- to open and this --> to close... Simple, but it can get annoying. CivBE also has an issue with putting enters between such comment brackets.

For comments in SQL you just need this: --Comment . Two single characters and you have commented all the line! :D

Now, this may not seem as useful, but it really is. To disable a whole <Row> in XML you must put the brackets at the beginning and at the end, being careful with closing incorrectly everything... To disable our trait in SQL we just need to do this:

Code:
[COLOR="SeaGreen"]--INSERT INTO Traits
--		(Type,			Description,			ShortDescription,		CultureFromKills)
--VALUES	('TRAIT_GENERIC',	'TXT_KEY_TRAIT_GENERIC',	'TXT_KEY_TRAIT_GENERIC_SHORT',	100);[/COLOR]

Simply putting two characters! ... Anyway, another fancy use is what JFD does with comments, which certainly helps in putting everything in order. Because it is a comment, you can put anything you want on the line after the two -- thingies. So, you can put some decoration like this:

Code:
[COLOR="SeaGreen"]--===============================================================================================================
-- Traits
--===============================================================================================================[/COLOR]

INSERT INTO Traits
	(Type,			Description,			ShortDescription,		CultureFromKills)
VALUES	('TRAIT_GENERIC',	'TXT_KEY_TRAIT_GENERIC',	'TXT_KEY_TRAIT_GENERIC_SHORT',	100);


[COLOR="SeaGreen"]--===============================================================================================================
--===============================================================================================================[/COLOR]

Very nice, and keeps things easier to look at.

4.2. Stealing from other tables

Another thing that is a lot easier in SQL than in XML is stealing data from other tables. Say you want to add a Building, but since it's a Temple replacement you want it to be a Temple just with no mantenaince cost (let's imagine you also want the icon and the text and description, because it's a dummy UB)... In XML you'd have to copy the whole BUILDING_TEMPLE table with all its values... in SQL you need somethign like this:

Code:
INSERT INTO Buildings	
		([B]Type,[/B]				BuildingClass, 	MaxStartEra,	Cost,	[B]GoldMaintenance,[/B]	PrereqTech,	Description,	Civilopedia,	Strategy,	ArtDefineTag,	MinAreaSize,	ConquestProb,	HurryCostModifier,	IconAtlas,	PortraitIndex)
SELECT		[B]'BUILDING_DUMMY_TEMPLE'[/B],	BuildingClass, 	MaxStartEra,	Cost,	[B]0,[/B]			PrereqTech,	Description,	Civilopedia,	Strategy,	ArtDefineTag,	MinAreaSize,	ConquestProb,	HurryCostModifier,	IconAtlas,	PortraitIndex
FROM		Buildings WHERE (Type = 'BUILDING_TEMPLE');

Now, there are some new things here, of course. We'll explain them now... the first line is easy, it's just a INSERT INTO thing, like you've seen before.

The next line is odd, instead of VALUES it has a SELECT... and the things after select are not between ()... This means you're going to "select" some of the values from another existing Building type (the Temple)... That's why everything is just the same BUT the building type (because its another building, BUILDING_DUMMY_TEMPLE) and the GoldManteinance (which is now 0)...

Then it says FROM Buildings WHERE (Type = 'BUILDING_TEMPLE')... This means, Insert these stuff by selecting the valuse from the "Buildings" table, where the type of the building is BUILDING_TEMPLE... this is how it selects the right values ;) ... With practice, it becomes far easier and faster using this to create UB and UU, as you'll even have your own templates (or you will have stolen some from JFD :lol: )

4.3. Easier mistake checking

In XML you commit one mistake in one file, and the whole file ruins itself.. You suddenly have a whole civ not working and you don't even know why.

In SQL, every single mistake is individual. So, if you only got your mistake in setting the UnitClassOverrides, the civ will exist, just without a UU (so you'll know faster where the mistake was at)... or if you got the issue at the Buildings yield,your building will exist, but without the yield. Is a lot easier and more relaxing :cool:

4.4. Putting together a lot of Rows

Another advantage is putting together a lot of rows... Let's see how you use XML to put spies to your civ:

Spoiler :
Code:
<Civilization_SpyNames>
		<Row>
			<CivilizationType>CIVILIZATION_LEUGI_PHILISTINE</CivilizationType>
			<SpyName>TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_0</SpyName>
		</Row>
		<Row>
			<CivilizationType>CIVILIZATION_LEUGI_PHILISTINE</CivilizationType>
			<SpyName>TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_1</SpyName>
		</Row>
		<Row>
			<CivilizationType>CIVILIZATION_LEUGI_PHILISTINE</CivilizationType>
			<SpyName>TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_2</SpyName>
		</Row>
		<Row>
			<CivilizationType>CIVILIZATION_LEUGI_PHILISTINE</CivilizationType>
			<SpyName>TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_3</SpyName>
		</Row>
		<Row>
			<CivilizationType>CIVILIZATION_LEUGI_PHILISTINE</CivilizationType>
			<SpyName>TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_4</SpyName>
		</Row>
		<Row>
			<CivilizationType>CIVILIZATION_LEUGI_PHILISTINE</CivilizationType>
			<SpyName>TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_5</SpyName>
		</Row>
		<Row>
			<CivilizationType>CIVILIZATION_LEUGI_PHILISTINE</CivilizationType>
			<SpyName>TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_6</SpyName>
		</Row>
		<Row>
			<CivilizationType>CIVILIZATION_LEUGI_PHILISTINE</CivilizationType>
			<SpyName>TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_7</SpyName>
		</Row>
		<Row>
			<CivilizationType>CIVILIZATION_LEUGI_PHILISTINE</CivilizationType>
			<SpyName>TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_8</SpyName>
		</Row>
		<Row>
			<CivilizationType>CIVILIZATION_LEUGI_PHILISTINE</CivilizationType>
			<SpyName>TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_9</SpyName>
		</Row>

	</Civilization_SpyNames>

A long and boring code. Now let's see it in SQL:

Code:
INSERT INTO Civilization_SpyNames 
			(CivilizationType, 			SpyName)
VALUES			('CIVILIZATION_LEUGI_PHILISTINE', 	'TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_0'),	
			('CIVILIZATION_LEUGI_PHILISTINE', 	'TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_1'),
			('CIVILIZATION_LEUGI_PHILISTINE', 	'TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_2'),
			('CIVILIZATION_LEUGI_PHILISTINE', 	'TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_3'),
			('CIVILIZATION_LEUGI_PHILISTINE', 	'TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_4'),
			('CIVILIZATION_LEUGI_PHILISTINE', 	'TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_5'),
			('CIVILIZATION_LEUGI_PHILISTINE', 	'TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_6'),
			('CIVILIZATION_LEUGI_PHILISTINE', 	'TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_7'),
			('CIVILIZATION_LEUGI_PHILISTINE', 	'TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_8'),
			('CIVILIZATION_LEUGI_PHILISTINE', 	'TXT_KEY_SPY_NAME_LEUGI_PHILISTINE_9');

You no longer need to scroll down that much, and you don't need that many <Row>s everywhere. Now, as you can see, to separate each line you just need a comma ( , ) instead of a semicolon ( ; ) which only goes in the last one.

For another example, I'll just show you this:

Code:
--==========================================================================================================================
-- Building Classes
--==========================================================================================================================	
INSERT INTO BuildingClasses 	
			(Type, 					DefaultBuilding,		Description)
VALUES			('BUILDINGCLASS_HAITI_BONUS',		'BUILDING_HAITI_BONUS',		'TXT_KEY_TRAIT_LEUGI_HAITI_SHORT'),
			('BUILDINGCLASS_HAITI_CHECK',		'BUILDING_HAITI_CHECK',		'TXT_KEY_TRAIT_LEUGI_HAITI_SHORT'),
			('BUILDINGCLASS_HAITI_IDEOLOGY',	'BUILDING_HAITI_IDEOLOGY',	'TXT_KEY_TRAIT_LEUGI_HAITI_SHORT'),
			('BUILDINGCLASS_HAITI_IDEOLOGY_0',	'BUILDING_HAITI_IDEOLOGY_0',	'TXT_KEY_TRAIT_LEUGI_HAITI_SHORT'),
			('BUILDINGCLASS_HAITI_TOURISM',		'BUILDING_HAITI_TOURISM',	'TXT_KEY_TRAIT_LEUGI_HAITI_SHORT');

This adds all Building Classes I needed in Haiti, in just a few easy to look lines :D

4.5. More Advanced Advantages and Resources

This tutorial ends here, but if you're willing there are some more advanced techniques to use in SQL. Some links if you're interested:
  • SQL Cheat Sheet: A simple guide to some of the features and comparisons with XML. You can also see how to update and delete rows in SQL (again, faster than XML :lol: )
  • Adding New Tables with SQL: For this you'll also need some Lua knowledge, but TLDR you can use SQL to add new Tables for your own evil needs without touching the DLL (you need Lua so the tables do something, of course)
  • SQL Trigger Magic: SQL triggers are fairly advanced, and you'll probably need some practice with SQL without trying these ones. However, they are also really useful. Allowing you to wait before all mods add Civilizations without even knowing their mod ids, or changing all Buildings to have the same Manteinance Cost... all of that is easily possible with SQL.

The End

Enjoy as you are assimilated to the one true master code :borg:

(XML is still useful for changing/adding the Pedia texts and descriptions btw)

For any questions, blasphemies or whatever, just post them.
 
Good stuff. Glad to see it's correctly quoted (ie not riddled with double quotes everywhere and/or quoting numbers)

Minor error in section 2

Code:
INSERT INTO Table_A
		(Row_A, Row_B,  Row_C)
VALUES		('A',	'B',	'C');

should be

Code:
INSERT INTO Table_A
		(Tag_A, Tag_B,  Tag_C)
VALUES		('A',	'B',	'C');

(and three other code samples)

And one unnecessary use of brackets in 4.2, ('BUILDING_DUMMY_TEMPLE') doesn't need them
 
It's probably worth adding that SQL has no "true" and "false" and just to use 1 and 0 instead

Code:
  <Units>
    <Row>
      <Type>UNIT_POPULATION</Type>
      <Pillage>false</Pillage>
      <Found>true</Found>
      ...
    </Row>
  </Units>
Code:
INSERT INTO Units(Type, Pillage, Found, ...)
VALUES('UNIT_POPULATION', 0, 1, ...);
 
Might be worth pointing out how to update values in multiple items, as that's not covered in the cheat sheet, e.g:

Code:
UPDATE Buildings
SET Cost = 1900
WHERE Type IN ('BUILDING_TEMPLE', 'BUILDING_SHRINE');

Also, to recommend installing SQLite Manager to test your SQL for any syntax errors or database duplications.

SQL is witchcraft! It allows you to accomplish beyond the preordained limits of XML.

Someone should call the Spanish Inquisition. We has a blasphemer in our midst :p
 
I still use XML for simple additions of new rows to existing tables. But for manipulation of existing data, and other advanced tasks, I use SQL. For me the main advantage of it is that it allows a large amount of data created or modified by a single command. For example in my total conversion mod I removed all civs and created new ones, and to give them all the starting settler and palace I only need this code:

Code:
INSERT INTO Civilization_FreeUnits (CivilizationType, UnitClassType, UnitAIType, Count)
SELECT Type, 'UNITCLASS_SETTLER', 'UNITAI_SETTLE', 1 FROM Civilizations 
WHERE Type <> 'CIVILIZATION_BARBARIAN';

INSERT INTO Civilization_FreeBuildingClasses (CivilizationType, BuildingClassType)
SELECT Type, 'BUILDINGCLASS_PALACE' FROM Civilizations
WHERE Type <> 'CIVILIZATION_BARBARIAN';

(A similar method can be used to give them the starting tech, if it's the same for all civs like in normal game.)

Edit: JFD's code won't work because it's missing a ; at the end :)
 
Hi, SQL handles bedmas similarly with brackets like other languages right?

Code:
UPDATE [Leader_Flavors] SET [Flavor] = Round((20 + [Flavor]) * 150 / 100) WHERE [FlavorType] = 'FLAVOR_EXPANSION';

Will that evaluate as "(20+Flavor) * 1.5, rounded"?

Also, the statements are handled sequentially as well? I.E.

Code:
Set ItemA = B + C

Set ItemD = ItemA * 2

Would essentially be saying the same thing as 2 * (B+C)?


As well, are there any limits to how many SQL files are allowed per mod?
 
Edit: JFD's code won't work because it's missing a ; at the end :)

Bah. Maybe a section on stupid mistakes that I make :lol: Thanks :)

Hi, SQL handles bedmas similarly with brackets like other languages right?

Code:
UPDATE [Leader_Flavors] SET [Flavor] = Round((20 + [Flavor]) * 150 / 100) WHERE [FlavorType] = 'FLAVOR_EXPANSION';

Will that evaluate as "(20+Flavor) * 1.5, rounded"?

Yes, that works, although I'm not sure the brackets around the tables are necessary.

As well, are there any limits to how many SQL files are allowed per mod?

I'm not sure if there is a limit to how many SQL files are allowed - I don't think there is one - but there is a limit to how many items you can insert into a table in one command. Not sure of the number, but it's fairly high anyway.
 
Littering SQL with unnecessary brackets is as bad as using unnecessary quotes

[Please], ((please), please), {don't do it}

You wouldn't write like that, so why do it to a poor programming language?

And SQL understands floating point numbers ... so use 1.5 if you mean 1.5

And white space is free
Code:
UPDATE Leader_Flavors
  SET Flavor = round((20 + Flavor) * 1.5)
  WHERE FlavorType = 'FLAVOR_EXPANSION';
 
You can also do block comments like this:
Code:
/*
Whatever it was that you're so ashamed of
but which will never come to light now
*/
I just use them to keep tech flavors out until my AI programmer gets to them.

Someone should call the Spanish Inquisition. We has a blasphemer in our midst :p
While I agree he's a blasphemer, let's just burn him ourselves. If we call the Inquisition, we'd be expecting it.
 
Well, this certainly helps make some sense of a few things I've been struggling with, and have been stealing other folks code to use as templates.

Though I'm about to really blaspheme and mention that for short tables (three to four columns max) I find it just as easy to read and manipulate this as its SQL equivalent:
Code:
<GameData>
	<Unit_UniqueNames>
<Row UnitType="UNIT_GREAT_GENERAL" UniqueName="TXT_KEY_GREAT_PERSON_WINFIELD_SCOTT" CivilizationType="CIVILIZATION_AMERICA" />
<Row UnitType="UNIT_GREAT_GENERAL" UniqueName="TXT_KEY_GREAT_PERSON_ROBERT_LEE" CivilizationType="CIVILIZATION_AMERICA" />
<Row UnitType="UNIT_GREAT_GENERAL" UniqueName="TXT_KEY_GREAT_PERSON_PATTON" CivilizationType="CIVILIZATION_AMERICA" />
<Row UnitType="UNIT_GREAT_GENERAL" UniqueName="TXT_KEY_GREAT_PERSON_TJACKSON" CivilizationType="CIVILIZATION_AMERICA" />
<Row UnitType="UNIT_GREAT_GENERAL" UniqueName="TXT_KEY_GREAT_PERSON_PERSHING" CivilizationType="CIVILIZATION_AMERICA" />
<Row UnitType="UNIT_GREAT_GENERAL" UniqueName="TXT_KEY_GREAT_PERSON_REYNOLDS" CivilizationType="CIVILIZATION_AMERICA" />
	</Unit_UniqueNames>
</GameData>
But I'm not saying the one way is better than the other. Just knowing I can use tabs in SQL to align everything so I can read which VALUE goes with which column tag is a big help in and of itself for larger tables like <Buildings>.
 
So having absolutely no knowledge of programming aside from once having classes on HTML web design and doing stuff in Visual Basic that was largely copy-pasting code from a book, I am now attempting to make a civilization using entirely SQL.

I already have almost no idea what I'm doing. :crazyeye:

Something like a basic civilization template would be super useful but for the most part asdf. That tutorial mostly in XML is a bit unhelpful since, well, it's in XML and the tutorial file used doesn't exist. But in any case, I am pondering whether the following things are doable easily.

UA: When a Mounted Unit defeats another enemy unit from a later era, gain +1 Happiness.

UU: Horseman replacement, gets +5 EXP whenever a tech is researched (or if that involves lua of some sort, something more like getting a fraction of science per turn as exp when it's built)

UU: Landsknecht replacement, but is at Rifling and has slightly lower combat strength than a Rifleman (same gold cost though). Gives adjacent mounted units +8 Combat Strength.
 
@Gyra Solune: You can't achieve these effects using XML or SQL, you need to use Lua.
 
Hi, I'm a new modder trying to make a total conversion mod. I am trying to convert my XML files into the SQL format as suggested by someone who was helping me with my mod on the forums. I just had some quick questions.

1. With my mod, I'm trying to add a lot of new stuff so I think it may be best to delete the unmodded tables and add my own. I looked at the link provided and it mentioned columns instead so I'm kind of confused. Is there something I'm missing here?
2. I looked at where you put the VALUES in "SQL (or, what you're afraid of):" and I have seen it put different places. So I was wondering where I should put it or if it can be in a number of different places without it causing any problems.

Anything helps. By the way, great tutorial.
 
Top Bottom