1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

[MOD] Colonization: 2071

Discussion in 'Civ4Col - Mods and Files' started by orlanth, Jan 7, 2010.

  1. Nightinggale

    Nightinggale Deity

    Joined:
    Feb 2, 2009
    Messages:
    4,354
    People have tried to trace the origin and there are indications that it came from Syracuse. There is even a specific name to that trace, which is Archimedes. We will never know for sure, but I do say that it isn't unlikely. First of all he had the brain to come up with it. Also we do know very little of his father, but what we do know is that he was an astronomist and that he might have been as brilliant as Archimedes. At least he was viewed as a great astronomist who discovered new science, though we lost what precisely he discovered.
    For all we know he figured out how to speak with the Progenitors :lol:

    I considered using perl, but I have used it very little. I decided on using bash because it has ok string handling and it is very easy and fast to write scripts. The downsite is that they are s l o w and that bash doesn't work natively in windows. However I haven't kept up to date with how to get bash in windows. I know cygwin should provide support for it, but I guess there are simpler ways to get it. Didn't TortoiseGit come with a bash installer btw? Maybe I should investigate this.

    If you have bash in windows (I think you can get it if you want), then you could write a script like this:

    Spoiler :
    #!/bin/bash

    #first line tells where the bash exe is. The line might be different on different computers

    # lines starting with # are comments

    # the print commands. They print the number of tabs you want and then the argument, followed by a newline
    function print1 {
    printf "\t"
    echo "$1"​
    }

    function print2 {
    printf "\t\t"
    echo "$1"​
    }

    function print3 {
    printf "\t\t\t"
    echo "$1"​
    }

    function print4 {
    printf "\t\t\t\t"
    echo "$1"​
    }

    function print5 {
    printf "\t\t\t\t\t"
    echo "$1"​
    }


    # the real script

    while TAGNAME in `cat input.txt`
    do
    # this is a loop and it creates a variable called TAGNAME with the content of each line of input.txt

    # first we make a new variable of the type name in lowercase
    TYPE_lower=`echo "${TAGNAME}" | tr '[:upper:]' '[:lower:]'`

    print2 "<ProfessionInfo>"
    print3 "<Type>${TAGNAME}</Type>"
    print3 "<Description>${TYPE_lower#*_}</Description>"
    print3 "<Civilopedia>TXT_KEY_UNIT_${TAGNAME#*_}_PEDIA</Civilopedia>"
    print3 "<Strategy>TXT_KEY_${TAGNAME}_STRATEGY</Strategy>"
    # you get the idea with the copy paste from CIV4ProfessionInfos.xml​
    done

    As you can see you just write the text you want it to print. If you want a variable, you just write ${name} and it will replace ${name} with whatever the content of name is before executing the line.

    I used another variable call, which is ${name#*_}. It removes the first _ and everything before it, meaning PROFESSION_COLONIST becomes COLONIST.

    There are all sorts of commands here: http://tldp.org/LDP/abs/html/string-manipulation.html

    Actually to get Description right, it should be something like:
    Spoiler :
    TYPE_lower=`echo "${TAGNAME}" | tr '[:upper:]' '[:lower:]'`
    TYPE_lower=${TYPE_lower#*_}
    TYPE_upper=${TAGNAME#*_}
    Description=${TYPE_upper:0:1}${TYPE_lower:1}

    Sure it's way more advanced than just the copy paste in the loop, but it will remove everything from before the _ and then it will print the first character from the uppercase string and then all the characters except the first from the lowercase string. However it shows the powers of bash string handlilng and gives an idea of what can be done with a fairly simple approach. Remember we generated 4 XML lines, which are different for each unit with those few lines and they are all based on just the name of the profession. We could also start the loop with
    TAGNAME="PROFESSION_${TAGNAME}"
    That way it assumes PROFESSION is missing in the txt input file.

    This script has no understanding of what XML is, but it's so crude that it will not have to know. It just generates output, which happens to be able to be copy pasted into an XML document.

    When executing the script, you could type something like "script.sh > output.txt". The red part makes it write the output to the file output.txt instead of on the screen. This could make copy pasting a lot easier.
     
  2. orlanth

    orlanth Storm God. Yarr!

    Joined:
    Nov 17, 2001
    Messages:
    1,776
    Progress marches on! :borg::scan::assimilate::borg::goodjob::science: ProfessionsInfos.xml is now completed & uploaded.:cool:

    I was hoping to be able to make a single generalizable script that could read in any XML file as a template and populate new tag entries from a list, but it looks like XML::Simple may not be entirely as simple as advertised.. :crazyeye: Actually it's not too bad and it seems close to working, but I can't quite figure out how to access all the pointers and references in the hash and array data structure it generates from XML. Well I'll attach the preliminary version of that here too if anyone has some insight.
    Spoiler :
    Code:
    #!/usr/bin/perl
    # read XML template and content list, generate XML for each content item
    
    # use module
    use XML::Simple;
    use Data::Dumper;
    
    # input filenames
    print "XML template: ";
    chomp ($templatefile = <>);
    print "List of content: ";
    chomp ($contentfile = <>);
    
    # read XML template
    my $simple = XML::Simple->new (ForceArray => 0, KeepRoot => 0);
    my $template = $simple->XMLin($templatefile);
    
    # write hash structure to log file
    open (LOG, "> log.txt") or die "Can't write to logfile: $!";
    print LOG Dumper ($template);
    
    # read content list
    open (CONTENT, "< $contentfile") or die "Can't read content from $contentfile: $!";
    @content = <CONTENT>;
    close CONTENT;
    
    # generate XML
    foreach $item (@content)
    	{
    	$newtag = $template->{YieldInfos};
    	$newtag->{YieldInfo}->{Type} = 'YIELD_'.$item;
    	$newtag->{YieldInfo}->{Description} = ucfirst(lc($item));
    	$newtag->{YieldInfo}->{UnitClass} = 'UNITCLASS_'.$item;
    	$newtag->{YieldInfo}->{iTextureIndex} = $index;
    	$newtag->{YieldInfo}->{Icon} = ',Art/Interface/Buttons/Yields/'.$item.'.dds';
    	$newtag->{YieldInfo}->{HighlightIcon} = ',Art/Interface/Buttons/Yields/'.$item.'1.dds';
    	$newtag->{YieldInfo}->{Button} = ',Art/Interface/Buttons/Yields/'.$item.'.dds';
    	print LOG "tag $index:\n";
    	print LOG Dumper (@newxml);
    	push (@newxml, $newtag);
    	$index++;
    	}
    
    print LOG Dumper (@newxml);
    
    $simple->XMLout(@newxml, 
                OutputFile => 'new.xml',
                XMLDecl    => "<?xml version='1.0'?>",
            );
            
    close LOG;
    
    Anyway, after bashing my head at that for a while I tried a different tack along the lines of your script example (ie making a specific one for professioninfos, grabbing yield names from Yieldinfos.xml to populate Professions appropriately.) Each of the standard professions that generates a Yield keeps that Yield as its XML tag name (eg PROFESSION_PLASTEEL), eliminating the necessity to remember to refer to PROFESSION_PLASTEEL_CRAFTINATOR or whatever. This script approach would require making a modified one for any other XML file types to do this for, but still speeds the process & reduces coding errors compared to typing & copy-pasting countless entries in text editors which can get intergalactically daunting. :crazyeye:

    Spoiler :
    Code:
    #!/usr/bin/perl
    # read content list, generate XML for each content item
    
    # input filenames
    print "List of content: ";
    chomp ($contentfile = <>);
    
    # grab yield names
    open (CONTENT, "< $contentfile") or die "Can't read content from $contentfile: $!";
    while (<CONTENT>) {
    	if ($_ =~ /YIELD_(\w+)<\/Type/) {
    		push (@content, $1);
    		}
    	}
    close CONTENT;
    
    open (OUTFILE, "> $contentfile".'.xml') or die "Can't write output: $!";
    
    # generate XML
    print OUTFILE '<?xml version="1.0">'."\n.";
    print OUTFILE '<!-- edited with XMLSPY v2004 rel. 2 U (http://www.xmlspy.com) by EXTREME (Firaxis Games) -->'."\n";
    print OUTFILE '<!-- Sid Meier\'s Civilization 4 -->'."\n".'<!-- Copyright Firaxis Games 2005 -->'."\n".'<!-- -->'."\n";
    print OUTFILE '<Civ4ProfessionInfos xmlns="x-schema:CIV4UnitSchema.xml">'."\n<ProfessionInfos>\n";
    foreach $item (@content)
    	{
    	print OUTFILE "<ProfessionInfo>\n";
    	print OUTFILE "\t<Type>PROFESSION_".$item."</Type>\n";
    	my $desc = $item;
    	$desc =~ tr/_/ /;
    	$desc =~ s/(\w+)/\u\L$1/g;
    	print OUTFILE "\t<Description>".$desc."</Description>\n";
    	print OUTFILE "\t<Civilopedia>[BOLD]".$desc."[/BOLD] is a wonderful profession to have.</Civilopedia>\n";
    	print OUTFILE "\t<Strategy></Strategy>\n";
    	print OUTFILE "\t<Help/>\n";
    	print OUTFILE "\t<Combat>UNITCOMBAT_MELEE</Combat>\n";
    	print OUTFILE "\t<DefaultUnitAI>UNITAI_COLONIST</DefaultUnitAI>\n";
    	print OUTFILE "\t<SpecialBuilding>NONE</SpecialBuilding>\n";
    	print OUTFILE "\t<bWorkPlot>0</bWorkPlot>\n";
    	print OUTFILE "\t<bCitizen>0</bCitizen>\n";
    	print OUTFILE "\t<bWater>0</bWater>\n";
    	print OUTFILE "\t<bScout>0</bScout>\n";
    	print OUTFILE "\t<bCityDefender>0</bCityDefender>\n";
    	print OUTFILE "\t<bCanFound>1</bCanFound>\n";
    	print OUTFILE "\t<bUnarmed>1</bUnarmed>\n";
    	print OUTFILE "\t<bNoDefensiveBonus>0</bNoDefensiveBonus>\n";
    	print OUTFILE "\t<iCombatChange>0</iCombatChange>\n";
    	print OUTFILE "\t<iMovesChange>0</iMovesChange>\n";	
    	print OUTFILE "\t<iWorkRate>0</iWorkRate>\n";
    	print OUTFILE "\t<iMissionaryRate>0</iMissionaryRate>\n";
    	print OUTFILE "\t<iPower>0</iPower>\n";
    	print OUTFILE "\t<iAsset>0</iAsset>\n";	
    	print OUTFILE "\t<YieldEquipedNums></YieldEquipedNums>\n";	
    	print OUTFILE "\t<FreePromotions></FreePromotions>\n";	
    	print OUTFILE "\t<YieldsProduced>\n";
    	print OUTFILE "\t\t<YieldType>YIELD_".$item."</YieldType>\n";
    	print OUTFILE "\t</YieldsProduced>\n";
    	print OUTFILE "\t<YieldsConsumed>\n";
    	print OUTFILE "\t\t<YieldType>NONE</YieldType>\n";
    	print OUTFILE "\t</YieldsConsumed>\n";
    	print OUTFILE "\t".'<Button>,/Art/Buttons/Yields/'.$item.'.dds</Button>'."\n";
    	print OUTFILE "</ProfessionInfo>\n";
    	}
    print OUTFILE "</ProfessionInfos>\n</Civ4ProfessionInfos>\n";
    close OUTFILE;
     
  3. Nightinggale

    Nightinggale Deity

    Joined:
    Feb 2, 2009
    Messages:
    4,354
    There is a reason why I decided against having a script reading the xml as xml :lol:

    Wrong approach. You are coding in perl, not bash :lol::p

    I can't see a way to NOT make a modified version for each XML file. However it's more or less just the print OUTFILE, which needs changing. The rest is fairly generic.


    First of all you are missing tabs.
    Code:
    0<Civ4ProfessionInfos xmlns="x-schema:CIV4UnitSchema.xml">
    1<ProfessionInfos>
    2<ProfessionInfo>
    2 (all lines in between)
    2</ProfessionInfo>
    1</ProfessionInfos>
    0</Civ4ProfessionInfos>
    Add those to make the layout correct. However the civ4 xml engine has a big don't care for indents and it is mainly for human readability or in other words it's not important.

    It might be nicer to read the code if $desc is set before the first print command. That might also make it less prone to bugs when the script is modified for other xml files.

    As you can see Description, Civilopedia and Strategy are TXT enums meaning you can change the text later without messing with the setup itself. Also it makes it possible to translate if anybody fancies that at some point.

    I think the script should look like
    You could then consider adding those TXT strings using a script to make generic descriptions later. That might make it easier to fill in info. Actually the $desc string generation is for the TXT file generation.

    Ok, so there are a few minor issues to deal with in the script, but the core is in place and it produces something the game will actually accept and play with. I say you did good in writing this script :goodjob:
     
  4. orlanth

    orlanth Storm God. Yarr!

    Joined:
    Nov 17, 2001
    Messages:
    1,776
    lol thanks :cool: (I used Perl mainly to make it run even slower than bash:lol:)
    At this point Perl is actually my only really known language :old: except for fragments of Basic and Scheme which I'm not sure is used widely outside of Intro to CS courses :crazyeye: fortunately it has lots of regexp functionality good for text modification. I'm glad it worked since it can certainly get daunting to generate lots of new XML content by manual typing & copy/paste while avoiding tag errors, I think this is one thing that prevents people from trying total conversion mods that need lots of new content made. All the XML will still be a huge task to get through but hopefully somewhat more achievable:scan::king:
    Yeah, I'd intentionally suppressed extra tabs from the outermost 2 tags since they're not needed and those 2 tags aren't truly used as such (do we need both <CIV4ProfessionInfos> and <ProfessionInfos>, really Firaxis? :crazyeye::p). Anyway almost all manually cut/pasted XMLs from most mods out there (including my old 2071) inevitably get to be a mess of different haphazard tab levels, hopefully this will somewhat relieve that :lol:
    I actually did that semi-intentionally as well :mischief: When modding XML content, in my experience having to also open several TXT_KEY files for editing of Descriptions and Pedia and Strategy and make sure you have the right tags pasted, etc can often slow modding substantially and create reference errors. Now that this basic script is working, for the pre-release version all the English text for each content item can be done right in the XML file for that content, and moved later. Before release it'll be possible to use a similar script to grab text content from these tags and replace it with an appropriate TXT_KEY, while writing that TXT_KEY tag and text content to a text/xml file. (IIRC Dazio and isabelxxx made a similar script for their mod which they said helped them a lot.):cool:

    Yeah, the script would need to be modified anyway if you want it to fill out file-specific tags appropriately. The next major daunting chunk of new XML that needs to be generated would be Buildings, Buildingclasses and Specialbuildings so I'm hoping it will be possible to generate all of these appropriately via a single script. Another reason for scripts is to give some kind of algorithmic nature to the design and balancing of core content items, so things aren't determined haphazardly and get their costs and power too out of balance to be fun. For buildings, each processed yield will have 3 "levels" of a specialbuilding like in vanilla.

    level 1 : 50 hammers
    level 2 : 100 hammers, 50 tools
    level 3 : 200 hammers, 100 tools, 50 of Yield X
    where Yield X will generally be one of the other processed yields from that category (ie the advanced building for Plasmids would need 50 Enzymes, and vice versa).
    There will of course be some special or nonstandard buildings which will be added and balanced later but this will at least get in place functioning productionlines for the yields.:scan::science:
     
  5. Nightinggale

    Nightinggale Deity

    Joined:
    Feb 2, 2009
    Messages:
    4,354
    Bash is horribly slow. I once wrote a script to make statistics on some huge txt files. It took 20 minutes and due to limitations in bash it was a bit buggy. I rewrote the script into using perl instead and it exploited the much better features for coding structure in perl. It ended up doing the same task in somewhere between 30 and 60 seconds. Admittedly the bash script could have been written better, but nowhere near 20 times faster. Also I never finished the perl script completely as the need for it was rendered obsolete.

    The only really good things about bash is that it takes virtually no time to write and it can do anything you can do from the command line, including starting any CLI based application and listen to the output. This mean you can say call VLC and get the resolution and length of any movie file and the script is done in minutes. I would hate to do that in any other language.

    Well it's a candidate for being the best language to know if you know only one. You can write real applications with it as well as scripts. At the same time it's one of the languages where Bjarne Stroustrup (inventor of C++) says if you know one, you know them all. Moving from perl to say C++ is a minor step compared to learning either one in the first place.

    That's a fair layout decision. The broken indent has annoyed me a few times, specially when I want to read data with a script. It would have been much easier if I could just ignore the first X characters, but replace one tab with spaces and X is different :crazyeye:
    The dll reads ProfessionInfos and executes a function for each element (ProfessionInfo) in order to store that one in memory. That's a design decision, which I think makes the C++ code easier to handle. CIV4ProfessionInfos on the other hand appears to be just some extra junk. I don't feel like modifying the C++ code to skip it. Too much work and too high risk compared to what we gain.

    You do realize that the game ignores TXT_KEY commands if they aren't present, right? The game will then print the TXT_KEY whenever the string is requested ingame. This mean you can set your script to add all of them and then postpone actually adding those until later.

    It's bad practice to fill in junk, which needs to be replaced anyway in the next commit. It fills up the git history and makes it a bit harder to locate real changes.
     
  6. orlanth

    orlanth Storm God. Yarr!

    Joined:
    Nov 17, 2001
    Messages:
    1,776
    :scan::borg::science: wow, by applying ancient Progenitor technology I think I am now actually almost done with the core Buildings XML ! :nuke::goodjob:
    I won't commit the files to git yet since there's still tweaking to be done (also buildinginfos might change with your market changes etc), but here's the script I've worked on for them if you want to take an early look:
    Spoiler :

    Code:
    #!/usr/bin/perl
    # read content list, generate building XML for each content item
    
    use Lingua::EN::Inflect qw ( PL PL_N PL_V PL_ADJ NO NUM
                      A AN def_noun def_verb def_adj def_a def_an ); 
    def_noun "Facility"  => "Facilities";
    
    # input filenames
    print "List of content: ";
    chomp ($contentfile = <>);
    
    # grab yield names
    open (CONTENT, "< $contentfile") or die "Can't read content from $contentfile: $!";
    while (<CONTENT>) {
    	if ($_ =~ /YIELD_(\w+)<\/Type/) {
    		push (@content, $1);
    		}
    	}
    close CONTENT;
    
    # open XML for writing
    open (BI, "> CIV4BuildingInfos.xml") or die "Can't write output: $!";
    open (BCI, "> CIV4BuildingClassInfos.xml") or die "Can't write output: $!";
    open (SBI, "> CIV4SpecialBuildingInfos.xml") or die "Can't write output: $!";
    open (ADB, "> CIV4ArtDefines_Building.xml") or die "Can't write output: $!";
    
    # generate XML headers
    print BI '<?xml version="1.0"?>'."\n";
    print BI '<!-- edited with XMLSPY v2004 rel. 2 U (http://www.xmlspy.com) by Josh Scanlan (Firaxis Games) -->'."\n";
    print BI '<!-- Sid Meier\'s Civilization 4 -->'."\n".'<!-- Copyright Firaxis Games 2005 -->'."\n".'<!-- -->'."\n".'<!-- Building Infos -->'."\n";
    print BI '<Civ4BuildingInfos xmlns="x-schema:CIV4BuildingsSchema.xml">'."\n<BuildingInfos>\n";
    
    print BCI '<?xml version="1.0"?>'."\n";
    print BCI '<!-- edited with XMLSPY v2004 rel. 2 U (http://www.xmlspy.com) by Jason Winokur (Firaxis Games) -->'."\n";
    print BCI '<!-- Sid Meier\'s Civilization 4 -->'."\n".'<!-- Copyright Firaxis Games 2005 -->'."\n".'<!-- -->'."\n".'<!-- Building Class Infos -->'."\n";
    print BCI '<Civ4BuildingClassInfos xmlns="x-schema:CIV4BuildingsSchema.xml">'."\n<BuildingClassInfos>\n";
    
    print SBI '<?xml version="1.0"?>'."\n";
    print SBI '<!-- edited with XMLSPY v2004 rel. 2 U (http://www.xmlspy.com) by EXTREME (Firaxis Games) -->'."\n";
    print SBI '<!-- Sid Meier\'s Civilization 4 -->'."\n".'<!-- Copyright Firaxis Games 2005 -->'."\n".'<!-- -->'."\n".'<!-- Special Building -->'."\n";
    print SBI '<Civ4SpecialBuildingInfos xmlns="x-schema:CIV4BuildingsSchema.xml">'."\n<SpecialBuildingInfos>\n";
    
    print ADB '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'."\n";
    print ADB '<!-- edited with XMLSPY v2004 rel. 2 U (http://www.xmlspy.com) by Jason Winokur (Firaxis Games) -->'."\n";
    print ADB '<!-- Sid Meier\'s Civilization 4 -->'."\n".'<!-- Copyright Firaxis Games 2005 -->'."\n".'<!-- -->'."\n".'<!-- Building art path information -->'."\n";
    print ADB '<Civ4ArtDefines xmlns="x-schema:CIV4ArtDefinesSchema.xml">'."\n<BuildingArtInfos>\n";
    
    sub makeclass
    {
    	my $tag = $_[0];
    	my $bdesc = $_[1];
    	print BCI "<BuildingClassInfo>\n";
    	print BCI "\t<Type>BUILDINGCLASS_".$tag."</Type>\n";
    	print BCI "\t<Description>".$bdesc."</Description>\n";	
    	print BCI "\t<DefaultBuilding>BUILDING_".$tag."</DefaultBuilding>\n";
    	print BCI "\t<VictoryThresholds/>\n";
    	print BCI "</BuildingClassInfo>\n";
    }
    
    # generate XML content
    foreach $item (@content)
    	{
    	my $desc = $item;
    	$desc =~ tr/_/ /;
    	$desc =~ s/(\w+)/\u\L$1/g;
    	$index++;
    	
    	# specialbuilding for item
    	print SBI "<SpecialBuildingInfo>\n";	
    	print SBI "\t<Type>SPECIALBUILDING_".$item."</Type>\n";
    	print SBI "\t<Description>".$desc."</Description>\n";
    	print SBI "\t<bValid>1</bValid>\n";
    	print SBI "\t<FontButtonIndex>".$index."</FontButtonIndex>\n";
    	print SBI "\t<ProductionTraits/>\n";
    	print SBI "\t".'<Button>,/Art/Buttons/Yields/'.$item.'.dds</Button>'."\n";
    	print SBI "</SpecialBuildingInfo>\n";
    
    	# level 1
    	my $tag = $item.'1';
    	if ($tag=~/TOOLS/ or $tag=~/WEAPONS/ or $tag=~/ROBOTICS/) {$suffix = 'Workshop';}
    	else {$suffix = 'Facility'};
    	my $bdesc = $desc.' '.$suffix;
    	if (A($bdesc) =~ /^(\w+?) / ) {$article = $1;}
    	my $plural = $desc.' '.PL_N($suffix);
    	print BI "<BuildingInfo>\n";	
    	print BI "\t<Type>BUILDING_".$tag."</Type>\n";
    	print BI "\t<BuildingClass>BUILDINGCLASS_".$tag."</BuildingClass>\n";
    	print BI "\t<SpecialBuildingType>SPECIALBUILDING_".$item."</SpecialBuildingType>\n";
    	print BI "\t<iSpecialBuildingPriority>0</iSpecialBuildingPriority>\n";
    	print BI "\t<Description>".$bdesc."</Description>\n";
    	print BI "\t<Civilopedia>".ucfirst($article).' [BOLD]'.$bdesc.'[\BOLD] allows basic production of [LINK=YIELD_'.$item.']'.$desc.'[\LINK] by citizens working in the [LINK=PROFESSION_'.$item.']'.$desc.'[\LINK] profession.[NEWLINE][PARAGRAPH:1]While the Earth superpowers initially maintained tight control over the complex and highly profitable production of '.$desc.' from raw materials imported from the New Worlds, development of the first small-scale '.$plural." by Human colonists and Alien empires eventually began to challenge Earth's previously unassailable monopoly.</Civilopedia>\n";
    	print BI "\t<Strategy>Build ".$article." to allow basic production of ".$desc."</Strategy>\n";
    	print BI "\t<ArtDefineTag>ART_DEF_BUILDING_".$tag."</ArtDefineTag>\n";
    	print BI "\t<MovieDefineTag>NONE</MovieDefineTag>\n";
    	print BI "\t<VictoryPrereq>NONE</VictoryPrereq>\n";
    	print BI "\t<FreeStartEra>NONE</FreeStartEra>\n";
    	print BI "\t<MaxStartEra>NONE</MaxStartEra>\n";
    	print BI "\t<iCityType/>\n";
    	print BI "\t<ProductionTraits/>\n";
    	print BI "\t<FreePromotion>NONE</FreePromotion>\n";
    	print BI "\t<bGraphicalOnly>0</bGraphicalOnly>\n";
    	print BI "\t<bWorksWater>0</bWorksWater>\n";
    	print BI "\t<bWater>0</bWater>\n";
    	print BI "\t<bRiver>0</bRiver>\n";
    	print BI "\t<bCapital>0</bCapital>\n";
    	print BI "\t<bNeverCapture>0</bNeverCapture>\n";
    	print BI "\t<bCenterInCity>0</bCenterInCity>\n";
    	print BI "\t<iAIWeight>0</iAIWeight>\n";
    	print BI "\t<YieldCosts>\n";
    	print BI "\t\t<YieldCost>\n";
    	print BI "\t\t\t<YieldType>YIELD_HAMMERS</YieldType>\n";	
    	print BI "\t\t\t<iCost>50</iCost>\n";	
    	print BI "\t\t</YieldCost>\n";
    	print BI "\t</YieldCosts>\n";
    	print BI "\t<iHurryCostModifier>0</iHurryCostModifier>\n";
    	print BI "\t<iAdvancedStartCost>0</iAdvancedStartCost>\n";
    	print BI "\t<iAdvancedStartCostIncrease>0</iAdvancedStartCostIncrease>\n";
    	print BI "\t<iProfessionOutput>3</iProfessionOutput>\n";
    	print BI "\t<iMaxWorkers>2</iMaxWorkers>\n";
    	print BI "\t<iMinAreaSize>-1</iMinAreaSize>\n";
    	print BI "\t<iConquestProb>0</iConquestProb>\n";
    	print BI "\t<iCitiesPrereq>0</iCitiesPrereq>\n";
    	print BI "\t<iTeamsPrereq>0</iTeamsPrereq>\n";
    	print BI "\t<iLevelPrereq>0</iLevelPrereq>\n";
    	print BI "\t<iMinLatitude>0</iMinLatitude>\n";
    	print BI "\t<iMaxLatitude>90</iMaxLatitude>\n";
    	print BI "\t<iExperience>0</iExperience>\n";
    	print BI "\t<iFoodKept>0</iFoodKept>\n";
    	print BI "\t<iHealRateChange>0</iHealRateChange>\n";
    	print BI "\t<iMilitaryProductionModifier>0</iMilitaryProductionModifier>\n";
    	print BI "\t<iDefense>0</iDefense>\n";
    	print BI "\t<iBombardDefense>0</iBombardDefense>\n";
    	print BI "\t<iAsset>50</iAsset>\n";
    	print BI "\t<iPower>0</iPower>\n";
    	print BI "\t<iYieldStorage>0</iYieldStorage>\n";
    	print BI "\t<iOverflowSellPercent>0</iOverflowSellPercent>\n";
    	print BI "\t<fVisibilityPriority>1.0</fVisibilityPriority>\n";
    	print BI "\t<SeaPlotYieldChanges/>\n";	
    	print BI "\t<RiverPlotYieldChanges/>\n";
    	print BI "\t<YieldChanges/>\n";
    	print BI "\t<YieldModifiers>\n";
    	print BI "\t\t<YieldModifier>\n";
    	print BI "\t\t\t<YieldType>YIELD_".$item."</YieldType>\n";	
    	print BI "\t\t\t<iModifier>0</iModifier>\n";	
    	print BI "\t\t</YieldModifier>\n";
    	print BI "\t</YieldModifiers>\n";
    	print BI "\t<ConstructSound/>\n";
    	print BI "\t<UnitCombatFreeExperiences/>\n";
    	print BI "\t<DomainFreeExperiences/>\n";
    	print BI "\t<DomainProductionModifiers/>\n";
    	print BI "\t<PrereqBuildingClasses/>\n";
    	print BI "\t<BuildingClassNeededs/>\n";
    	print BI "\t<AutoSellsYields/>\n";
    	print BI "\t<HotKey/>\n";
    	print BI "\t<bAltDown>0</bAltDown>\n";	
    	print BI "\t<bShiftDown>0</bShiftDown>\n";
    	print BI "\t<bCtrlDown>0</bCtrlDown>\n";
    	print BI "\t<iHotKeyPriority>0</iHotKeyPriority>\n";
    	print BI "</BuildingInfo>\n";
    
    	&makeclass($tag, $bdesc);
    
    	print ADB "<BuildingArtInfo>\n";
    	print ADB "\t<Type>ART_DEF_BUILDING_".$tag."</Type>\n";
    	print ADB "\t<LSystem>LSYSTEM_1x1</LSystem>\n";
    	print ADB "\t<bAnimated>0</bAnimated>\n";
    	print ADB "\t<CityTexture>Art/Buttons/Buildings/".$tag.'.dds</CityTexture>'."\n";
    	print ADB "\t<CitySelectedTexture>".',IS,FILLER,TEXT</CitySelectedTexture>'."\n";
    	print ADB "\t<fScale>1.0</fScale>\n";
    	print ADB "\t<fInterfaceScale>0.5</fInterfaceScale>\n";
    	print ADB "\t<NIF>Art/Buildings/".$item.'/'.$tag.'.nif</NIF>'."\n";
    	print ADB "\t<KFM/>\n";
    	print ADB "\t<Button>Art/Buttons/Buildings/".$tag.'.dds</Button>'."\n";
    	print ADB "</BuildingArtInfo>\n";
    
    	# level 2
    	my $tag = $item.'2';
    	if ($tag=~/TOOLS/ or $tag=~/WEAPONS/ or $tag=~/ROBOTICS/) {$suffix = 'Plant';}
    		elsif ($tag=~/NARCOTICS/ or $tag=~/BIOWEAPONS/ or $tag=~/PHARMACEUTICALS/ or $tag=~/PETROCHEMICALS/ or $tag=~/COLLOIDS/ or $tag=~/CATALYSTS/) {$suffix = 'Refinery';}
    		else {$suffix = 'Lab';}
    	my $bdesc = $desc.' '.$suffix;
    	if (A($bdesc) =~ /^(\w+?) / ) {$article = $1;}
    	my $plural = $desc.' '.PL_N($suffix);
    	print BI "<BuildingInfo>\n";	
    	print BI "\t<Type>BUILDING_".$tag."</Type>\n";
    	print BI "\t<BuildingClass>BUILDINGCLASS_".$tag."</BuildingClass>\n";
    	print BI "\t<SpecialBuildingType>SPECIALBUILDING_".$item."</SpecialBuildingType>\n";
    	print BI "\t<iSpecialBuildingPriority>1</iSpecialBuildingPriority>\n";
    	print BI "\t<Description>".$bdesc."</Description>\n";
    	print BI "\t<Civilopedia>".ucfirst($article).' [BOLD]'.$bdesc.'[\BOLD] enhances production of [LINK=YIELD_'.$item.']'.$desc.'[\LINK] by citizens working in the [LINK=PROFESSION_'.$item.']'.$desc.'[\LINK] profession.[NEWLINE][PARAGRAPH:1]By leveraging their growing industrial base to encompass the construction of '.$plural.', Human colonies and Alien empires became increasingly able to produce '.$desc." more efficiently and on a larger scale, furthering their economic independence from the mercantilist industries of Earth.</Civilopedia>\n";
    	print BI "\t<Strategy>Build ".$article." to allow more efficient production of ".$desc."</Strategy>\n";
    	print BI "\t<ArtDefineTag>ART_DEF_BUILDING_".$tag."</ArtDefineTag>\n";
    	print BI "\t<MovieDefineTag>NONE</MovieDefineTag>\n";
    	print BI "\t<VictoryPrereq>NONE</VictoryPrereq>\n";
    	print BI "\t<FreeStartEra>NONE</FreeStartEra>\n";
    	print BI "\t<MaxStartEra>NONE</MaxStartEra>\n";
    	print BI "\t<iCityType/>\n";
    	print BI "\t<ProductionTraits/>\n";
    	print BI "\t<FreePromotion>NONE</FreePromotion>\n";
    	print BI "\t<bGraphicalOnly>0</bGraphicalOnly>\n";
    	print BI "\t<bWorksWater>0</bWorksWater>\n";
    	print BI "\t<bWater>0</bWater>\n";
    	print BI "\t<bRiver>0</bRiver>\n";
    	print BI "\t<bCapital>0</bCapital>\n";
    	print BI "\t<bNeverCapture>0</bNeverCapture>\n";
    	print BI "\t<bCenterInCity>0</bCenterInCity>\n";
    	print BI "\t<iAIWeight>0</iAIWeight>\n";
    	print BI "\t<YieldCosts>\n";
    	print BI "\t\t<YieldCost>\n";
    	print BI "\t\t\t<YieldType>YIELD_HAMMERS</YieldType>\n";	
    	print BI "\t\t\t<iCost>100</iCost>\n";	
    	print BI "\t\t</YieldCost>\n";
    	print BI "\t\t<YieldCost>\n";
    	print BI "\t\t\t<YieldType>YIELD_TOOLS</YieldType>\n";	
    	print BI "\t\t\t<iCost>50</iCost>\n";	
    	print BI "\t\t</YieldCost>\n";
    	print BI "\t</YieldCosts>\n";
    	print BI "\t<iHurryCostModifier>0</iHurryCostModifier>\n";
    	print BI "\t<iAdvancedStartCost>0</iAdvancedStartCost>\n";
    	print BI "\t<iAdvancedStartCostIncrease>0</iAdvancedStartCostIncrease>\n";
    	print BI "\t<iProfessionOutput>6</iProfessionOutput>\n";
    	print BI "\t<iMaxWorkers>3</iMaxWorkers>\n";
    	print BI "\t<iMinAreaSize>-1</iMinAreaSize>\n";
    	print BI "\t<iConquestProb>0</iConquestProb>\n";
    	print BI "\t<iCitiesPrereq>0</iCitiesPrereq>\n";
    	print BI "\t<iTeamsPrereq>0</iTeamsPrereq>\n";
    	print BI "\t<iLevelPrereq>0</iLevelPrereq>\n";
    	print BI "\t<iMinLatitude>0</iMinLatitude>\n";
    	print BI "\t<iMaxLatitude>90</iMaxLatitude>\n";
    	print BI "\t<iExperience>0</iExperience>\n";
    	print BI "\t<iFoodKept>0</iFoodKept>\n";
    	print BI "\t<iHealRateChange>0</iHealRateChange>\n";
    	print BI "\t<iMilitaryProductionModifier>0</iMilitaryProductionModifier>\n";
    	print BI "\t<iDefense>0</iDefense>\n";
    	print BI "\t<iBombardDefense>0</iBombardDefense>\n";
    	print BI "\t<iAsset>100</iAsset>\n";
    	print BI "\t<iPower>0</iPower>\n";
    	print BI "\t<iYieldStorage>0</iYieldStorage>\n";
    	print BI "\t<iOverflowSellPercent>0</iOverflowSellPercent>\n";
    	print BI "\t<fVisibilityPriority>1.0</fVisibilityPriority>\n";
    	print BI "\t<SeaPlotYieldChanges/>\n";	
    	print BI "\t<RiverPlotYieldChanges/>\n";
    	print BI "\t<YieldChanges/>\n";
    	print BI "\t<YieldModifiers>\n";
    	print BI "\t\t<YieldModifier>\n";
    	print BI "\t\t\t<YieldType>YIELD_".$item."</YieldType>\n";	
    	print BI "\t\t\t<iModifier>25</iModifier>\n";	
    	print BI "\t\t</YieldModifier>\n";
    	print BI "\t</YieldModifiers>\n";
    	print BI "\t<ConstructSound/>\n";
    	print BI "\t<UnitCombatFreeExperiences/>\n";
    	print BI "\t<DomainFreeExperiences/>\n";
    	print BI "\t<DomainProductionModifiers/>\n";
    	print BI "\t<PrereqBuildingClasses/>\n";
    	print BI "\t<BuildingClassNeededs>\n";
    	print BI "\t\t<BuildingClassNeeded>\n";
    	print BI "\t\t\t<BuildingClassType>BUILDINGCLASS_".$item."1</BuildingClassType>\n";
    	print BI "\t\t\t<bNeededInCity>1</bNeededInCity>\n";
    	print BI "\t\t</BuildingClassNeeded>\n";
    	print BI "\t</BuildingClassNeededs>\n";
    	print BI "\t<AutoSellsYields/>\n";
    	print BI "\t<HotKey/>\n";
    	print BI "\t<bAltDown>0</bAltDown>\n";	
    	print BI "\t<bShiftDown>0</bShiftDown>\n";
    	print BI "\t<bCtrlDown>0</bCtrlDown>\n";
    	print BI "\t<iHotKeyPriority>0</iHotKeyPriority>\n";
    	print BI "</BuildingInfo>\n";
    
    	&makeclass($tag, $bdesc);
    
    	print ADB "<BuildingArtInfo>\n";
    	print ADB "\t<Type>ART_DEF_BUILDING_".$tag."</Type>\n";
    	print ADB "\t<LSystem>LSYSTEM_2x1</LSystem>\n";
    	print ADB "\t<bAnimated>0</bAnimated>\n";
    	print ADB "\t<CityTexture>Art/Buttons/Buildings/".$tag.'.dds</CityTexture>'."\n";
    	print ADB "\t<CitySelectedTexture>".',IS,FILLER,TEXT</CitySelectedTexture>'."\n";
    	print ADB "\t<fScale>1.05</fScale>\n";
    	print ADB "\t<fInterfaceScale>0.55</fInterfaceScale>\n";
    	print ADB "\t<NIF>Art/Buildings/".$item.'/'.$tag.'.nif</NIF>'."\n";
    	print ADB "\t<KFM/>\n";
    	print ADB "\t<Button>Art/Buttons/Buildings/".$tag.'.dds</Button>'."\n";
    	print ADB "</BuildingArtInfo>\n";
    
    	# level 3
    	my $tag = $item.'3';
    	if ($tag=~/TOOLS/ or $tag=~/WEAPONS/ or $tag=~/ROBOTICS/ or $tag=~/SEMICONDUCTORS/) {$suffix = 'Foundry';}
    		elsif ($tag=~/PLASMIDS/ or $tag=~/ENZYMES/ or $tag=~/PROGENITOR_TECH/ or $tag=~/ALIEN_RELICS/ or $tag=~/STATE_SECRETS/ or $tag=~/MICROBES/) {$suffix = 'Institute';}
    		else {$suffix = 'Complex';}
    	my $bdesc = $desc.' '.$suffix;
    	if (A($bdesc) =~ /^(\w+?) / ) {$article = $1;}
    	my $plural = $desc.' '.PL_N($suffix);
    	print BI "<BuildingInfo>\n";	
    	print BI "\t<Type>BUILDING_".$tag."</Type>\n";
    	print BI "\t<BuildingClass>BUILDINGCLASS_".$tag."</BuildingClass>\n";
    	print BI "\t<SpecialBuildingType>SPECIALBUILDING_".$item."</SpecialBuildingType>\n";
    	print BI "\t<iSpecialBuildingPriority>2</iSpecialBuildingPriority>\n";
    	print BI "\t<Description>".$bdesc."</Description>\n";
    	print BI "\t<Civilopedia>".ucfirst($article).' [BOLD]'.$bdesc.'[\BOLD] enables highly efficient large-scale production of [LINK=YIELD_'.$item.']'.$desc.'[\LINK] by citizens working in the [LINK=PROFESSION_'.$item.']'.$desc.'[\LINK] profession.[NEWLINE][PARAGRAPH:1]The growing technological sophistication and infrastructure of several Human colonies and Alien empires eventually enabled the construction of large '.$plural." which could produce '.$desc.' far more efficiently than the aging industrial base of Earth.</Civilopedia>\n";
    	print BI "\t<Strategy>Build ".$article." to maximize production of ".$desc."</Strategy>\n";
    	print BI "\t<ArtDefineTag>ART_DEF_BUILDING_".$tag."</ArtDefineTag>\n";
    	print BI "\t<MovieDefineTag>NONE</MovieDefineTag>\n";
    	print BI "\t<VictoryPrereq>NONE</VictoryPrereq>\n";
    	print BI "\t<FreeStartEra>NONE</FreeStartEra>\n";
    	print BI "\t<MaxStartEra>NONE</MaxStartEra>\n";
    	print BI "\t<iCityType/>\n";
    	print BI "\t<ProductionTraits/>\n";
    	print BI "\t<FreePromotion>NONE</FreePromotion>\n";
    	print BI "\t<bGraphicalOnly>0</bGraphicalOnly>\n";
    	print BI "\t<bWorksWater>0</bWorksWater>\n";
    	print BI "\t<bWater>0</bWater>\n";
    	print BI "\t<bRiver>0</bRiver>\n";
    	print BI "\t<bCapital>0</bCapital>\n";
    	print BI "\t<bNeverCapture>0</bNeverCapture>\n";
    	print BI "\t<bCenterInCity>0</bCenterInCity>\n";
    	print BI "\t<iAIWeight>0</iAIWeight>\n";
    	print BI "\t<YieldCosts>\n";
    	print BI "\t\t<YieldCost>\n";
    	print BI "\t\t\t<YieldType>YIELD_HAMMERS</YieldType>\n";	
    	print BI "\t\t\t<iCost>200</iCost>\n";	
    	print BI "\t\t</YieldCost>\n";
    	print BI "\t\t<YieldCost>\n";
    	print BI "\t\t\t<YieldType>YIELD_TOOLS</YieldType>\n";	
    	print BI "\t\t\t<iCost>100</iCost>\n";	
    	print BI "\t\t</YieldCost>\n";
    	print BI "\t\t<YieldCost>\n";
    	print BI "\t\t\t<YieldType>YIELD_EARTH_GOODS</YieldType>\n";	
    	print BI "\t\t\t<iCost>50</iCost>\n";	
    	print BI "\t\t</YieldCost>\n";
    	print BI "\t</YieldCosts>\n";
    	print BI "\t<iHurryCostModifier>0</iHurryCostModifier>\n";
    	print BI "\t<iAdvancedStartCost>0</iAdvancedStartCost>\n";
    	print BI "\t<iAdvancedStartCostIncrease>0</iAdvancedStartCostIncrease>\n";
    	print BI "\t<iProfessionOutput>6</iProfessionOutput>\n";
    	print BI "\t<iMaxWorkers>5</iMaxWorkers>\n";
    	print BI "\t<iMinAreaSize>-1</iMinAreaSize>\n";
    	print BI "\t<iConquestProb>0</iConquestProb>\n";
    	print BI "\t<iCitiesPrereq>0</iCitiesPrereq>\n";
    	print BI "\t<iTeamsPrereq>0</iTeamsPrereq>\n";
    	print BI "\t<iLevelPrereq>0</iLevelPrereq>\n";
    	print BI "\t<iMinLatitude>0</iMinLatitude>\n";
    	print BI "\t<iMaxLatitude>90</iMaxLatitude>\n";
    	print BI "\t<iExperience>0</iExperience>\n";
    	print BI "\t<iFoodKept>0</iFoodKept>\n";
    	print BI "\t<iHealRateChange>0</iHealRateChange>\n";
    	print BI "\t<iMilitaryProductionModifier>0</iMilitaryProductionModifier>\n";
    	print BI "\t<iDefense>0</iDefense>\n";
    	print BI "\t<iBombardDefense>0</iBombardDefense>\n";
    	print BI "\t<iAsset>200</iAsset>\n";
    	print BI "\t<iPower>0</iPower>\n";
    	print BI "\t<iYieldStorage>0</iYieldStorage>\n";
    	print BI "\t<iOverflowSellPercent>0</iOverflowSellPercent>\n";
    	print BI "\t<fVisibilityPriority>1.0</fVisibilityPriority>\n";
    	print BI "\t<SeaPlotYieldChanges/>\n";	
    	print BI "\t<RiverPlotYieldChanges/>\n";
    	print BI "\t<YieldChanges/>\n";
    	print BI "\t<YieldModifiers>\n";
    	print BI "\t\t<YieldModifier>\n";
    	print BI "\t\t\t<YieldType>YIELD_".$item."</YieldType>\n";	
    	print BI "\t\t\t<iModifier>50</iModifier>\n";	
    	print BI "\t\t</YieldModifier>\n";
    	print BI "\t</YieldModifiers>\n";
    	print BI "\t<ConstructSound/>\n";
    	print BI "\t<UnitCombatFreeExperiences/>\n";
    	print BI "\t<DomainFreeExperiences/>\n";
    	print BI "\t<DomainProductionModifiers/>\n";
    	print BI "\t<PrereqBuildingClasses/>\n";
    	print BI "\t<BuildingClassNeededs>\n";
    	print BI "\t\t<BuildingClassNeeded>\n";
    	print BI "\t\t\t<BuildingClassType>BUILDINGCLASS_".$item."2</BuildingClassType>\n";
    	print BI "\t\t\t<bNeededInCity>1</bNeededInCity>\n";
    	print BI "\t\t</BuildingClassNeeded>\n";
    	print BI "\t</BuildingClassNeededs>\n";
    	print BI "\t<AutoSellsYields/>\n";
    	print BI "\t<HotKey/>\n";
    	print BI "\t<bAltDown>0</bAltDown>\n";	
    	print BI "\t<bShiftDown>0</bShiftDown>\n";
    	print BI "\t<bCtrlDown>0</bCtrlDown>\n";
    	print BI "\t<iHotKeyPriority>0</iHotKeyPriority>\n";
    	print BI "</BuildingInfo>\n";
    
    	&makeclass($tag, $bdesc);
    
    	print ADB "<BuildingArtInfo>\n";
    	print ADB "\t<Type>ART_DEF_BUILDING_".$tag."</Type>\n";
    	print ADB "\t<LSystem>LSYSTEM_2x2</LSystem>\n";
    	print ADB "\t<bAnimated>0</bAnimated>\n";
    	print ADB "\t<CityTexture>Art/Buttons/Buildings/".$tag.'.dds</CityTexture>'."\n";
    	print ADB "\t<CitySelectedTexture>".',IS,FILLER,TEXT</CitySelectedTexture>'."\n";
    	print ADB "\t<fScale>1.1</fScale>\n";
    	print ADB "\t<fInterfaceScale>0.6</fInterfaceScale>\n";
    	print ADB "\t<NIF>Art/Buildings/".$item.'/'.$tag.'.nif</NIF>'."\n";
    	print ADB "\t<KFM/>\n";
    	print ADB "\t<Button>Art/Buttons/Buildings/".$tag.'.dds</Button>'."\n";
    	print ADB "</BuildingArtInfo>\n";
    
    	}	
    	
    # closing tags
    print BI '</BuildingInfos>'."\n</Civ4BuildingInfos>\n";
    close BI;
    print BCI '</BuildingClassInfos>'."\n</Civ4BuildingClassInfos>\n";
    close BCI;
    print SBI '</SpecialBuildingInfos>'."\n</Civ4SpecialBuildingInfos>\n";
    close SBI;
    print ADB '</BuildingArtInfos>'."\n</Civ4ArtDefines>\n";
    close ADB;
    It takes a list of Yields (should provide it with only the "processed" ones) and generates XML for the appropriate Specialbuildings and three levels of BuildingInfos and BuildingClasses with the corresponding BuildingArtDefs . Phew, this would've taken me literally months of manual XML editing and introducing and fixing tag reference errors! :crazyeye: Maybe I could improve by making it more modular with subroutines etc, but this lets you easily specify all the stats for each of the three building "levels" in a standardized way and adjust/rebalance these simultaneously however desired.

    I'm trying to have the scripts also generate some appropriate text for the Description and Pedia (including some autogenerated Pedia hyperlinks to the related yields and professions) which we could then edit as desired. (I've used Perl Lingua::EN::Inflect to generate plurals and articles in the text, but was a little disappointed that it didn't seem to know how to pluralise Facilities.. :crazyeye:) In ProfessionsInfos, I think Help and Strategy are never actually displayed by the game AFAIK, so I guess those should be left blank.
     
  7. orlanth

    orlanth Storm God. Yarr!

    Joined:
    Nov 17, 2001
    Messages:
    1,776
    I've worked further on some scripts to aid in generating much of the heavy amount of core XML content needed for total conversion modding.

    Currently these can generate and pre-populate XML files for yields, professions, units, and unitclasses, and also create specialbuildings and 3 tiers of buildings and buildingclasses for each yield produced inside cities. They also generate xml artdefines for buildings and units and reference these from the appropriate files. Some appropriate standard text is generated for Description, Strategy, and Pedia, including autogenerated hyperlinks to related Pedia pages, and most of these are now moved to a separate text XML via TXT_KEY references in the original files.

    I don't think it'd probably make sense to try using scripts for much more than these; and the scripts still need improvement and there's still a lot of work to be done in editing & adding to the core content that's generated. But hopefully these can give total conversion modders a big initial boost in establishing a large chunk of the core XML content necessary for modding, which can then gradually be added to and edited as desired. :scan::cool::scan:
     
  8. Nightinggale

    Nightinggale Deity

    Joined:
    Feb 2, 2009
    Messages:
    4,354
    You did month's worth of work in one day and then no commits.... you are slowing down. I had already planned to play the finished MOD next weekend :cry:

    Sounds like your scripts is starting to be more advanced than mine. Then again we aim for different goals, which naturally will result in different scripts. Using Lingua::EN::Inflect didn't cross my mind at all.

    I looked at the C++ code for strategy. It's part of CvBaseInfo meaning it's present for more or less everything from XML. However it appears that only BuildingInfo, UnitInfo and CivicInfo use it. The first two only use it for "Sid's tips" and the affected code will be skipped if the string is empty. Civics (inventions) appears to assume the strategy is always set and use it for argument 4 in TXT_KEY_CENSURE_EXCOMMUNICATION.

    Apart from that it doesn't look like strategy is used at all. We could change that, but I don't see the point. Time could be better spend elsewhere.
     
  9. orlanth

    orlanth Storm God. Yarr!

    Joined:
    Nov 17, 2001
    Messages:
    1,776
    It's getting to be quite a lot of XML (attached) :crazyeye: .. do you think I should commit it all to git already? Maybe it should wait until we can be sure there are no leftover errors from missing hardcoded M:C-specific content with the current "skeleton" version; I'd guess it will become harder to troubleshoot for that once this large amount of content is added. But if you want, it could be a good time to apply your bash scripts to the attached yields xml to get the cpp and header ready for it.:scan:
     
  10. Nightinggale

    Nightinggale Deity

    Joined:
    Feb 2, 2009
    Messages:
    4,354
    When adding a new variable to GlobalDefinesALT.xml I ended up not using the cache as it appears a bit complex. This is no good and now I redesigned the whole cache to make it easier to add/remove what to cache.

    As a bonus it's easier to see which XML tags the DLL use. In CvEnums.h there is a new enum called XMLconstantTypes (at the end). This one contains a list of all tags being read, be it from modded files or vanilla. It could use some more comments on what they actually do, but at least the list is there. The plan is that the enum value should be used whenever the XML tag is used as it not only makes the code noteworthy faster, but also enables searching for the enum value and that way find all places where it's used and through that way figure out what it does. Right now a few places reads data from XML without using the enum, but that will hopefully be fixed in the near future.

    The cache is set in CvGlobals::cacheXMLval() meaning caching a new value means adding 2 lines, one in each file.

    While looking at what is cached I say we need to clean it. For instance CULTURE_YIELD is set to YIELD_CULTURE in GlobalDefinesALT. I changed it to use YIELD_CULTURE enum value in the DLL (performance). However we can't avoid it as python still reads CULTURE_YIELD.

    UNITARMOR_MAIL is in CIV4UnitCombatInfos while UNITARMOR_PLATE is in GlobalDefinesALT. Not only would I prefer them to be defined in the same file, I would also like to get rid of them in the DLL. I could keep on going, but it isn't high priority issues.

    Sounds like you really should commit now. Maybe you should have committed a while ago. It's an open question when you should commit something, but if you ask me I say first you committed a bit too much (needed TXT_KEY set first) and now you did too much at once. Try to think about the history of the code. When you look for a specific change, you shouldn't have too many commits as it makes it tricky to find the right one. At the same time most or all related changes should be in the same as when you look at one commit in the log and see the changes, you should see related changes meaning you get a list of all code for feature X.

    Also when committing to the C++ source, you commit to the M:C log. Try to start the commit message with "2071: " as it will make those commits easier to spot like I did here: https://github.com/Nightinggale/Medieval_Tech/commit/7be30746581d1baca96fb4c472bb79dd48c84a42
    No real bad commit messages have appeared so far, but using at least this little standard would be an improvement, specially if we all use it ;)

    When to commit is often a hot topic and even experienced people argue or even fight over this topic.
     
  11. orlanth

    orlanth Storm God. Yarr!

    Joined:
    Nov 17, 2001
    Messages:
    1,776
    ok, I went ahead and committed a whole slug of XML.. :crazyeye::scan: I've replaced the last remaining vanilla XML yield tags, so an updated DLL cpp and header would need to be generated using your bash scripts. (edit: on second thought, will it cause problems that I renamed YIELD_HAMMERS to YIELD_INDUSTRY ? All the "abstract" non-cargo yield types are ordered after that yield as was the case with Hammers.) The abstract yields are Media (Crosses), Liberty (Bells), Research (Ideas), Education (Education), Influence (Culture), Credits (Gold), and two new abstract yields for 2071, Energy and Pollutants.

    The XML files have lots of cross-references between each other so its often difficult to add things efficiently in a stepwise manner while keeping all the referenced tags correct. (eg to add one new building you'd need to edit buildings xml and buildingclass xml, and specialbuildings if needed, add TXT_KEY references and ArtDef refererences in each of those files, then edit the Text xml and Artdef xml files with the appropriate content and paths, then edit every civilization you've made if you don't want them all getting access to it.) With this script, the core layout for all these cross referenced xml files are created by xmlgen.pl in one go, and their individual stats can then be adjusted as desired. Many of the buildings currently have placeholder names in the description (eg "Lab" for most 2nd-tier production buildings), but these are all in TXT_KEYs so will be easy to edit prior to release.) :cool:
     
  12. Nightinggale

    Nightinggale Deity

    Joined:
    Feb 2, 2009
    Messages:
    4,354
    Yes. YIELD_HAMMERS and everything after that one in M:C is assumed to be present. We could change that, but it would likely be easier just to stick to the M:C names. The code and specially the AI code have special cases for all the virtual yields, which is why they assume the names to be present. Also the python scripts tend to have those names hardcoded.

    However if you look at Yields_Colonization_2071.h we do have these lines
    We can add lines like that for virtual yields as well and all will be good. I will modify the exposure to python (mainly modify my script) to always expose the M:C virtual yieldnames to python. We could expose both names to python, but I think it would be best if we don't. Imagine a 2071 python change, which uses YIELD_INDUSTRY. It would cause M:C problems, which wouldn't appear if it used YIELD_HAMMERS. It would be silly to lose compatibility if this is the only problem.

    I think I will have the new script done and committed the new yields within the next 24 hours (hopefully less than that). You shouldn't have that excuse for not working during the weekend :p
     
  13. Nightinggale

    Nightinggale Deity

    Joined:
    Feb 2, 2009
    Messages:
    4,354
    I committed the new yields. Now it's only YIELD_EDUCATION, which is the same as M:C, which really wasn't the plan, but we can handle that. Python still use the M:C names for those yields.

    2071 now has 57 yields, way more than M:C's 34 :eek:
    I think RaR has something like 57 as well.
     
  14. Nightinggale

    Nightinggale Deity

    Joined:
    Feb 2, 2009
    Messages:
    4,354
    I looked into how armor is made and found a number of issues.

    All armors have their own UnitCombatInfo. I don't think that was the intension of that class. It's more like a class giving details about say mounted, which in turn is used to give bonus vs mounted. It's just basic info meaning they really don't have much to them at all.

    CIV4UnitCombatInfos fails to add Type into the storage, which getDefineINT() reads from (vanilla bug or intended?). This is both good and bad. Good because the less defines we have, the faster getDefineINT() is. Bad because it mean lines like GC.getDefineINT("UNITARMOR_LEATHER") returns 0 instead of the expected 9. Some of the C++ code is broken because of this. Luckily it is just the Pedia setup code, no real ingame bugs.

    I propose that we get rid of a most of the UnitCombatInfos. Instead we add the info to ProfessionInfo.
    UNITTACTIC_PARRY, UNITARMOR_SHIELD, UNITWEAPON_BLUNT
    Those appears to be just bools, which we can add to professions.

    Crushing Blow and Glancing Blow are also bools, which could be added to profession.

    However I came up with another idea. We could add such bools to yields. That way we could make the game give those features to any unit, which requires YIELD_PLATE_ARMOR. This mean it can automatically give those bonuses to units for alt equipment without setting up anything than just yield requirements.

    Both solutions mean we can get rid of any mentioning of specific armors in the DLL. We can also allow units to use multiple armors at once if we like, say using YIELD_TARGETING_COMPUTER and YIELD_EXPLOSIVE_AMMO at the same time or whatever. It gives a high degree of modding freedom without changing the DLL.

    Alternatively we can move all the code to free promotions. This would be the easiest solution from a coding point of view. However I'm not sure I like it as we will end up with a lot of promotions even units with 0 xp and units with experience will be harder to spot.

    What do you guys say to this?


    Also I realized that while yield requirements for professions are cached, yield requirements for alt equipment is uncached. Luckily that shouldn't be too difficult to fix and with a noteworthy speed boost to follow.

    I noticed one potential bug/limitation in the yield equipment cache. If the profession needs no yields for the base, then the game will assume the alternative also uses no yields for performance reasons. The easy solution is not to make a profession with that combo. I might fix this as I make a cache for the alt equipment anyway.
     
  15. orlanth

    orlanth Storm God. Yarr!

    Joined:
    Nov 17, 2001
    Messages:
    1,776
    Nightingale, where are the new buildinginfos.xml tags like <YieldDemands> supposed to fit in the XML? :confused: The new tags don't appear yet in the M:C XML itself, and it's hard to tell from the schema where they should go. I tried placing <YieldDemands> above <iMinAreaSize> or above <ConstructSound> but keep getting fatal XML loading errors each time from being out of the order it's expecting.

    It might be easiest to include one "example" <Buildinginfo> item in the M:C XML file that includes all possible tags for that file in the expected loading order. (In making xmlgen script I can copy the correct format directly from XML files and add appropriate output commands in Textpad).

    On loading, it also gives a string of asserts expecting M:C Yield tagnames, eg:
    It looks like your dll files are set up appropriately with 2071 tagnames, so I'm not sure why that's still the case :confused:

    From a moddability perspective as well, I think the most flexible and robust method would be to let the combat features be handled by Promotions. With this, you could use the existing tags (including AltEquipmentTypes and AltFreePromotions) to let units and/or professions inherit these in any way the modder wants. Even better, you'd also automatically have the ability to do things like make a Tech or Founding Father that grants them to certain units or professions.

    edit: one advantage of the UnitCombats in CIV4UnitCombatInfos is you can create units or promotions which have a bonus against anything within a UnitCombat group; and you can also restrict certain Promotions to particular UnitCombats. I don't know how Kailric handled it, but if units can effectively belong to more than one UnitCombat group it's rather a nice feature. (You can create professions with more than one "category" eg Mounted and Heavy Armor for M:C Knights, and have units, professions and promos give bonuses against a certain category, adding lots of strategic depth to unit design.):cool: So it could be worth retaining the ability to let units/professions have more than one UnitCombat, even if abilities are handled by promotion.
     
  16. Nightinggale

    Nightinggale Deity

    Joined:
    Feb 2, 2009
    Messages:
    4,354
    An example would be
    Code:
    <BuildingClassNeededs/>
    <YieldDemands>
    	<YieldDemand>
    		<YieldType>YIELD_SILVER</YieldType>
    		<iYieldDemand>100</iYieldDemand>
    	</YieldDemand>
    </YieldDemands>
    <HotKey/>
    You need to copy in the schema from M:C as I didn't update it in the 2071 branch. The same goes for UnitInfo.

    You are running Yields_Medieval_Tech.cpp line 142. That one will only be compiled if COLONIZATION_2071 isn't defined. Makefile.settings should contain
    Code:
    CUSTOM_CFLAGS = -DCOLONIZATION_2071
    Maybe I should change the Makefile to show which defines are set as it would help in cases like this.
     
  17. Nightinggale

    Nightinggale Deity

    Joined:
    Feb 2, 2009
    Messages:
    4,354
    That is what it is designed for. It isn't designed to take armor type and then hardcode the DLL to add crushing blow to that combat type.
    Basically if an armor should be a UnitCombatInfo, then it should be say a mirror armor and the laser attack unit will then have -75% attack and defense vs mirror armor. We shouldn't need to add combat types unless we add promotions to work on them. Features like crushing blow should be added in a different manner.

    edit:

    He did something like that, but then again not really as the profession has one type working for the stuff you mention and then it has a list of types, which gives a few bonuses like shields can block attacks and plate mail gives crushing blows (both hardcoded in DLL). I wouldn't mind going all the way with it and allow combos as you read it as it would provide additional interesting setup options. However I can't promise anything as I would have to look closely at the code to ensure that it will be able to handle this with decent speed and all that.
     
  18. orlanth

    orlanth Storm God. Yarr!

    Joined:
    Nov 17, 2001
    Messages:
    1,776
    Synced another commit.. :hammer: it took some doing, but the game now reads and recognizes all the generated xml. :cool::scan: I set paths to placeholder art to get things running, so everything looks like Free Colonists and Town Halls atm, but still :woohoo::p

    There are a few asserts on loading:
    Spoiler :
    File: Yields.cpp
    Line: 43
    Expression: this->function(eYield)
    Message: Yield YIELD_SILICATES missing in YieldGroup_AI_Sell_To_Europe

    Assert Failed

    File: Yields.cpp
    Line: 45
    Expression: !this->function(eYield)
    Message: Yield YIELD_STATE_SECRETS is a false positive in YieldGroup_AI_Sell_To_Europe

    Assert Failed

    File: Yields.cpp
    Line: 43
    Expression: this->function(eYield)
    Message: Yield YIELD_ROBOTICS missing in YieldGroup_AI_Buy_From_Europe

    Assert Failed

    File: Yields.cpp
    Line: 110
    Expression: YieldGroup_Light_Armor(eYield) || YieldGroup_Heavy_Armor(eYield)
    Message: YIELD_DURALLOY is armor, but neither light or heavy armor
    I also included placeholder buildings for the required M:C buildings Shrine and Trading Post; it now loads without asserts for these, but in Pedia it looks like they provide a big set of production bonuses not specified by the generated XML. Is there some DLL hardcoding re these buildings?

    If Shrine attracts Pilgrims, I'm thinking it could be reused by 2071 for a rare Progenitor Monolith which you can excavate from Goody Huts and set up in your colony, attracting a steady trickle of UFO Cultists as immigrants (having below-average stats similar to Proletarians, but a free bonus in being mindlessly attracted by the Monolith's subspace radiation :scan:;)). I suppose the Trading Post could be reused as a Trade Consulate set up in alien cities by human units with the Emissary profession.

    Lastly, on starting a game, there are a bunch of asserts for setting yield prices:
    It loads to the main map without further asserts, but then shows the bar of yields along the bottom like in the cityscreen (perhaps since it got hung up trying to set prices for these?)
     
  19. Nightinggale

    Nightinggale Deity

    Joined:
    Feb 2, 2009
    Messages:
    4,354
    Yield_Colonization_2071.cpp has some yieldgroups where you set up precisely which yields to have in each group. You then set up the access functions in Yield_Colonization_2071.h to calculate if yield X is in that group, preferably as fast as possible as only the header access functions will be used while playing. The assert tells that you have a mismatch, which isn't serious until somebody starts playing for real.

    Most likely. M:C has too much hardcoded stuff in the DLL for my liking. I will keep an eye for such hardcoding. What do they demand?

    I think that's the whole idea with the shrine.

    Somewhat related to the first assert. The AI has 4 main groups of yields:
    -Buy from Europe
    -Sell to Europe
    -Food, lumber, stone. Luxury food goes here too if enabled in the header file.
    -Virtual yields

    Yields are placed in the first group where it applies in the order I have written. Anything not present in any of those 4 groups will cause an assert as the AI can't figure out what to do with that yield. Basically you change the group setup in Yield_Colonization_2071.cpp to make sure no yields are unspecified. I think the AI will just ignore all the yields, which causes those asserts and as such it isn't an important assert at this point.

    M:C does the same thing. I haven't found the cause yet, but once the game is started it works just fine. It's a minor graphical glitch, which will not cause any problems later on.
     
  20. Nightinggale

    Nightinggale Deity

    Joined:
    Feb 2, 2009
    Messages:
    4,354
    I fixed both and in the process I paid attention to the surrounding code. First of all I'm not sure I like the implementation of Alt Equipment, but now we have it. I think it would have been better to make two professions instead.

    What I noticed was that CvUnit::canHaveProfession() doesn't check for inventions when figuring out if a profession should be allowed. This is an often called function (the AI use it all the time), which is why it's critical for good performance. I want to make it ignore uninvented professions, which isn't that hard to do. It should be done at the top and using a cache to make it really fast and neither are tricky.

    However skipping as many professions as possible would be the best option and then I started wondering. Natives never use a bunch of "Eurpoean" professions and vice versa. If we tell the cache that those never used professions aren't invented, then we would save some time. In fact I think we could save quite a lot of time. It would also be easier to code if we have a function canUseProfession() for each player and it tells if it can be used, but not why it can't be used right now.

    The problem with this approach is that it should work in ProfessionInfos and CivilizationInfos (possibly UnitInfos as well if it can't be avoided). Where does it say which civ can use which profession?

    I also figure I will use the same trick on units. If eUnit's Unitclass points to a different unit for the civ in question, then we can set that unit to uninvented for that civ. As it already checks the invention cache it would be 100% the same speed as checking for invented units right now, but we check those XML limitations for free.
     

Share This Page