• Our friends from AlphaCentauri2.info are in need of technical assistance. If you have experience with the LAMP stack and some hours to spare, please help them out and post here.

[MODCOMP] Unit Statistics

I really like the mod. Promotions are now showing. I found another bug, I think. My Warrior number 4 built in Paris shows to be an archer built in Bejing....:D

warrior_4.JPG
 
Code:
					typenumber = 0
	
					UnitTypeNumber = {
										TYPENUMBER : typenumber }
							
					sdEntityInit("UnitStats", unitI.getDescription(), UnitTypeNumber)
				number = sdGetVal("UnitStats", unitI.getDescription(), TYPENUMBER)
				number = number + 1
				sdSetVal("UnitStats", unitI.getDescription(), TYPENUMBER, number)
unit.setName(unitI.getDescription() + " " + str(number))

Could you explain to me how this works? I normally code in Visual basic 6.0 (please stop laughing) and I can't seem to understand. I know if you explain to me or give me a link to a thread or site that explains these functions perhaps then I will understand how you incrementing the number of each unit, which you then add to the units name.

I ask this because I have a great idea on naming and want to expand this to give the user several options for naming. But to do so I need to understand this code.

Thanks, and once my idea is coded and working I will pass it on to you to see what you think.

Also, I have successfully integrated this mod and the Merc mod together.
 
@Jeff1787: Thanks again for the report. When AI units call my functions, I get a mess. I now included some conditionals that should make sure that this doesn't happen again. I also tried giving the AI units full access to the statistics (so that I would get the "real" statistics of captured workers, but the result was even worse (I saved the attempt as unitstats2 in case anyone can help).


@Nexushyper:

I coded the mod in notepad, but now that you mention it, I should probably switch ;) (I didn't really plan to make an own mod, so I didn't think of a comfortable editor)

as to the code:

first of all, you need the SD Toolkit

at the top of the unitstats file, you can see

Code:
#######SD Tool Kit#######

import SdToolKit
sdEcho         = SdToolKit.sdEcho
sdModInit      = SdToolKit.sdModInit
sdModLoad      = SdToolKit.sdModLoad
sdModSave      = SdToolKit.sdModSave
sdEntityInit   = SdToolKit.sdEntityInit
sdEntityExists = SdToolKit.sdEntityExists
sdGetVal       = SdToolKit.sdGetVal
sdSetVal       = SdToolKit.sdSetVal

############################

then for the code itself

Code:
			if (len(unit.getNameNoDesc()) == 0):

checks if the unit has a name

Code:
				unitI = PyInfo.UnitInfo(unit.getUnitType())
				if(sdEntityExists("UnitStats", unitI.getDescription()) == False):	

					typenumber = 0
	
					UnitTypeNumber = {
										TYPENUMBER : typenumber }
							
					sdEntityInit("UnitStats", unitI.getDescription(), UnitTypeNumber)

this is SD Toolkit specific:

unitI.getDescription() is the string of the unit type, for instance "Tank". If you build your first tank, an entity is created through the SD Toolkit where we can store our data. in this case, I need only one variable, which I call TYPENUMBER.
Code:
				number = sdGetVal("UnitStats", unitI.getDescription(), TYPENUMBER)
				number = number + 1
				sdSetVal("UnitStats", unitI.getDescription(), TYPENUMBER, number)
				unit.setName(unitI.getDescription() + " " + str(number))

sdGetVal fetches the number of tanks already built. I store the value under "number" and add one.
sdSetVal stores the new value back.

unit.setName is the centerpiece of the naming process. All that code before is only here to count the units of each type. If you don't want to do that, you can just leave it out.
 
Ok, that makes sense.

So you are just seeing how many have been made and adding one then adding that to the name. In this Case Tank.

Thus the fifth tank built will be named Tank 5. So if Tank 4 is destroyed and you build tank #6 it will still be named Tank 6 and not Tank 4. Correct?


Also, I found UnitCombatTypes. Which returns:

