Controlling art style of unit models displayed in UI

Leoreth

Bofurin
Retired Moderator
Joined
Aug 23, 2009
Messages
38,035
Location
風鈴高等学校
Recently it was brought to my attention that if you look into another player's city (e.g. via espionage) and it is currently building a unit, the model of the unit being displayed uses the art style of the currently active player, not the owner of the city. This can have confusing consequences such as a European civ's city building an Asian Spearman just because the player has an Asian art style.

However, looking into the code, it seems not so easy to control this. This is what draws the model in my interface code (BUG mod):
Code:
screen.addUnitGraphicGFC( "InterfaceUnitModel", CyInterface().getOrderNodeData1(i), 175, yResolution - 138, 123, 132, WidgetTypes.WIDGET_HELP_SELECTED, 0, -1,  -20, 30, 1, False )
As you can see, the method only takes a unit type and then draws the model, presumably assuming that it belongs to the active player, using their art style.

Is there any way to get around this? I'd really like to display the unit model based on the art style of the player controlling the city instead.
 
The way I would investigate this would be to debug the DLL. Add a call just prior to that line and call some function the DLL. Use a breakpoint in that function. Once it break, add a breakpoint in getUnitInfo or something and move on. Once it reach the new breakpoint, look at the stack to see where it is gathering information. Getting the unit art style has to somehow interact with the DLL. There is also a CvUnit function to get the artstyle... or something like that.

I'm sure this is indeed possible to fix. The question is how hard it will be and if it requires a hack or can be done cleanly.
 
So this is what is being called directly from the EXE:
Code:
const CvArtInfoUnit* CvPlayer::getUnitArtInfo(UnitTypes eUnit, int iMeshGroup) const
{
   CivilizationTypes eCivilization = getCivilizationType();
   if (eCivilization == NO_CIVILIZATION)
   {
       eCivilization = (CivilizationTypes) GC.getDefineINT("BARBARIAN_CIVILIZATION");
   }
   UnitArtStyleTypes eStyle = (UnitArtStyleTypes) GC.getCivilizationInfo(eCivilization).getUnitArtStyleType();
   EraTypes eEra = getCurrentEra();
   if (eEra == NO_ERA)
   {
       eEra = (EraTypes) 0;
   }
   return GC.getUnitInfo(eUnit).getArtInfo(iMeshGroup, eEra, eStyle);
}
My solution was to add another CvGame member m_eCityScreenOwner that is by default NO_PLAYER, but can be set to the player controlling the currently displayed city from Python. Then I modified the method to:
Code:
const CvArtInfoUnit* CvPlayer::getUnitArtInfo(UnitTypes eUnit, int iMeshGroup) const
{
   CivilizationTypes eCivilization;

   PlayerTypes eCityScreenOwner = GC.getGameINLINE().getCityScreenOwner();
   if (eCityScreenOwner == NO_PLAYER)
   {
       eCivilization = getCivilizationType();
   }
   else
   {
       eCivilization = GET_PLAYER(eCityScreenOwner).getCivilizationType();
   }

   if (eCivilization == NO_CIVILIZATION)
   {
       eCivilization = (CivilizationTypes) GC.getDefineINT("BARBARIAN_CIVILIZATION");
   }

   UnitArtStyleTypes eStyle = (UnitArtStyleTypes) GC.getCivilizationInfo(eCivilization).getUnitArtStyleType();
   EraTypes eEra = getCurrentEra();
   if (eEra == NO_ERA)
   {
       eEra = (EraTypes) 0;
   }
   return GC.getUnitInfo(eUnit).getArtInfo(iMeshGroup, eEra, eStyle);
}

And then set/reset the owner of the shown city screen before and after the unit is displayed:
Code:
gc.getGame().setCityScreenOwner(CyInterface().getHeadSelectedCity().getOwner())
screen.addUnitGraphicGFC( "InterfaceUnitModel", CyInterface().getOrderNodeData1(i), 175, yResolution - 138, 123, 132, WidgetTypes.WIDGET_HELP_SELECTED, 0, -1,  -20, 30, 1, False )
gc.getGame().resetCityScreenOwner()

Which worked like a charm :) Thanks for your help!
 
Back
Top Bottom