Quick Modding Questions Thread

Use raze function if kill gives problems.

I try platy but i get errors.

I changed:
Code:
	def onCityRazed(self, argsList):
		'City Razed'
		city, iPlayer = argsList [COLOR="Red"][B]# line 2132[/B][/COLOR]
		iOwner = city.findHighestCulture()
## RECONSTRUCTION Start
		CyInterface().addMessage(0,true,15,"onCityRazed: "+str(CyTranslator().getText(str(self.TargetFound),())),'',0,'',13,-1,-1, true,true)
## RECONSTRUCTION End
		# Partisans!
		if city.getPopulation > 1 and iOwner != -1 and iPlayer != -1:
			owner = gc.getPlayer(iOwner)
			if not owner.isBarbarian() and owner.getNumCities() > 0:
				if gc.getTeam(owner.getTeam()).isAtWar(gc.getPlayer(iPlayer).getTeam()):
					if gc.getNumEventTriggerInfos() > 0: # prevents mods that don't have events from getting an error
						iEvent = CvUtil.findInfoTypeNum(gc.getEventTriggerInfo, gc.getNumEventTriggerInfos(),'EVENTTRIGGER_PARTISANS')
						if iEvent != -1 and gc.getGame().isEventActive(iEvent) and owner.getEventTriggerWeight(iEvent) < 0:
							triggerData = owner.initTriggeredData(iEvent, true, -1, city.getX(), city.getY(), iPlayer, city.getID(), -1, -1, -1, -1)
			
		#Raze the Arcology
		owner = PyPlayer(city.getOwner())
		razor = PyPlayer(iPlayer)
		
		self.iArcologyCityID = -1
		
		if city.getNumRealBuilding(gc.getInfoTypeForString("BUILDING_ARCOLOGY")):
			self.iArcologyCityID = city.getID()
		
		CvUtil.pyPrint('Player %d Civilization %s City %s was razed by Player %d' 
			%(owner.getID(), owner.getCivilizationName(), city.getName(), razor.getID()))	
		CvUtil.pyPrint("City Razed Event: %s" %(city.getName(),))
	
	def onCityAcquired(self, argsList):
		'City Acquired'
		iPreviousOwner,iNewOwner,pCity,bConquest,bTrade = argsList
## RECONSTRUCTION Start
		pPlayerNew = gc.getPlayer(iNewOwner)
		pPlayerPrevious = gc.getPlayer(iPreviousOwner)
		if bConquest:
			#bPlayer = gc.getPlayer(gc.getBARBARIAN_PLAYER())
			#if(bPlayer.getID() == iNewOwner):
			#if(pPlayerNew == bPlayer):
				pPlotX = CyMap().plot(pCity.getX(), pCity.getY())
				#self.TargetFound = 0
				#CyInterface().addMessage(0,true,15,"onCityAcquired: "+str(CyTranslator().getText(str(self.TargetFound),())),'',0,'',13,-1,-1, true,true)
				#CyInterface().addMessage(iNewOwner,true,15,"Osvajac-Broj jedinica porazeni: "+str(CyTranslator().getText(str(pPlayerPrevious.getNumUnits()),())),'',0,'',13,-1,-1, true,true)
				#CyInterface().addMessage(iNewOwner,true,15,"Osvajac-Broj jedinica osvajac: "+str(CyTranslator().getText(str(pPlayerNew.getNumUnits()),())),'',0,'',13,-1,-1, true,true)
				#CyInterface().addMessage(iPreviousOwner,true,15,"Porazeni-Broj jedinica porazeni: "+str(CyTranslator().getText(str(pPlayerPrevious.getNumUnits()),())),'',0,'',13,-1,-1, true,true)
				#CyInterface().addMessage(iPreviousOwner,true,15,"Porazeni-Broj jedinica osvajac: "+str(CyTranslator().getText(str(pPlayerNew.getNumUnits()),())),'',0,'',13,-1,-1, true,true)
				(loopUnit, iter) = pPlayerNew.firstUnit(false)
				while(loopUnit):
					if(loopUnit.isHasPromotion(gc.getInfoTypeForString("PROMOTION_CITY_RAZE"))):
						if(loopUnit.getX() == pCity.getX() and loopUnit.getY() == pCity.getY()):
							for iPopulation in xrange(pCity.getPopulation()):
								pNewUnit = pPlayerNew.initUnit(loopUnit.getUnitType(), loopUnit.getX(), loopUnit.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION)
								pNewUnit.finishMoves()
								self.TargetFound = 1
							#pPlayerNew.disband(pCity)
							break
					(loopUnit, iter) = pPlayerNew.nextUnit(iter, false)
				#if(self.TargetFound == 1):
				#	pCity.kill()
#for iUnit in xrange(pPlotX.getNumUnits()):
#	pUnitX = pPlotX.getUnit(iUnit)
#	if(pUnitX.getOwner() == iNewOwner and pUnitX.isHasPromotion(gc.getInfoTypeForString("PROMOTION_CITY_RAZE"))):
#		for iPopulation in xrange(pCity.getPopulation()):
#			pNewUnit = pPlayerNew.initUnit(pUnitX.getUnitType(), pCity.getX(), pCity.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION)
#		pPlayerNew.disband(pCity)
#		break
## RECONSTRUCTION End
		CvUtil.pyPrint('City Acquired Event: %s' %(pCity.getName()))