-1 = NO_UNITCOMBAT
0 = UNITCOMBAT_RECON
1 = UNITCOMBAT_ARCHER
2 = UNITCOMBAT_MOUNTED
3 = UNITCOMBAT_MELEE
4 = UNITCOMBAT_SIEGE
5 = UNITCOMBAT_GUN
6 = UNITCOMBAT_ARMOR
7 = UNITCOMBAT_HELICOPTER
8 = UNITCOMBAT_NAVAL

So ships fall under 8, and ground units (land) fall under 1 thru 6. Helicopter is 7. Where do bombers, and planes go??


I ask this because I have an idea for naming. Based on Land, Sea or Air units. Depending on which type depends on the name.

The other part of this is instead of using the number of that type built I wanted to use a list. So, is there a way to create an entity with a list? Several entities (Like a database stroage) for several lists?

Here is the idea for naming that I had.
Tank 1st Army 1st Corp 1st Div (Which can be user set to look like that, or your way or Tank 1Army 1Corp 1Div or Tank 1A 1C 1D)

Navy will be x Fleet y Group z Squadron
Air will be x Wing y Group z Squadron

Thus the reason I need to know if I can make tables of info. These tables will store numbers.
For instance, the first lets say 5 ground units will be named [unit] 1stArmy 1stCorp 1st - 5thDiv. The code will pull the numbers from a table of numbers not used (one for each, Army, Corp, Div) and then add that number to a counter. (first unit made will add 1, then second unit will replace it with 2, etc) When that counter hits 5 it moves to 2nd Corp and names 1st - 5th Div. You see where i am going with this?

I also need the tables so if Tank 2nd Army 4th Corp 3rd Div dies, the next tank will be named that.

Or I can just code it so it doesn't replace lost unit names.


Anyways, if this was Visual Basic I would have had this coded already. But I do not know python, nor all the calls for civ4. I would like to see if I could do this naming I mentioned above, but I need a push. I need to know if it is possible at all. I need to know if it is possible what options I have. (I.E. I should use datastorage.py that so and so made, or I could modify sdtoolkit or use sdtoolkit as is.) Just let me know if this is possible and give me some hints and I'll do my best to make it work.

I know in VB 6.0 I can create my own file type and storage type variable. (I know because i got sick of access files and made my own database storage files.) Is this possible with python? If yes, is it possible with Civ4 python?

Thanks.
 
So if Tank 4 is destroyed and you build tank #6 it will still be named Tank 6 and not Tank 4. Correct?

Yep, that's right.

So ships fall under 8, and ground units (land) fall under 1 thru 6. Helicopter is 7. Where do bombers, and planes go??

I'm not sure, but since planes and bombers don't fight classical combats (they can just bombard or intercept), they might be left out in UnitCombatTypes. If you want to name a unit depending on whether they are naval, land or air units, you coul use unit.getUnitClassType (list see here) and work with conditionals:
Code:
#check if unit is sea unit
(if unit.getUnitClassType() >= 44 and unit.getUnitClassType() <= 54):


The other part of this is instead of using the number of that type built I wanted to use a list. So, is there a way to create an entity with a list? Several entities (Like a database stroage) for several lists?

A list would be easy to implement. Check this List Tutorial.

The code would then look like this

Code:
namelist = ['Tom', 'Snappy', 'Kitty', 'Jessie', 'Chester']
unit.setName(unitI.getDescription() + " " + namelist(number))

apart from the fact that a list starts with 0 instead of 1.

I also need the tables so if Tank 2nd Army 4th Corp 3rd Div dies, the next tank will be named that.

I suggest that you either mark a name as free in an onUnitLostEvent or make a unit list every time you name a unit. The latter method would even save you the work of creating a Database, although I wouldn't call it an elegant way.

I called the unit you want to rename "newunit", unit is the argument of unitList.

Code:
gc.getGame().getActivePlayer().getUnitList()
for name in namelist:
    for unit in unitList:
          if unit.getNameNoDesc() = name:
          #here you'd have to code a way that the name is only changed to the
          #current value of namelist if the above condition is not true for
          #any value of the unitlist.
 
EDIT: Ok I figured it out.

Thanks for the great work on this mod. And thanks for your help.


I should be starting a new thread soon with my version of this mod, with different naming options, as well as Merc Mod all combined. Thanks again!



EDIT 2: Ok so I do have one last question. How do i test my code line by line?
 
