1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

[MODCOMP]Tax and Investment slider

Discussion in 'Civ4 - SDK/Python' started by gfurst, Oct 4, 2010.

  1. gfurst

    gfurst Warlord

    Joined:
    Sep 4, 2010
    Messages:
    202
    Location:
    Beagá, MG, Brasil
    The original thread was here : http://forums.civfanatics.com/showthread.php?t=387680
    May offer some more information on my idea.
    I'll update this first post as the project progress.

    Main idea:
    -> Overall commerce produced by a city will have and Tax:commerce: multiplier, the result is named usable commerce.
    -> Then usable commerce is divided into the usual :gold::science::culture::espionage: in each city
    -> So, before usual slider there would be a tax slider, from 0 to 100, and later all the usual sliders with 0 to 100 total sum between them.
    -> Add triggers to xml for buildings/civics for when sliders go up/down( ie same way theater increases :culture:/10% :culture: slider)(ie +1 :mad: citizen/ 10% tax rate on democracy)(ie library +1 :science: point/ 10% research investment) you got the idea ;).

    little graph to demonstrate:


    Changes should be made in SDK( thx Baldyr) since the code would occur in every single city in the game.
    Change to python code, since( correct me if i'm wrong) most interface options use python.
    AI would use regular code for the previous sliders, since its almost the same, with the addition to the tax slider. But shouldn't be too hard since effects from it would be directly converted to bonuses.


    I've never modded so i could need some help :p, although I'm very familiar with c++ language, never used python before but seems to be really easy, xml also.
    The most troubling is that i have Linux and I'm not sure if i can compile the DLL directly in my machine.
    I'm currently reading An idiots Guide to Editing DLL which is quite good!

    Anyway, needing help finding cpp files regarding economic mechanics in the Game core, and what variables they use, if some knows or have a holy spirit in between, please, i appreciate it!

    Thx
     
  2. Baldyr

    Baldyr "Hit It"

    Joined:
    Dec 5, 2009
    Messages:
    5,530
    Location:
    Sweden
    Any Python documentation you might need, with your programming experience, can be found on Python.org. The CivIV Python API is located here. The Cy classes mostly mirror Cv classes in the SDK, so you would be able to easily check out what exactly any of them does. Since almost averything is also available in C++ there would be little point for you to create your own Python scripts. (Editing the pre-existing interface modules is probably necessary though.)

    The game also includes a module called PyHelpers which wraps useful stuff into a more convenient API. You should be able to find it amongst the Python modules in the game. Since you already know OOP you would probably be able to pick up Python simply by looking at the PyHelpers code, as it uses the Python API just as you would while modding.

    So Python is the least of your worries.
     
  3. gfurst

    gfurst Warlord

    Joined:
    Sep 4, 2010
    Messages:
    202
    Location:
    Beagá, MG, Brasil
    I think i found it!!!! (yeeaayyyy)

    This little snippet of code
    Code:
    CvCity.cpp/L=7009
    int CvCity::getTotalCommerceRateModifier(CommerceTypes eIndex)
    {
    	return max(0, (getCommerceRateModifier(eIndex) + GET_PLAYER(getOwnerINLINE()).getCommerceRateModifier(eIndex) + ((isCapital()) ? GET_PLAYER(getOwnerINLINE()).getCapitalCommerceRateModifier(eIndex) : 0) + 100));
    }
    Is the total commerce rate modifier for a city, found in CvCity.cpp line 7009.
    What it does is basically sums up the rate modifier from several functions, modifier from city itself + player modifier overall + modifier for player capital...

    Didn't understand the parameter (CommerceTypes eIndex) but it seems to be a identifier of what type of commerce it is, maybe :gold::science: and stuff?

    This is one place to make changes, but a better option should be:

    Code:
    CvPlayer.cpp/L=9056
    int CvPlayer::getCommerceRateModifier(CommerceTypes eIndex)
    {
    	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    	FAssertMsg(eIndex < NUM_COMMERCE_TYPES, "eIndex is expected to be within maximum bounds (invalid Index)");
    	return m_aiCommerceRateModifier[eIndex];
    }
    However i couldn't find the return method, thus have no idea what it is, possibly a arrays of containing variables that are rates per CommerceTypes.
    I need to figure out what is this commerce type class, tonight I'll pray, hehe.

    Perhaps instead of commerce, i should look for yield, since commerce is a yield such as food and hammers.
     
  4. God-Emperor

    God-Emperor Deity

    Joined:
    Jul 18, 2009
    Messages:
    3,551
    Location:
    Texas
    Commerce itself is a yield type. As such it's generation is dealt with using functions with the word "yield" in their names rather than "commerce". These use YieldType values to specify if they are dealing with food, production, or commerce.

    The functions with "commerce" in their names that use the CommerceType values are involved with the gold, research, culture, and espionage (the 4 CommerceType values represent these) that result from the split via the slider and other modifiers (buildings and such).

    So to adjust the pre-split raw commerce yield you need to look at the various functions with "yield" in their names (and probably the functions that call them). To mess with how the split is done you'd look at the ones with "commerce" in their names (and probably the functions that call them).
     
  5. gfurst

    gfurst Warlord

    Joined:
    Sep 4, 2010
    Messages:
    202
    Location:
    Beagá, MG, Brasil
    Yeah i could gather that from further noising the source file, yield type should not be the answer, cause maybe they don't include trade routes, I'll have better at it, keeping track of some many functions and such big files is hard, going to write it down :).

    The problem now is figuring out where the splitter is, the best option is multiplie the tax rate before split happens.

    One thing i got confused, a lot of the ...CommerceRate.. functions are both in CvCity.cpp and CvPlayer.cpp, don't know if i'm supposed to look in city or player files...
    such as "int m_aiCommerceRate[NUM_COMMERCE_TYPES];" exists in both scopes, aren't they supposed to be the same? opsss just found something useful...
    "int m_aiCommercePercent[NUM_COMMERCE_TYPES];"

    Let's see if i got right... City commerce rates -> commerce type splitter -> local commerce modifiers -> global player sink -> player modifiers -> final player rates

    My taxrate variable would go to the player as a global status, but would be used locally before commerce in city splits... one thing i didn't get, like in the code above, it uses the rate modifier of the player to change something locally, maybe i'm just confused.

    Anyway, long hours, giving it a little break. thx for the input God-Emperor.
    Do you have any personal input about the mod( like/hate/none)?
     
  6. Baldyr

    Baldyr "Hit It"

    Joined:
    Dec 5, 2009
    Messages:
    5,530
    Location:
    Sweden
    You can find all the CivIV "types" here.
     
  7. gfurst

    gfurst Warlord

    Joined:
    Sep 4, 2010
    Messages:
    202
    Location:
    Beagá, MG, Brasil
    Thx guys, the types Baldyr sent helped clear my mind, new day and already making progress...
    Found this:

    Code:
    CvCity.cpp/L=6979
    int CvCity::getCommerceFromPercent(CommerceTypes eIndex, int iYieldRate)
    {
    	int iCommerce;
    
    	iCommerce = ((iYieldRate * GET_PLAYER(getOwnerINLINE()).getCommercePercent(eIndex)) / 100);
    
    	if (eIndex == COMMERCE_GOLD)
    	{
    		iCommerce += (iYieldRate - iCommerce - getCommerceFromPercent(COMMERCE_RESEARCH, iYieldRate) - getCommerceFromPercent(COMMERCE_CULTURE, iYieldRate));
    	}
    
    	return iCommerce;
    }
    It does basically get the trade yield rate and multiplies the percent:)science::culture::espionage:), the gold rate is the same and any leftovers from overall commerce that might exist. I didn't get why espionage isn't on that sum.
    Later this returns to getBaseCommerceRate and to all possible modifiers already existent in the game...

    Chaging line
    Code:
    iCommerce = ((iYieldRate * GET_PLAYER(getOwnerINLINE()).getCommercePercent(eIndex)) / 100);
    to
    Code:
    iCommerce = ((iYieldRate * GET_PLAYER(getOwnerINLINE()).getCommercePercent(eIndex)) * GET_PLAYER(getOwnerINLINE()).getTaxPercent() / 10000);
    should do the trick, and the TaxPercent related functions on the CvPlayer.cpp scope.

    On that aspect is almost the same to CommercePercent related, but simpler. After that how the slider works, i will probably use some of Bug/Bull interface change( the +-5%). And finally work the slider to the AI. And some optional features maybe.
     
  8. Baldyr

    Baldyr "Hit It"

    Joined:
    Dec 5, 2009
    Messages:
    5,530
    Location:
    Sweden
    You should probably make your mod with the BUG mod as a base. If you don't, you'll probably end up regretting it...
     
  9. Afforess

    Afforess The White Wizard

    Joined:
    Jul 31, 2007
    Messages:
    12,239
    Location:
    Austin, Texas
    Actually, I'd recommend Better BUG AI as a base. Include BUG, BULL, the UP, and BBAI mods, all essential for BTS.
     
  10. gfurst

    gfurst Warlord

    Joined:
    Sep 4, 2010
    Messages:
    202
    Location:
    Beagá, MG, Brasil
    I'm using RevDCM as a base, it should contain all of those essentials right? I'm not actually using anything yet, perhaps is time to set up the mod directory? As yet it still is just in planning phase, coding after all takes only a couple minutes if well planned.

    I've found this modcomp, and it was just what i was looking for( complementary with this one). The modder however is inactive in quite a while, his modpack also seems incomplete, and files where from before the hacker attack. So files lost( NO!!!).

    Anyone knows something related to this?
     
  11. gfurst

    gfurst Warlord

    Joined:
    Sep 4, 2010
    Messages:
    202
    Location:
    Beagá, MG, Brasil
    Baldyr, if you want to help, i could use you to figure out how to deal with the interface thingy.
    EmperorFool already told me where to find it in the BUG mod, it's a python file and i got a bit confused :crazyeye:
    If you do want, i'll enter the details, but it's basically just to add a new slider.
     
  12. Baldyr

    Baldyr "Hit It"

    Joined:
    Dec 5, 2009
    Messages:
    5,530
    Location:
    Sweden
    Oh, I've never dabbled with the interface myself. (Not yet anyway. :mischief:) If you have Python related issues I might be able to help none-the-less, but someone else would be more qualified actually... But we can just figure it out together - you, me and the rest of the modding community. :)
     
  13. Afforess

    Afforess The White Wizard

    Joined:
    Jul 31, 2007
    Messages:
    12,239
    Location:
    Austin, Texas
    You are going to need to create a new widget for the slider in the SDK. Look at how the commerce sliders work for an rough example of what you need for that widget.
     
  14. gfurst

    gfurst Warlord

    Joined:
    Sep 4, 2010
    Messages:
    202
    Location:
    Beagá, MG, Brasil
    That seems the best way to go :)

    Thanks, i will take a look at it right away, although i should read more in modding documentation before.
     
  15. gfurst

    gfurst Warlord

    Joined:
    Sep 4, 2010
    Messages:
    202
    Location:
    Beagá, MG, Brasil
    ok i found:
    Code:
    		.def("getCommercePercent", &CyPlayer::getCommercePercent, "int (CommerceTypes eIndex)")
    		.def("setCommercePercent", &CyPlayer::setCommercePercent, "int (CommerceTypes eIndex, int iNewValue)")
    		.def("changeCommercePercent", &CyPlayer::changeCommercePercent, "int (CommerceTypes eIndex, int iChange)")
    In CyPlayerInterface1.cpp, with the description:
    Published python interface for cyplayer.

    I guess this is the interface between the DLL and the python scripts, how do i find where they are being called? I still don't have a proper IDE to edit python, though efficiently searching the calls.
    I'm afraid my ignorance is starting to show :blush::confused:
     
  16. gfurst

    gfurst Warlord

    Joined:
    Sep 4, 2010
    Messages:
    202
    Location:
    Beagá, MG, Brasil
    Just found this:

    Code:
    	# Will update the percent buttons
    
    	def updatePercentButtons( self ):
    
    
    
    		screen = CyGInterfaceScreen( "MainInterface", CvScreenEnums.MAIN_INTERFACE )
    
    
    
    		for iI in range( CommerceTypes.NUM_COMMERCE_TYPES ):
    
    			szString = "IncreasePercent" + str(iI)
    
    			screen.hide( szString )
    
    			szString = "DecreasePercent" + str(iI)
    
    			screen.hide( szString )
    
    
    
    		pHeadSelectedCity = CyInterface().getHeadSelectedCity()
    
    
    
    		if ( not CyInterface().isCityScreenUp() or ( pHeadSelectedCity.getOwner() == gc.getGame().getActivePlayer() ) or gc.getGame().isDebugMode() ):
    
    			iCount = 0
    
    
    
    			if ( CyInterface().getShowInterface() != InterfaceVisibility.INTERFACE_HIDE_ALL and CyInterface().getShowInterface() != InterfaceVisibility.INTERFACE_MINIMAP_ONLY and CyInterface().getShowInterface() != InterfaceVisibility.INTERFACE_ADVANCED_START):
    
    				for iI in range( CommerceTypes.NUM_COMMERCE_TYPES ):
    
    					# Intentional offset...
    
    					eCommerce = (iI + 1) % CommerceTypes.NUM_COMMERCE_TYPES
    
    										
    
    					if (gc.getActivePlayer().isCommerceFlexible(eCommerce) or (CyInterface().isCityScreenUp() and (eCommerce == CommerceTypes.COMMERCE_GOLD))):
    
    						szString1 = "IncreasePercent" + str(eCommerce)
    
    						screen.setButtonGFC( szString1, u"", "", 70, 50 + (19 * iCount), 20, 20, WidgetTypes.WIDGET_CHANGE_PERCENT, eCommerce, gc.getDefineINT("COMMERCE_PERCENT_CHANGE_INCREMENTS"), ButtonStyles.BUTTON_STYLE_CITY_PLUS )
    
    						screen.show( szString1 )
    
    						szString2 = "DecreasePercent" + str(eCommerce)
    
    						screen.setButtonGFC( szString2, u"", "", 90, 50 + (19 * iCount), 20, 20, WidgetTypes.WIDGET_CHANGE_PERCENT, eCommerce, -gc.getDefineINT("COMMERCE_PERCENT_CHANGE_INCREMENTS"), ButtonStyles.BUTTON_STYLE_CITY_MINUS )
    
    						screen.show( szString2 )
    
    
    
    						iCount = iCount + 1
    
    
    
    						if (gc.getActivePlayer().isCommerceFlexible(eCommerce)):
    
    							screen.enable( szString1, True )
    
    							screen.enable( szString2, True )
    
    						else:
    
    							screen.enable( szString1, False )
    
    							screen.enable( szString2, False )
    
    							
    
    		return 0
    I just don't know what to make of it... For it seems to be only updating the graphics( yes i know how to read the description. humm maybe looking for "updatePercentButtons" would be a good idea... report back
     
  17. gfurst

    gfurst Warlord

    Joined:
    Sep 4, 2010
    Messages:
    202
    Location:
    Beagá, MG, Brasil
    ok, reporting back i still dunno exactly how the python code works, but i found the widgetDLL stuff, found one that gets the commerce from the current player.
    Sorry, i kinda took a break today, played a little... yeah i still play :p

    Is there anywhere with a scheme or information about how the data goes from the DLL to the python( game interface, dunno if that's correct)
     
  18. Baldyr

    Baldyr "Hit It"

    Joined:
    Dec 5, 2009
    Messages:
    5,530
    Location:
    Sweden
    Its not completely clear what is unclear, and I hesitate to tell a real programmer how to read code... But the code seems to control what commerce types are present in the "sliders" (top left interface) at any given time, and what sliders are enabled/disabled depending on the situation.

    What exactly do you wanna do with this, then? (I'm not entirely sure if I'm following you trail of though on this thing, so please explain more precisely and we'll figure it out yet.)
     
  19. Baldyr

    Baldyr "Hit It"

    Joined:
    Dec 5, 2009
    Messages:
    5,530
    Location:
    Sweden
    Hell, here goes. I'm not familiar with the CyGInterfaceScreen class, but I can always guess. And those who know can always correct me where I'm wrong...
    Code:
    	def updatePercentButtons( self ):
    Method definition, takes no parameters/arguments except the class instance (with dot notation). I have no idea if this means anything for someone who works with C++.
    Code:
    		screen = CyGInterfaceScreen( "MainInterface", CvScreenEnums.MAIN_INTERFACE )
    The value assigned to the screen variable (which isn't defined anywhere, its created on-the-fly) is a CyGInterfaceScreen instance (which takes two parameters). I'm guessing this is just the way the game is setup and you can access different interface elements with another set of settings. :dunno:
    Code:
    		for iI in range( CommerceTypes.NUM_COMMERCE_TYPES ):
    The range() built-in function actually creates a list type (data structure). In the default BtS game there are 4 CommereTypes values and this is also why the value for CommerceTypes.NUM_COMMERCE_TYPES is 4. So the function call range(4) will return this:
    Code:
    [0, 1, 2, 3]
    The for/in loop will then access the data one element at the time, beginning with the first one (zero). Basic ordered iteration with Python.
    Code:
    			szString = "IncreasePercent" + str(iI)
    
    			screen.hide( szString )
    
    			szString = "DecreasePercent" + str(iI)
    
    			screen.hide( szString )
    There is obviously a CyGInterfaceScreen.hide() method but I wouldn't know what it does. Looking at the context it seems like these lines are just used to hide the stuff that will be set/enabled later by default, so it would only be necessary to reveal those that are actually to be shown. Or something. And this is done with adding a string like "IncreasePercent0" or "DecreasePercent1" as an argument to the method. The str() function of course converts any type to string type, like the iI integer value from above.
    Code:
    		pHeadSelectedCity = CyInterface().getHeadSelectedCity()
    The pHeadSelectedCity is assigned a reference to a CyCity object that is mirroring a CvCity object created in the SDK. Obviously there is a method for fetching such a ting in the CyInterface class. This is probably the city that is active at a given moment in the game, or something. (Is some city always active? :confused:)
    Code:
    		if ( not CyInterface().isCityScreenUp() or ( pHeadSelectedCity.getOwner() == gc.getGame().getActivePlayer() ) or gc.getGame().isDebugMode() ):
    The rest of the code will only be executed if the city screen is active, or if the pHeadSelectedCity value belongs to the active player, or if the game is run in "debug mode". So otherwise the slider thingies will not be visible, then.
    Code:
    			iCount = 0
    The following code will be counting the number of widgets used, or something. So we assign the iCount variable a default value.
    Code:
    			if ( CyInterface().getShowInterface() != InterfaceVisibility.INTERFACE_HIDE_ALL and CyInterface().getShowInterface() != InterfaceVisibility.INTERFACE_MINIMAP_ONLY and CyInterface().getShowInterface() != InterfaceVisibility.INTERFACE_ADVANCED_START):
    The following block of code will not be executed if the interface has been hidden, limited or is not yet available. I would have done it this way however:
    Spoiler :
    if not CyInterface().getShowInterface() in [InterfaceVisibility.INTERFACE_HIDE_ALL,
    InterfaceVisibility.INTERFACE_MINIMAP_ONLY, InterfaceVisibility.INTERFACE_ADVANCED_START]:

    Moving on:
    Code:
    				for iI in range( CommerceTypes.NUM_COMMERCE_TYPES ):
    This we already covered - the commerce types (accessed with the integer values 0-3) are looped one more time. This time things may or may not be enabled/shown.
    Code:
    					# Intentional offset...
    
    					eCommerce = (iI + 1) % CommerceTypes.NUM_COMMERCE_TYPES
    This time around we'll not be using the iI value directly, but use a modulus operation to sort them in this order instead: 1, 2, 3, 0. So CommerTypes.COMMERCE_GOLD comes last, then.
    Code:
    					if (gc.getActivePlayer().isCommerceFlexible(eCommerce) or (CyInterface().isCityScreenUp() and (eCommerce == CommerceTypes.COMMERCE_GOLD))):
    Next condition will only pass if the active player is "commerce flexible" (permitted to alter the sliders?) - or if the city screen is up and its the last iteration (gold).
    Code:
    						szString1 = "IncreasePercent" + str(eCommerce)
    
    						screen.setButtonGFC( szString1, u"", "", 70, 50 + (19 * iCount), 20, 20, WidgetTypes.WIDGET_CHANGE_PERCENT, eCommerce, gc.getDefineINT("COMMERCE_PERCENT_CHANGE_INCREMENTS"), ButtonStyles.BUTTON_STYLE_CITY_PLUS )
    
    						screen.show( szString1 )
    
    						szString2 = "DecreasePercent" + str(eCommerce)
    
    						screen.setButtonGFC( szString2, u"", "", 90, 50 + (19 * iCount), 20, 20, WidgetTypes.WIDGET_CHANGE_PERCENT, eCommerce, -gc.getDefineINT("COMMERCE_PERCENT_CHANGE_INCREMENTS"), ButtonStyles.BUTTON_STYLE_CITY_MINUS )
    
    						screen.show( szString2 )
    Now we are using CyGInterfaceScreen.show() to reveal what was hidden at the beginning of the method definition. We also use the CyGInterfaceScreen.setButtonGFC() method to add the + and - buttons. And use a lot of strange parameters which we do not worry about. One of them is calculated with the iCount variable, which comes next:
    Code:
    						iCount = iCount + 1
    So I guess each line in the commerce sliders is 19 pixels apart, then...
    Code:
    						if (gc.getActivePlayer().isCommerceFlexible(eCommerce)):
    
    							screen.enable( szString1, True )
    
    							screen.enable( szString2, True )
    
    						else:
    
    							screen.enable( szString1, False )
    
    							screen.enable( szString2, False )
    And finally we enable the widgets/buttons/whatever if the active player can change the commerce sliders. Otherwise we disable them, although they may still be visible.
    Code:
    		return 0
    For some reason the method always returns the value zero, which is a stand-in for False. Otherwise it would return -1/None (Nill).

    In short: I think that you can make edit this function to both make individual sliders visible/invisible to your specifications, as well as decide whether or not they are actually accessible (or merely visible). Is this something you need to do?
     
  20. Baldyr

    Baldyr "Hit It"

    Joined:
    Dec 5, 2009
    Messages:
    5,530
    Location:
    Sweden
    Yeah, do that. So there should be one tax slider and four investment sliders, then? But since the investment sliders are already present as the default commerce sliders, then you only need to add the new tax slider? Like above the others...? Is the main tax slider available in the city screen or only outside of it? While the investment sliders are only available in city view...? :confused:
     

Share This Page