Platy World Builder

BUG does mess with the CvGameUtils disabling some of its functions somehow with its own ones.
 
Yeah, there's a BugGameUtils.py that sets everything to the default and overrides anything in GameUtil.py. Presumably part of their goal to allow modular python, but personally I found that causes more issues than it solves. I long ago commented out all the sections that set defaults, but that wasn't working in this instance.

I solved it however. BUG has another file, WidgetUtil.py, that had its own version of getWidgetHelp. I shifted the Inquisition and Worldbuilder widget stuff to there and now everything works as expected. As you say, BUG is great to play with but a pain to mod with. They keep replacing systems with their own implementation, which is fine when you're specifically coding on top of BUG but a real nuisance when trying to merge stuff that wasn't. If I understood BUG better I'd probably strip a lot of unnecessary stuff out of HR.

Anyway, thanks for pointing me in the right direction! I never would have guessed it was all caused by widgets (whatever they are, lol).
 
Now you know why I write my own U.I. script?
 
Nothing much, fed up when editing Espionage Screen in Ultrapack, so...

Diplomacy Screen
1) War Weariness
Added +/- 10K, +/- 1K
2) War Weariness Commands
Added +/- 10K to All
3) Espionage
Added +/- 10K
4) Espionage Commands
Added +/- 10K to All
 
Hello, Great Builder!

Quarterly update of the French translation!

Amazing job you did with the screens since I last checked!
 
Thanks for this Modcomp!

I was first introduced to it through Tholal's More Naval AI modmod (version 2.5) for Fall from Heaven II, which I am using as a basis for my Magister Modmod.

He was using an outdated version at the time, so I've updated it for him and also added some new functionality that really only makes sense for FfH2 based modmods.


After merging in the latest released version, I noticed an issue with the Specialists/Great People Rate screen. In my modmod, where settled great persons provide GPP too, there were duplicates of all of the great persons.

I think that this line is supposed to prevent that duplication, but it does not. That is because what you add to List2 is (GPInfo.getDescription() + " Platy_" + str(iGP)) rather than just iGP.
Code:
		for i in xrange(gc.getNumSpecialistInfos()):
			ItemInfo = gc.getSpecialistInfo(i)
			self.iList.append(ItemInfo.getDescription() + " Platy_" + str(i))
			iGPClass = ItemInfo.getGreatPeopleUnitClass()
			if iGPClass == -1: continue
			iGP = gc.getCivilizationInfo(pCity.getCivilizationType()).getCivilizationUnits(iGPClass)
			[B][COLOR="Red"]if not iGP in self.iList2:[/COLOR][/B]
				GPInfo = gc.getUnitInfo(iGP)
				self.iList2.append(GPInfo.getDescription() + " Platy_" + str(iGP))


This code also seems to assume that all GPP are of types that can be granted by specialists, which is not always true. You can also have GPP which are granted only by buildings. (FfH2 treats GPP for Adventurers and Commanders that way, and my modmod also does the same for Shades and Disciples of Acheron.) This world builder does not let you adjust the GPP for those.

Last but not least, your code runs into problems for any players that have NONE as a unique unit replacing some type of great person.

At first I just decided to hardcode a list of possible great persons in my modmod, but then I decided it would be better to just fix the code to something you could use too. This seems to be working nicely:

Code:
		self.iList = []
		self.iList2 = [][COLOR="Cyan"]
		self.iList3 = [][/COLOR]

		for i in xrange(gc.getNumSpecialistInfos()):
			ItemInfo = gc.getSpecialistInfo(i)
			self.iList.append(ItemInfo.getDescription() + " Platy_" + str(i))
			iGPClass = ItemInfo.getGreatPeopleUnitClass()
			if iGPClass == -1: continue
			iGP = gc.getCivilizationInfo(pCity.getCivilizationType()).getCivilizationUnits(iGPClass)