I just run civilization with the debugging settings on (check the Debugging Tutorial), but yesterday, I downloaded python so that I now can test simple non-civ-specific commands/lines myself.
 
A very small critique:

"AD" is supposed to come before the year and "BC" comes after the year. Many people don't know this though. In my Kill List mod I had it set up like this but your expansion of my mod seems to have removed this. Was this intentional or an oversite?

Roger Bacon
 
Alright, I need your suggestions / help:

I want to implement high scores of some type. And in order to make the statistics page look nicer, I thought of some buttons/medals for the best units.

I really like the simple and Promotion-like style of Zuul's Promotion Buttons and Rabbit, White's Promotion Buttons, this kind of button would suit me best.

I think the unit statistics could get something similar, but perhaps with a different background (green?).

Now to the thing I'd like your input on. A list with possible high scores and how the button could look like:

unit with most kills: a bloody axe or sword maybe? or burning?

unit with most barbarian kills**: a pierced head? (sounds more like what a barbarian would do if they killed a unit ;))

unit with most animal kills**: a fur?

unit with most civ-specific kills**: don't think this will be implemented, as it gets too crowded...

unit that did the most damage*: same ideas as with most kills.

unit that received the most damage*: blood drops, a cross, something like this

unit that did the most damage while defending*: a shield and a sword

unit that did the most damage while attacking*: sword and axe crossed

unit that received the most damage while defending*: a shield with a blodd drop or a shield with arrows/cuts in it

unit that received the most damage while attacking*: sword and axe crossed, either with a blood drop or battered

unit that has moved furthest: someone with a staff

unit that has moved furthest in enemy territory*: dunno, someone stalking? camouflage?

unit that was transported furthest: a transport helicopter (similar to the airlift-button, but in the promotion-style)

unit that travelled furthest (move + transport): a globe

oldest unit: yoda ;)

unit with most owner changes**: maybe a whip

unit with most experience**: veteran stripes or a medal

unit that survived longest in enemy territory*: something camouflaged?


*not yet implemented, but planned for a release this week.
**probably possible to implement, but implementation not yet planned


This is a list with 18 high scores, which is too much in my opinion. your best units would probably get many of those (10 or more of those stats could easily be won by the same unit), since some of the stats are overlapping (most damage, most kills and most damage attacking/defending by example).

Which stats deserve a button? how many should be made? I want a highscore-button to be something exclusive, only few units should get one. and if you're in favour of implementing a button, please tell me your suggestions how they could look.

Last but not least, I need someone who is willing to draw the actual buttons, but that's no top priority right now. First I want to implement all stats that look promising and doable, so that I have a clear list of what buttons I need.
 
RogerBacon said:
A very small critique:

"AD" is supposed to come before the year and "BC" comes after the year. Many people don't know this though. In my Kill List mod I had it set up like this but your expansion of my mod seems to have removed this. Was this intentional or an oversite?

Roger Bacon

I adapted the way Civ4 shows the years in the upper right corner. Strictly speaking, this is wrong, but it looks consistent. Oh, and it will automatically be corrected if (if, not when ;)) the official files are corrected.
 
Today, the mod made a huge leap (from 1.05 to 1.17).

It has new statistics (damage inflicted), a high score function and is fully configurable. Check the version information for a full list of changes.

but I have also bad news:

the high score function take too long to load (13 sec with 200 units). I have disabled it by default and will think of an alternative way of calculating them.

Nevertheless I'm still optimistic that I'll be able to implement them in a way that doesn't take too much resources and would like your input on the buttons.
 
Teg_Navanis said:
the high score function take too long to load (13 sec with 200 units). I have disabled it by default and will think of an alternative way of calculating them.

Would you like me to take a crack at it?
 
Just to let you know. I successfully integrated this with Merc Mod and a 2 dozen others. I also will be attaching 3 files for you. First one is your file with minor editing on my part. Second is the ini with 1 edited and 3 added. The third file is my own code. (in zip file new naming option.zip)

These files (if you want to use them) give a 4th naming option. The one I discussed earlier in this thread. (Yes I got it to work).


Also, while testing the mod tonight I got this error


