CanDoResearch? Can anyone help? Kael, TheLopez or TBA?

Joined
Jul 21, 2003
Messages
7,819
Location
Adelaide, South Australia
Hiya guys. Something I have wanted to do for the longest time is to have a more 'Dynamic' Tech tree. One way of doing that, IMO, is to limit some of the techs a civ has access to based on their access to resources. Taken to its logical conclusion-this could open up whole strings of techs which ONLY those civs with appropriate resources can tap into.

On a less ambitious note, I would really just like to have a situation where, if you have no horses, you can't learn Horseback Riding and if you lack Copper you can't learn Bronze Working.

So, the question is, can I make resource access a preprequisite of the CanDoResearch function in CvGameUtils? I have searched the API and can find no reference to resource at all.
If it can be done, can someone suggest how I incorporate it?

Thanks in advance.

Aussie_Lurker.
 
Well, probably what you would need to do is use the SDK to add a new tag that is a child tag of the <AndPreReqs> tag kind of like the <PrereqTech> tag call it something like <PrereqResource>.

Another way would be to use the canResearch in CvGameUtil and the countOwnedBonuses method in the CyPlayer class. You could do something like
Code:
	def canResearch(self,argsList):
		ePlayer = argsList[0]
		eTech = argsList[1]
		bTrade = argsList[2]
		# If player has horses and they are trying to research horseback riding then they can research Horseback riding and return true
		# otherwise return false.
		return False

Does this answer your question?
 
It does, except for one thing. Once I add the <andResourcePrereq> to the XML file, what section of the code do I go to in order to add resource prerequisites?
Also, I assume that I will only need to do this once?

Thanks in advance.

Aussie_Lurker.
 
Aussie_Lurker said:
... if you lack Copper you can't learn Bronze Working.
I hope this was just an example, cause you might create a chicken vs. egg paradox if you were to implement this for a tech which makes it's dependent resource visible to the player. (i.e. I can't see/mine copper unless I know Bronze Working, only I can't learn Bronze Working unless I have copper... :crazyeye: )
 
Well Denniz, obviously you would shift when Iron and Copper become available. For instance, I would make them either both appear with mining, or have Copper appear with mining, and iron appear with bronze working.
I admit though that I am prevented from doing some things. For instance, I wanted animal husbandry to rely on presence of cattle, sheep or pigs, and for Masonry to require either stone or marble. To do that, though, Quarries and Pastures would need to appear earlier-and this would definitely be a 'Chicken or Egg' scenario.

Aussie_Lurker.
 
Well here's TBA...

You shuold be able to use the CvGameUtils.py method. Don't use canResearch. This function is for making things you wouldn't normally be able to research researchable. Instead using cannotResearch which makes things you would normally be able to research researchable. There's quite a distinction.

One trouble with what the idea is that resources aren't global. If you had one colony in the middle of nowhere which had access to horses, but no trade route home, then do you want to be able to research horseback riding or not?

There are two methods you could use to handle this IMO. You could just make it so that only the capital needed the resources, or you could do something clever where only beakers collected in towns with horses went towards the total, and the rest got stored up for the next tech, or something.

BTW - resources are called bonuses for the sake of the API.
 
Thanks for the advice, TGA, I think this will help a LOT (oh, and I REALLY don't know how I got your name wrong ;) ). Oh and, how would I do the thing you mention with the beakers?? (Truth be told, I was hoping for a more 'finessed' system where having the resource simply 'halves' the research cost-rather than determining if you can do the research at all-but wasn't sure if it could be done!

If I am unable to achieve my aims via Python, then I may be seeking advice about the SDK ;).

Aussie_Lurker.
 
Hi TheLopez or TheGreatApple.

Could you please have a quick look at this section of code, and let me know if you think it will work? What I am trying to do is to have access to copper change your research progress in Bronze Working by 50%.

Thank you in advance.

Code:
def onBeginPlayerTurn(self, argsList):
		'Called at the beginning of a players turn'
		iGameTurn, iPlayer = argsList

		player = gc.getActivePlayer()
		if (player.hasBonus(gc.getInfoTypeForString("BONUS_COPPER")))
                                player.changeResearchProgress(gc.getInfoTypeForString("TECH_BRONZE_WORKING"), 50)
                else:
                                player.changeResearchProgress(gc.getInfoTypeForString("TECH_BRONZE_WORKING"), 0)
 
A few things.

1) CyPlayer.hasBonus(...) doesn't exist. I don't know where you found it, but it ain't in the API. It wouldn't work anyway, because, as I explained above, a player can both have a bonus, and not have it, depending on what place in the player's empire you are.
2) gc.getActivePlayer() find the human player who is "active" on the computer. You really want player = gc.getPlayer(iPlayer)
3) CyPlayer.changeResearchProgress(...) doesn't exist either. You really need to use the API if you want code that will stand a chance of working. Research is handled as a team, so you'd want to do gc.getTeam(player.getTeam()).changeResearchProgress(...). You got the variables wrong as well - there should be 3:
Code:
VOID changeResearchProgress(TechType eIndex, INT iChange, PlayerType ePlayer)
void (TechID, iChange, iPlayer ) - edits progress towards TechID
Also, I'm not even sure if this is the right function for what you want to do - the description for it doesn't sound too hopeful.
 