[COLOR="Cyan"]			if iGP == -1: continue
			if not iGP in self.iList3:
				self.iList3.append(iGP)

		for i in xrange(gc.getNumBuildingInfos()):
			ItemInfo = gc.getBuildingInfo(i)
			iGPClass = ItemInfo.getGreatPeopleUnitClass()
			if iGPClass == -1: continue
			iGP = gc.getCivilizationInfo(pCity.getCivilizationType()).getCivilizationUnits(iGPClass)
			if iGP == -1: continue
			if not iGP in self.iList3:
				self.iList3.append(iGP)

		for iGP in self.iList3:
			GPInfo = gc.getUnitInfo(iGP)
			self.iList2.append(GPInfo.getDescription() + " Platy_" + str(iGP))
[/COLOR]



Since FfH2 has no Spaceship or Corporations, I think I'd like to disable those (half)screens. How would I go about doing that?

FfH2 also has repeatable rituals, and my modmod has rituals with world and team limits. How would I go about changing the project screen to let me adjust the number of rituals performed rather than merely turning them off and on?


The preview you show here shows the ability to sort between buildings, national, team, and world wonders, but in what I downloaded the only choices are buildings and wonders. I would rather be able to have those categories, and all buildings (wonders included) category, and the ability to add a couple special building categories (for temples, civ specific buildings, and buildings granted by spells).

The Grant Available command does not seem to be working for Buildings. It does seem to work for Wonders, but is ignoring the Holy City requirements of the religious Shrines.


There are a lot of promotions in FfH2 and its modmods (Magister Modmod has almost 3 times as many as the world builder promotions screen can show at one time), which could be divided into categories like Equipment, Spell spheres, spell effects, etc. How would I go about adding the ability to sort between the way you can sort between different bonus classes?
 
Whoa, what a long post :D

1) Specialists and GPP
I will update with your solution, with one adjustment.
I won't define a new temporary list.
For the last step, when you loop through the list, you might just change the values in the list to include the description, rather than append to a new list.

Actually, this style of appending with the "Platy" separation was my old method to append 2 different values into one list, but recently I figure out that I can simply append ((x, y)) directly.
Don't shoot me, python is my trial-and-error-self-taught language :D

2) If you refer to those half-screens files, you will notice they have something in common
A) TableHeight is half (/2), adjust that back to normal
B) 2 additional "screen.addPanel" codes to separate them.

Just change A and remove B, plus all the relevant codes relating to the other halfscreen that you don't need, which will include the headers, drop down selections, the table codes and of course all the handleinput results.
I guess with your skills, you will know what I mean.

There is a reason why every screen was done in full screen.
Because 90% are using jump to pedia widgets, which means the full screen is meant to hide the pedia pop up when you click them.
The religion screen though is not using pedia widgets so you can adjust the screen size if you find it too empty after cutting off the corporation half.

3) Ritual
If they are still projects, actually the spaceship part is more suitable since, it is already in the style where you can +/- rather than true/false.
If you want to separate rituals from projects, then just keep both parts and adjust spaceship codes to identify based on definition of rituals.
Else, if you only want a merged list of rituals and projects, then remove the top project part, and adjust the spaceship codes.

4) Wonders
Well, the conclusion was, Team Wonders are usually not found in mods anyway, and... National Wonders alone looks too empty, so I merge all wonders.

5) Grant Available
One thing strange I noticed is the Command dropdown does not work for certain screens until you do something else first, such as changing from Buildings to Wonders.
This is noticeable in Buildings and Techs, and I guess some others too which I havent figured out.
So for instance, you cannot use the Add All Techs Command while in the initial screen, but after you change the Era to display ancient for instance, then the Command dropdown will work.
Bizzare, but I haven't solved it yet.
Holy City hmm, will update it later.

6) Promotions
Well, you will have to add a dropdown list like Bonus(for Bonus Class), Techs(for Eras), Buildings (for Building Class)
Then looking at Tech as example:
Code:
		self.iList = []
		for i in xrange(gc.getNumTechInfos()):
			ItemInfo = gc.getTechInfo(i)
			iEra = ItemInfo.getEra()
			[COLOR="Red"]if self.iEra == 1000 or self.iEra == iEra:[/COLOR]
				self.iList.append(ItemInfo.getDescription() + " Platy_" + str(i))
		self.iList.sort()