Code:
Traceback (most recent call last):

  File "CvEventInterface", line 27, in onEvent

  File "CvCustomEventManager", line 82, in handleEvent

  File "CvCustomEventManager", line 93, in _handleDefaultEvent

  File "CvUnitStatisticsEventManager", line 162, in onUnitLost

  File "UnitStatisticsUtils", line 290, in onUnitLost

  File "SdToolKit", line 144, in sdGetVal

KeyError: u'Settler0'
ERR: Python function onEvent failed, module CvEventInterface


It happened when I used the starting settler to build my first city.
 

Attachments

@TheLopez: I thought of another way to implement it. Every time a value gets updated, get the best unit's ID from a stored data file and check this unit's value. if the updated unit's value is higher, set this unit as the new best unit.

Instead of comparing 5000 values at once, it just compares up to 3 at a time. I think I can add conditionals to only check these values when it makes sense (in onCombatLogHit "if cdDefenderiCurrHitPoint <= 0" (or vice versa, depending on if you're attacking or defending)). I still have to check how often and in what order onUnitSetXY and onUnitMove are called when a tank moves twenty tiles.

@Nexushyper: Thanks, the trash-bin is Name Generator - specific and I forgot not to call it when another one is loaded. You'd have to change the code to make it work for your Name Generator. May I integrate your Name Generator into unit statistics? You might want to create a trashbin similar to mine first.
 
Teg_Navanis: First of all I wanted to thank you for the great work you're doing here, and I wanted to ask you if you could help me with a little problem.

I was trying to use Zulu's 0.5 with your mod but can't find out how to do it as you customevents is like this:

class CvCustomEventManager(CvEventManager.CvEventManager, object):

and his:
class CvCustomEventManager(CvEventManager.CvEventManager):

Thanks in advance and keep up the great work
 
I'll re-implement a classical CustomEventsManager - file for those of you who want to combine it with another mod via copy & paste.
 
I don't yet know what to do with the movement statistics. here what I found out.

to know how I got to the numbers below, open spoiler.
Spoiler :

I moved a stack of 40 units 10 tiles with the go to - command.

(for every unit, the onUnitMove and onUnitSetXY - event are called 10 times each. In every event, 2 high scores are checked)



with the current version of unit statistics, this movement takes 10 seconds.

without unit statistics, 1 second.

with a test version of unit statistics that checks/updates the movement high scores after every move, it takes 35 seconds.



I made some maths and this is what I got:

moving one unit one tile would take 1/10 second with the test version (high scores)

moving one unit one tile takes 2/100 seconds with the current version

moving one unit one tile takes 2/1000 seconds without the mod.



checking/updating a high score takes 2/100 additional seconds.



calculating high scores the way I had in mind takes this long:

when a unit is created: 2/100 additional seconds
when a unit won a fight: 12/100 additional second
when a unit moves: 1/10 additional second

I don't think updating the high scores on unit creation and after every (won) fight is inconvenient for the player, but moving large stacks could/will get annoying with this method.

If I calculate the movement high scores the current way (every time the unit statistics are opened), it would take 1 sec to open the unit statistics per 70 units. If I implement the update of the high scores in the onBeginGameTurn - event, the AI-turns would take 1 additional second per 70 units you have and the movement high score would not be totally up-to-date.


Which solution do you think is best? or better leave them out?
 
Teg_Navanis said:
I'll re-implement a classical CustomEventsManager - file for those of you who want to combine it with another mod via copy & paste.
Kimbal and Teg, you can use the CvCustomEventManager file from the Merc Mod special edition and strip out the merc related info. Otherwise if you want I'll upload a copy of the merged CvCustomEventManager file for the merge between PnP V0.5 and Unit Stats.
 
Here is the zip file containing the two files you need to merge the Promotions and Unit Stats mods.
 

Attachments

Teg_Navanis
Sure use it all you want. I was hoping you would use it as it would save me a bit a time when you make updates. That is, if you use it as a naming option that is one less file I have to edit when you make updates and I go to merge it with my mod.

:)

EDIT: To view my entire mod which has your wotk and TheLopez's work see this thread http://forums.civfanatics.com/showthread.php?t=163524
 
Back
Top Bottom