python to change unit art?

davidlallen

Deity
Joined
Apr 28, 2008
Messages
4,743
Location
California
I have a working "limited fuel" mod and gunships. When the gunship runs out of fuel, I want the unit art to be different, the rotor should be still and the shadow should show it on the ground. Refar has contributed the "grounded gunship" art.

Is there a good way to change the art (only) of a unit in python?

The only way I could think of is to create a copy of the unit, GROUNDED_GUNSHIP. When the unit runs out of fuel, create a new unit, copy its damage, experience, and promotions, and delete the old unit. Same thing in reverse when it gets refueled.

This is working, sort of, but there is one inefficiency and one problem. So I am hoping somebody can suggest a different approach.

The inefficiency: I need to copy the promotions, and there is no way to iterate like CyUnit.getNumPromotions, CyUnit.getPromotion(i). I don't want to have to loop *all* promotions with "if unit1.isHasPromotion(promo): unit2.setHasPromotion(promo,true)". So I have manually built a list in python of all the promotions the gunship could have, and I loop through that instead. It is still inefficient. Is there any way to loop the promotions that a unit has?

The problem: I am missing something about experience. There is a call getExperience, fine. But, the prototype for setExperience is (int experience, int max_experience). Huh? How do I know what the max experience is? There is no getMaxExperience or anything similar. I am calling with -1 since I don't know what else to pass. But, the new unit has an incorrect "next level" threshold.

Suppose the original unit has 3 XP, so its next level is 4. The XP shows up in the display as "(3/4)" and it is not eligible for any new promotion. I copy the unit as I have described. The new copy shows up with XP "(3/2)" and it is now eligible for promotion! Of course it has the one promotion already since I copied it. It seems that copying the unit gives it a free promotion eligibility.

I don't know if it will help any, but here is the related python function.

Code:
   def changeGunship(self, pOld, hasGas):
      iOwner = pOld.getOwner()
      pOwner = self.gc.getPlayer(iOwner)
      if hasGas: iType = self.gc.getInfoTypeForString("UNIT_GUNSHIP")
      else: iType = self.gc.getInfoTypeForString("UNIT_GUNSHIP_GROUND")
      pNew = pOwner.initUnit(iType, pOld.getX(), pOld.getY(),
         UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_EAST)
      pNew.setDamage(pOld.getDamage(), iOwner)
      pNew.setExperience(pOld.getExperience(), -1)
      pNew.setScriptData(pOld.getScriptData())
      # No efficient way to loop promotions I have?
      for iPromo in self.gunPromos:
         if pOld.isHasPromotion(iPromo): pNew.setHasPromotion(iPromo, true)
      pOld.kill(false, iOwner)
 
Looping through all the promos to see which ones a unit has when your cloning the unit isn't really ineffiecient. Its how fraxis does it in the few examples I've seen. If they made a CyUnit.getNumPromotions, the SDK code would just loop through all promos and count the number the unit had. There is really no other way to do it.

EDIT: I remember seeing something about you being able to change a units graphic in game, but don't recall the name. Give me a minute and I'll look it up.

EDIT2: Bad news, after looking at the SDK, it seems they didn't expose CyUnit.setArtInfo to python.
 
EDIT2: Bad news, after looking at the SDK, it seems they didn't expose CyUnit.setArtInfo to python.

Thanks for the information regarding the inability to change unit art with python. Thats one thing I can scratch off my list for the mod I'm working on.
 
Thanks for the investigation on changing unit art.

Any suggestions on how to work around the max experience problem?
 
Thanks for the investigation on changing unit art.

Any suggestions on how to work around the max experience problem?

Yea, give me a while, I am bout to play some Civ with my buddy, but after that I will look into it and see if I can come up with an answer for ya. :cool:
 
-1 mean no limit for experience, so this is good. For the experience tou need to set also the level of the unit. Or perhaps simply use the function convert, it does all in one.

Tc ho !
 
I would have thought the engine could figure out the level given the number of experience points. I see there is also CyUnit.getLevel() and setLevel(). I will try calling that in addition. What is the convert function you mention?
 
I would have thought the engine could figure out the level given the number of experience points.

But if you want to have free xp to choose some level, obviously the level doesn't match.

What is the convert function you mention?

almost exactly what you want to do :

python call :
Spoiler :
Code:
newUnit = pPlayer.initUnit(...)
newUnit.convert(pOldUnit)

convert SDK function :
Spoiler :
Code:
void CvUnit::convert(CvUnit* pUnit)
{
	CvPlot* pPlot = plot();

	for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{
		setHasPromotion(((PromotionTypes)iI), (pUnit->isHasPromotion((PromotionTypes)iI) || m_pUnitInfo->getFreePromotions(iI)));
	}

	setGameTurnCreated(pUnit->getGameTurnCreated());
	setDamage(pUnit->getDamage());
	setMoves(pUnit->getMoves());

	setLevel(pUnit->getLevel());
	int iOldModifier = std::max(1, 100 + GET_PLAYER(pUnit->getOwnerINLINE()).getLevelExperienceModifier());
	int iOurModifier = std::max(1, 100 + GET_PLAYER(getOwnerINLINE()).getLevelExperienceModifier());
	setExperience(std::max(0, (pUnit->getExperience() * iOurModifier) / iOldModifier));

	setName(pUnit->getNameNoDesc());
	setLeaderUnitType(pUnit->getLeaderUnitType());

	CvUnit* pTransportUnit = pUnit->getTransportUnit();
	if (pTransportUnit != NULL)
	{
		pUnit->setTransportUnit(NULL);
		setTransportUnit(pTransportUnit);
	}

	std::vector<CvUnit*> aCargoUnits;
	pUnit->getCargoUnits(aCargoUnits);
	for (uint i = 0; i < aCargoUnits.size(); ++i)
	{
		aCargoUnits[i]->setTransportUnit(this);
	}

	pUnit->kill(true);
}

Tcho !
 
Ah-ha! "pNew.convert(pOld) ; pOld.kill()" does exactly what I need, thanks! I never would have tried convert(), in my documentation it is listed, but nothing says what it does.
 
Top Bottom