Anothing this. In CvGameUtils.py there is a doResearch function. If you want to edit how research works, I suggest you stick the code in here, as this function will be triggered at the end of every turn in the research phase.
 
Hmmm, looks like I was way off base there TGA :(. I confess I used an earlier bit of Python I used and tried to modify it for this purpose, clearly that wasn't the best way to go about it.

I have looked at the API, and the key areas I thought would be of greatest relevence to me were the
Code:
Bool hasResource (ResourceID)
and the changeResearchProgress lines you refer to in your reply. If the latter doesn't work, then I am just going to have to take the 'crude' route and merely deny the techs to those who lack the resources-either via GameUtils or via the SDK.
Anyway, thanks for the advice.

Aussie_Lurker.
 
Aussie_Lurker said:
I have looked at the API, and the key areas I thought would be of greatest relevence to me were the
Code:
Bool hasResource (ResourceID)
Which API are you using? The one I'm using here is the for the latest patch and doesn't have that function anywhere...
 
sorry. Bool hasBonus :mischief: . Bit of a brain-fart there I am afraid. Kind of like when I called you TBA instead of TGA!!!!

Aussie_Lurker.
 
FYI: here is my cannotResearch() function in the CvGameInterface.py file:

Code:
def cannotResearch(argsList):
	ePlayer = argsList[0]
	eTech = argsList[1]
	pPlayer = gc.getPlayer(ePlayer)

	if eTech == gc.getInfoTypeForString('TECH_HIDDEN_PATHS'):
		if pPlayer.getStateReligion() != gc.getInfoTypeForString('RELIGION_FELLOWSHIP_OF_LEAVES'):
			return True

	if eTech == gc.getInfoTypeForString('TECH_NECROMANCY'):
		if pPlayer.getStateReligion() != gc.getInfoTypeForString('RELIGION_THE_ASHEN_VEIL'):
			return True

	if eTech == gc.getInfoTypeForString('TECH_DIVINATION'):
		if pPlayer.getStateReligion() != gc.getInfoTypeForString('RELIGION_THE_ORDER'):
			return True

	if eTech == gc.getInfoTypeForString('TECH_MIND_STAPLING'):
		if pPlayer.getStateReligion() != gc.getInfoTypeForString('RELIGION_OCTOPUS_OVERLORDS'):
			return True

	if eTech == gc.getInfoTypeForString('TECH_DWARVEN_MINING'):
		if pPlayer.getStateReligion() != gc.getInfoTypeForString('RELIGION_RUNES_OF_KILMORPH'):
			return True

	return False

It blocks access to techs if the player doesn't have the appropriate religion. Changing this to make sure the capital has the appropriate bonus as TGA mentioned should be easy. You could use this to block techs based on civic options, other tech choices (choosing one section of the tech tree blocks the other), access to water (check for a coastal city), creation of a national wonder, ownership of a unit of a certain level, x amont of cities owned, x amount of farms or mines in the empire, etc etc.

Tons of customization available here. CvGameInterface.py is my favorite python file, simple and powerful.
 
Kael said:
Tons of customization available here. CvGameInterface.py is my favorite python file, simple and powerful.
Oooh - I hadn't noticed CvGameInterface.py. I've been using CvGameUtils.py.

It's much the same, but CvGameInterface.py is probably a bit neater. Thanks!

BTW - why not use elif clauses? It should save a bit on performance, given that that function is called quite a bit from what I can tell.
 
The Great Apple said:
Oooh - I hadn't noticed CvGameInterface.py. I've been using CvGameUtils.py.

It's much the same, but CvGameInterface.py is probably a bit neater. Thanks!

BTW - why not use elif clauses? It should save a bit on performance, given that that function is called quite a bit from what I can tell.

This is probably my non-programmer nature coming out. I tend to go with simplicity over performance if the performance gain is relativly minor. I would elif block on this if the cut group was large enough but as it would only buy me a gain when it was one of the prior hits I kept it basic.
 
Hey guys, you have been an ENORMOUS HELP!! Thank you for the assistance. I am afraid that I need to 'pick your brains' again.

This is what I want to do-in a nutshell:

At def OnUnitMove, I want the computer to look at the plot the unit is currently on, and the distance between this plot and a plot containing a city or fort belonging to a friendly civ (using pathfinding). If the distance between the two is greater than a specific number, then the unit gets an 'attrition' promotion which harms their combat performance.
Now, I know it is possible to grant units plot-based promotions, but am not sure if it is possible to tie in either pathfinding or distance between X and Y.
The question is (a) can it be done and (b) how would I go about it?

Thank you in advance.

Aussie_Lurker.
 
Aussie_Lurker said:
Hey guys, you have been an ENORMOUS HELP!! Thank you for the assistance. I am afraid that I need to 'pick your brains' again.

This is what I want to do-in a nutshell:

At def OnUnitMove, I want the computer to look at the plot the unit is currently on, and the distance between this plot and a plot containing a city or fort belonging to a friendly civ (using pathfinding). If the distance between the two is greater than a specific number, then the unit gets an 'attrition' promotion which harms their combat performance.
Now, I know it is possible to grant units plot-based promotions, but am not sure if it is possible to tie in either pathfinding or distance between X and Y.
The question is (a) can it be done and (b) how would I go about it?

Thank you in advance.

Aussie_Lurker.

Can definitly be done, something like the following in onMove:

Code:
	iX = pUnit.getX()
	iY = pUnit.getY()
	bSafe = False
	for iiX in range(iX-2, iX+3, 1):
		for iiY in range(iY-2, iY+3, 1):
			pPlot = CyMap().plot(iiX,iiY)
			if (pPlot.isCity() and pPlot.getCity().getOwner() == pUnit.getOwner()):
				bSafe = True
	if bSafe == False:
		pUnit.blah blah blah (whatever you want to do)

The above is untested but should search all plots within 2 tiles of the plot the unit moved into looking for the criteria. The criteria will need to be specified as you want it. Then is it doesn't find anything that meets the criteria it does whatever you want to the unit.
 
Kael, don't know if I said this before, but you are a TRUE LEGEND!!! Just to clarify though. If I want to increase the range the computer searches for a safe plot, is the number(s) I change the ones I have bolded?

Code:
iX = Unit.getX() 
iY = pUnit.getY() 
bSafe = False 
for iiX in range[B](iX-2,[/B] iX+3, 1): 
         for iiY in range[B](iY-2,[/B] iY+3, 1): 
                  pPlot = CyMap().plot(iiX,iiY) 
                  if (pPlot.isCity() and pPlot.getCity().getOwner() == pUnit.getOwner()): 
                           bSafe = True 
if bSafe == False: 
           pUnit.blah blah blah (whatever you want to do)

Also, and I hate asking you ALL these questions, can I introduce elements which (a) restrict what TYPE of units are effected by this code (I think I already know the answer to this, based on Bruhic's RealFort Mod) and (b) Can I alter the above code so that enemy units between Unit X and Safe Plot Y results in the search being either aborted or returned as false? Lastly, can this bSafe code be applied to specific terrain types-like jungles, tundra or desert?
As I said, I am SO SORRY to be such a pain, but your knowledge of Python is absolutely PHENOMENAL!!! Thanks again for ALL your help. As I said, you are a legend!!!

Aussie_Lurker.
 
Aussie_Lurker said:
Kael, don't know if I said this before, but you are a TRUE LEGEND!!! Just to clarify though. If I want to increase the range the computer searches for a safe plot, is the number(s) I change the ones I have bolded?

Code:
iX = Unit.getX() 
iY = pUnit.getY() 
bSafe = False 
for iiX in range[B](iX-2,[/B] iX+3, 1): 
         for iiY in range[B](iY-2,[/B] iY+3, 1): 
                  pPlot = CyMap().plot(iiX,iiY) 
                  if (pPlot.isCity() and pPlot.getCity().getOwner() == pUnit.getOwner()): 
                           bSafe = True 
if bSafe == False: 
           pUnit.blah blah blah (whatever you want to do)

Also, and I hate asking you ALL these questions, can I introduce elements which (a) restrict what TYPE of units are effected by this code (I think I already know the answer to this, based on Bruhic's RealFort Mod) and (b) Can I alter the above code so that enemy units between Unit X and Safe Plot Y results in the search being either aborted or returned as false?
As I said, I am SO SORRY to be such a pain, but your knowledge of Python is absolutely PHENOMENAL!!! Thanks again for ALL your help. As I said, you are a legend!!!

Aussie_Lurker.

The numbers you bolded will increase how far the search looks above and to the left of the units plot. If you wanted to increase the range so that it searches every plot within 3 of the unit change it to:

Code:
for iiX in range(iX-3, iX+4, 1): 
         for iiY in range(iY-3, iY+4, 1):

Its a bit confusing because you would epxect it to be (iX-3, iX+3, 1) but the range doesn't search the last set of numbers so you have to extend an extra row so it becomes (iX-3, -X+4, 1).

Yes, its easy to have this only effect certain unit types (or any other qualifier you want. Just put and if statement in front of the whole section that skips it if it isn't a type of unit that is vulnerable to the effect.

The code to check to see if their are enemy units int he way is defintily doable, I would probably go with a brute force method depending on what tile turned up the city, it would be long but simple. TGA or others that are better programmers might know a more clever way to do it.

FYI: The hardest part of what you are attempting to do isn't going to be building the functions, but getting the AI to understand respond correctly to the new conditions.
 
Back
Top Bottom