Instead of simply appending them, there is an Era check to see if the era corresponds to the era in the dropdown selection, where 1000 here refers to All.

Thus, the question will be how you define which promotion is a Equipment or a Spell Sphere etc.
There should be some checks which can separate them into those different categories.

For instance, for my Platypedia modcomp, Specialists are separated into normal types and great types.
There is no special tag in BTS to define what is a Great Specialist and what is not, so I simply define GS as one with "GREAT" in the TYPE tag.
 
Updates

Specialists
Updated Great Specialists codes

Wonders
1) National, Team and World Wonders are still in same page, but they are sorted in such a way that NW are displayed first, followed by TW and WW
2) Added Holy City check

All Pages
Replaced the old method of appending to simpler one.

Techs
1) Repeatable Techs aka Future Tech now display with a number to indicate how many of that the team has
2) Grant All Tech Command ignores Repeatable Techs now, because there is no way to reduce it...
 

Attachments

  • Civ4ScreenShot0000.JPG
    Civ4ScreenShot0000.JPG
    89.4 KB · Views: 246
  • Civ4ScreenShot0001.JPG
    Civ4ScreenShot0001.JPG
    101.8 KB · Views: 232
I do shoot you! Even in C/C++ you have multidimensional arrays! int [*a number*][2] is acceptable :lol: and you got an A in that :p

Now I have my own back :satan:
 
The difference is:
For my case, both methods work, just that one is simpler.

For your case, the method will fail, and it is not just a simple error, it is a critical error that will hang the whole game.

:banana:
 
one is simpler and the other one is ridiculous :lol:

mine was just an over-site, I wasn't playing attention to how the game will change as it didn't apply to me when I used it.

don't worry I will be watching your work like a cat waiting to pounce on you :lol:
 
You will have to jump dunno how many miles to be able to pound on me given our locations...

Given that mine works while yours don't, players will not notice any difference for mine, while they will curse and swear when your mod hangs their computers.
 
but if we both wrote the storm feature mine would be 1000 times faster than yours :p

a) mines written in C++
b) The storms can hit ANY tile, if there is a storm on the selected tile it just adds the time up to max turns for the storm to live. So there are never any performance hits in my mod from this feature or anybody else's :p where as your's checks through every tile in the game every turn AND in python :lol:

c) I was thinking there is actually a less memory efficient method to solving the problem that takes the best of both worlds. it involves on game start making a list of all plots. When the checks are made it cycles through the whole list, but if a tile is unavailable it removes it from the list, so instead of getting slower as the game progresses or remaining constant like yours, it should in theory get faster as the game progresses :D
 
If it can hit any tile, does it make sense?

Storm in the desert or artic?
 
storms hit in the desert... but most of my storms occur in the sea anyway, the storms are geared to hit the sea more often than land.

even in the tundra storms can happen. Norway gets great lightning I hear.

anyway read my edit :p
 
Frankly speaking, whether it is done in C++ or python, I doubt it matters.
If you are doing a 10000 iteration via SDK every turn or a 10000 iteration via python every turn, what makes you think SDK will be significantly faster?

Codes change according to the design intended.
When I design the pseudo code for Keldath's idea, it is obvious that
1) It will be done once in a blue moon. Unless the civ is killed and respawn every turn... then that is another matter. So even though it is a loop through all plots in map, it is not important.

Take a look at natural wonder mod. You designed it as well, the only reasonable solution was in fact the same solution as this:
Loop through all plots, collect all suitable plots, then choose a random one

2) Suitable plots change all the time. It is impossible to keep a list of suitable ones at start, and expect the list to remain valid 1000 turns later.

Storm thingy of yours is of a totally different design.
Since you apparently don't care about the plot details beside water or land, then of course codes will be done in a different nature.