## RECONSTRUCTION Start
		[COLOR="Red"]if(self.TargetFound == 1):
			self.TargetFound = 0
			self.onCityRazed(argsList)[/COLOR] [COLOR="DarkGreen"][B]#line 2202[/B][/COLOR]
## RECONSTRUCTION End
	
	def onCityAcquiredAndKept(self, argsList):
		'City Acquired and Kept'
		iOwner,pCity = argsList

		CvUtil.pyPrint('City Acquired and Kept Event: %s' %(pCity.getName()))

and i gets these errors:

1) ValueError: too many values to unpack
2) File "CvEventManager", line 2132 in onCityRazed
3) File "CvEnentManager", line 2202, in onCityAcquired
4) File "BugEventManager", line 361, in _handleDefaultEvent
5) Traceback(most recent call last):

What is Civ4lerts, the old version or Platy's?

The last Python error is the most important one. Note the line that is referred there and try to adjust it if possible.

I use BUG from LoR.

@for ALL:
All errors from THIS code (post #4311):

1) RuntimeError: unidentifiable C++ exception
2) File "Civ4lerts", line 485, in _passesTest
3) File "Civ4lerts", line 362, in resetCity
4) File "Civ4lerts", line 242, in _resetCity
5) File "Civ4lerts", line 213, in onCityAcquiredAndKept
6) File "BugEventManager", line 361, in _handleDefaultEvent
7) Traceback (most recent call last):
 
The first thing is to get it right without BUG/Civ4lerts.

On onCityAcquired try pPlayerNew.raze(pCity) instead of self.TargetFound = 1.

Raze instead of kill, as per Platy's suggestion.
 
Is there a way to make Pillaging not cost movement points? It would be a boost to infantry.

I tried editing the CIV4MissionInfos line:

Code:
<iTime>10</iTime>

to 0, but it didn't do it.
 
dll only.
 
The CvGameCore one?

Can I edit DLL with notepad? I'm assuming no, of course:crazyeye:
You can edit the source code with notepad, but that will not bring the result you want. You would need to install the compiler and set it up to compile a new dll file. However based on the problems people post about and the number of modders, who gives up entirely on the dll, I get the impression that the dll is by far the hardest part to mod. I question if it is the way to go for somebody, who starts out asking if notepad can be used.

Also use notepad++ instead of notepad. It's much better, even for xml modding.
 
Ah, don't underestimate me. Plus I'd make a backup before tweaking things willy nilly:nuke:

Well, its a pretty simple change. The biggest deal is to set up a compiler, which there are pretty good tutorials for.

The change needed for units not to use movement is in CvUnit.cpp :
in the function
PHP:
bool CvUnit::pillage()
change
PHP:
	changeMoves(GC.getMOVE_DENOMINATOR());
to
PHP:
//	changeMoves(GC.getMOVE_DENOMINATOR());

while this is doing what you ask, it might need further work on the AI as most of the AI moves are programmed in a way so it will do stuff and then continue to next unit/stack, instead of checking whether it should do something after it have done something. Meaning, that while it might not use moves, the AI is instructed to make a pillage and will end the units turn there. Not saying it will, just saying it might.
 
Is there a way to make Pillaging not cost movement points? It would be a boost to infantry.

I tried editing the CIV4MissionInfos line:

Code:
<iTime>10</iTime>

to 0, but it didn't do it.

Yes, but via Python

dll only.

You can do that via Python.

@for ALL
Code in file CvEventManager.py:
Code:
	def onUnitPillage(self, argsList):
		'Unit pillages a plot'
		pUnit, iImprovement, iRoute, iOwner = argsList
		iPlotX = pUnit.getX()
		iPlotY = pUnit.getY()
		pPlot = CyMap().plot(iPlotX, iPlotY)
		
[COLOR="Red"]# < ZLATKO RECONSTRUCTION START >[/COLOR]
		if pUnit.isHasPromotion(gc.getInfoTypeForString("PROMOTION_HARMONY_PILLAGE")):
			pUnit.changeMoves(-60) [COLOR="Blue"]#THIS DON'T COST MOVEMENT[/COLOR]
			if iImprovement > -1:
				pUnit.changeDamage(-20, false) [COLOR="Blue"]#THIS HEAL UNIT FOR 20HP[/COLOR]
[COLOR="Red"]# < ZLATKO RECONSTRUCTION END >[/COLOR]
		if (not self.__LOG_UNITPILLAGE):
			return
		CvUtil.pyPrint("Player %d's %s pillaged improvement %d and route %d at plot at (%d, %d)" 
			%(iOwner, PyInfo.UnitInfo(pUnit.getUnitType()).getDescription(), iImprovement, iRoute, iPlotX, iPlotY))
 