I never heard of lightning storm in Sahara desert though...
 
oh yeah, that happens :D

http://www.youtube.com/watch?v=HB0CKyu136Y

and I've done tests in the past, C++ is around 1000 times faster than python. I moved some of psi corps python code into C++ and he noticed significant difference in turn times :D with the exact same code design :p

I must say, although unsuitable can become suitable it doesn't happen often and isn't worth using...
 
The keyword there in the question is "significantly"

Unless your loop is really so tedious that it is looping 1000000 times or within each iteration you are doing 1000 calculations.... Does it matter?

I highly doubt that a loop of less than 10000 iteration will matter whether it is done in SDK or python, especially when it is triggered once in a blue moon.

@Sahara
See, it is so rare that when it happens, people make a video of it.
Who will care to make a video of lightning storm in Singapore since it happens every now and then.
But your code apparently doesn't care about terrain since all you do is roll a plot index and put storm there without caring what are the plot details :D
 
the code I moved was simply;

is the unit able to move into this tile?

from this:

Code:
##		if ePlayer in self.deactivated:
##			return False
##		else:
##			if gc.getTeam(gc.getPlayer(ePlayer).getTeam()).isHasTech(gc.getInfoTypeForString("TECH_B5_INTERPLANETARY_MISSILES")) or gc.getPlayer(ePlayer).isBarbarian():
##				self.deactivated.add(ePlayer)
##				return False
##		eUnitType = gc.getPlayer(ePlayer).getUnit(iUnit).getUnitType()
##		eUnitCombat = self.unitCombatDict.get(eUnitType, None)
##		if eUnitCombat == None:
##			eUnitCombat = gc.getUnitInfo(eUnitType).getUnitCombatType()
##			self.unitCombatDict[eUnitType] = eUnitCombat
##		if eUnitCombat == gc.getInfoTypeForString("UNITCOMBAT_FRIGATE"):
##			bRestricted = gc.getMap().plot(iX, iY).getOwner() != ePlayer
##		elif eUnitCombat == gc.getInfoTypeForString("UNITCOMBAT_DESTROYER"):
##			bRestricted = gc.getMap().plot(iX, iY).getOwner() != ePlayer
##		elif eUnitCombat == gc.getInfoTypeForString("UNITCOMBAT_CRUISER"):
##			bRestricted = gc.getMap().plot(iX, iY).getOwner() != ePlayer
##		elif eUnitCombat == gc.getInfoTypeForString("UNITCOMBAT_TRANSPORT"):
##			bRestricted = gc.getMap().plot(iX, iY).getOwner() != ePlayer
##		elif eUnitCombat == gc.getInfoTypeForString("UNITCOMBAT_CARRIER_SHIP"):
##			bRestricted = gc.getMap().plot(iX, iY).getOwner() != ePlayer
##		else:
##				bRestricted = False
##		return bRestricted

to this:

Code:
if (!GC.getUnitClassInfo(getUnitClassType()).canLeaveBorders())
	{
		if (!GET_PLAYER(getOwnerINLINE()).isBarbarian())
		{
			bool bIsRestricted = true;
			for (int i = 0; i < GC.getNumTechInfos(); i++)
			{
				if (GC.getTechInfo((TechTypes) i).isAllowsLeaveBorders() && GET_TEAM(GET_PLAYER(getOwnerINLINE()).getTeam()).isHasTech((TechTypes) i))
				{
					bIsRestricted = false;
					break;
				}
			}
			if (pPlot->getOwnerINLINE() != getOwnerINLINE() && bIsRestricted)
			{
				return false;
			}
		}
	}

and a significant difference was achieved :D

edit: do you get lots of rain with those storms? I love rain :)
 
If you are talking about codes done in unitCannotMoveInto...
That one is a well known "do not activate unless you have no choice" python callback.

@Rain
Love or Hate depends on whether I am napping at home, or traveling to meet clients...
 
Top Bottom