Code:
pUnit.changeMoves(-60)
What if the unit has less than 60 move left? Say it can move in enemy land for a cost of 30, then it can move, pillage and sudden have full move again, which allows it to move to next plot and pillage, effectively allowing it unlimited movement points in an ideal situation. This solution is somewhat hackish and I'm quite sure it has the bug I just pointed out. However depending on xml setup, this bug can be quite difficult to trigger. It could be worth a try to see if the AI figures out a way to cheat like this. The AI's reaction to free pillage should be tested anyway. I'm not quite sure you like the result as I suspect it to be overpowered.
 
If the unit has half a move left (-30), pillaging will change it to (30) rather than (0).
(-60) will change it back to (-30), half a move.

It works, but better to replace 60 with gc.getMOVE_DENOMINATOR()
 
Because MOVE_DENOMINATOR is defined as 60 in the Global Defines and can be changed.

I know that I answered a bit quickly that the answer is dll only but look at the calculation done in CvMainInterface:
Code:
if ( (pHeadSelectedUnit.movesLeft() % gc.getMOVE_DENOMINATOR()) > 0 ):
	iDenom = 1
else:
	iDenom = 0
iCurrMoves = ((pHeadSelectedUnit.movesLeft() / gc.getMOVE_DENOMINATOR()) + iDenom )

The dll solution is easier because the freeze of the movement is coded there.

It's like for Zlatko's other problem. I was thinking that if it CTD on onCityAcquired it is probably because of the popup that checks for a then non-existing city. It seems easier to check in the dll for the unit with the promotion, shortcircuit the "raze or keep city" popup and raze the city.

I didn't check the dll code though.
 
@Nightinggale
O yeah, i miss that :\

@platyping
Wait, wait, you and Nightinggale confuse me, he said that my idea is cheating, you say that my idea can works.

@isenchine
Yes, i agree with you.
 
If the unit has half a move left (-30), pillaging will change it to (30) rather than (0).
(-60) will change it back to (-30), half a move.
I thought movement was capped at 0. If it isn't, then I see no problems with this approach.

It works, but better to replace 60 with gc.getMOVE_DENOMINATOR()
Somebody once told me that it would not be a bug to hardcode numbers like this as long as all the numbers stay the same. While true for code functionality, I say such code would fail hard in the "code prone to bugs" category.

Yes use gc.getMOVE_DENOMINATOR() and similar functions instead of just writing the number. You never know if you for some reason want to change the number. It would be best if route movement cost is of a number, which multiplied by an int gives MOVE_DENOMINATOR. For 60, it is 1-6, 10, 12, 15, 20, 30. If you take a wild number like 36756720, then the only numbers missing from the range 1-30 would be 19, 23, 25, 29 and the int movement counter would still be able to handle 58 movement points. It would not be human readable numbers, but routes can be as fast as you would like and still make it an int number of plots/movement point. There is a fair amount of math going into finding "the best" number to suit your needs though.

It's not a major issue if you don't get the math behind this. 60 is a relatively good number as it has been used for millennia because it has so many divisors. In fact that's why there are 60 minutes in an hour.
 
Code changed to:
Code:
# < ZLATKO RECONSTRUCTION START >
		if pUnit.isHasPromotion(gc.getInfoTypeForString("PROMOTION_HARMONY_PILLAGE")):
			pUnit.changeMoves((-1)*gc.getMOVE_DENOMINATOR())
			if iImprovement > -1:
				pUnit.changeDamage(-20, false)
# < ZLATKO RECONSTRUCTION END >

There is no infinitive movement in this and in previous code, unit can infinitive pillage on one plot, if unit move to some another plot unit lose movement (as platy said) and can pillage infinitive on that plot but will have 1 instead of 2 movements(because unit is moved from one to another plot), if unit move on next plot, unit movement is 0 and unit can't do anything. There is no infinitive movement for one turn.
 
small problem with Python:
When founding a city on a unit Bunker , the unit bunker remains. But the unit bunker should be killed after the city was founded.
I think the best place for the code should be the def onCityBuilt...but thats all i know.
I downloaded Conflict on Chiron and it turned out to contain an empty folder called CvGameCoreDLL. Either way I have the xml files, which was what I was looking for. I assume you are talking about IMPROVEMENT_BUNKER. Looking in vanilla DLL source, I found this in CvCity::init()
PHP:
CyArgsList argsList;
argsList.add(iX);
argsList.add(iY);
long lResult=0;
gDLL->getPythonIFace()->callFunction(PYGameModule, "citiesDestroyFeatures", argsList.makeFunctionArgs(), &lResult);

if (lResult == 1)
{
	if (pPlot->getFeatureType() != NO_FEATURE)
	{
		pPlot->setFeatureType(NO_FEATURE);
	}
}

pPlot->setImprovementType(NO_IMPROVEMENT);
It should call citiesDestroyFeatures in python, then depending on the return value destroy the feature. After that it should destroy the improvement.

Based on what I can see here, it should work. Next step would be to compile a debug DLL, set a breakpoint at the last line and step through the code to see how/why it fails to do as expected. Naturally doing that would require access to the DLL source code.
 
Back
Top Bottom