patel-nikhil / SHCLiveStatReader

A program that reads and stores Stronghold Crusader stats, as they happen in game
7 stars 2 forks source link

working out after-game stats screen #4

Closed GRhin closed 4 years ago

GRhin commented 4 years ago

So, we have noticed that the after-game stats are all located around the same area, so to facilitate finding these stats. i have made a spreadsheet containing all adress locations around the area of the stats we have already found. and labeled the addresses we know (and bolded)

https://docs.google.com/spreadsheets/d/1Pg_LMhhTN82vhezguDuMJTtXuZGSOAAXtZyzpfY7SIw/edit?usp=sharing

Note that the odd-number player names are off by 2 bytes. There are some convenient gaps that could include pitch, total kills, score, or something similar. If you want to check out addresses, or know where some are, let me know and i can update it.

void4 commented 4 years ago

The creator of http://statsmylord.com/ (@lawrencefoley, also on the Sourcehold Discord) may have more information on the structure.

Somewhere in there should be the "death" skull image

GRhin commented 4 years ago

Thats great, at this stage i think we have found everything he has, plus a bit more. I think we have even found the death time/date... One of the big things i want to find is the "score" the thing that defines the order of greatest lord... I think i know the adress by looking at this sheet, but havent had a chance to look yet.

lawrencefoley commented 4 years ago

This is a really cool project! Awesome to see someone working on something similar to my website. Looks like you have all the stats that I have on my website, but I would be more than happy to share my findings or code. It's a bit of a mess right now so I'd like to clean it up before putting it on a public repo, but I could share pieces of it if that would help.

As for the "score" value, I had looked for that a while myself. I'll let you know here if I find it before the rest of the group does.

Also, would it be ok if I used the memory addresses the group find in my website? @patel-nikhil

Edit: I've attached my config file. This is for versions 1.4 and 1.4.1 of the SHC. config.zip

patel-nikhil commented 4 years ago

@lawrencefoley I just opened your website - very nicely done!

My codebase is still in very early stages, and now that I know with help from @GRhin more information regarding offset between player stats, etc. I plan to revise make my logic more modular and efficient.

@GRhin has been helping me significantly with finding the memory values, and barring any objections from him, of course, I'm more than happy to let you use it on your website

GRhin commented 4 years ago

@lawrencefoley thanks for the zip, will browse soon. I hadnt seen your project before void pointed it out, and I like the idea. I actually have a different application of the same idea on the backburner (much more complex, but what you have would be a part of it). If you are willing to share info when i get into it properly, add me on discord GRhin#9114 and ill explain the details of my application

Also, did you know about the weighted kills/deaths? They are much more informative when comparing players. I.e. 100 slaves lost is weighted to 100, but 100 E.archer gets weighted to 500, i have a list somewhere of the values of each unit, except for seige equipment and tunnelors which arent recorded. Ping my on discord if you want it.

And as another point, do you know how the stars in the after-game screen are calculated? a friend has been trying to work out a pattern to see how it decides to give 5 stars, or 2 or 11, and hasnt come up with anything.

void4 commented 4 years ago

@lawrencefoley I had a look at your config.json, can you explain what the "ID" field represents? Also, do you generate the .json file from a table? Or do you edit it manually? In my MemoryReader, I use a more compact table format: https://github.com/void4/PySHCLiveReader/blob/master/tables.py

@GRhin In your Google Doc, you have many "P1 Kills P1", "P1 Kills P2" etc. fields. Are these unit kills?

GRhin commented 4 years ago

Good news, I have found today: -Players present in game (557-55E) -Time at which players died (5A4-5C0) -Gaia kills player x (5A4-5C0) -# of Lords killed by player x (7EA-7F1) -Weighted Buildings Destroyed (864-880)

void4 commented 4 years ago

Are the addresses the same if UCP is not installed? Edit: Have you found a way to make the game not fullscreen?

GRhin commented 4 years ago

I think so, but cannot be 100% certain as I have not checked

On Tue, 18 Feb. 2020, 1:55 am void4, notifications@github.com wrote:

Are the addresses the same if UCP is not installed?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/patel-nikhil/SHCLiveStatReader/issues/4?email_source=notifications&email_token=ALGGWTVHA4ZRF4S2DKS5UVLRDKQNRA5CNFSM4KV6R2T2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEL6WHRI#issuecomment-587031493, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALGGWTTAKGIIFIVB2YLMLXLRDKQNRANCNFSM4KV6R2TQ .

lawrencefoley commented 4 years ago

@lawrencefoley thanks for the zip, will browse soon. I hadnt seen your project before void pointed it out, and I like the idea. I actually have a different application of the same idea on the backburner (much more complex, but what you have would be a part of it). If you are willing to share info when i get into it properly, add me on discord GRhin#9114 and ill explain the details of my application

Also, did you know about the weighted kills/deaths? They are much more informative when comparing players. I.e. 100 slaves lost is weighted to 100, but 100 E.archer gets weighted to 500, i have a list somewhere of the values of each unit, except for seige equipment and tunnelors which arent recorded. Ping my on discord if you want it.

And as another point, do you know how the stars in the after-game screen are calculated? a friend has been trying to work out a pattern to see how it decides to give 5 stars, or 2 or 11, and hasnt come up with anything.

@GRhin I'll DM you on Discord. I haven't found where the weighted kills are. I'd love to know though. :-)

@void4 Oh, the ID field doesn't mean anything. I generate that JSON file from a CheatEngine file so that ID just corresponds to the ID in the CheatEngine file I have. I prefer the JSON format because it's more structured, but I'd be open to working on a different format together.

Also, more of a general question: What version of the game are you guys using? I'm using the 1.4 and 1.4.1 version of the Steam game.

GRhin commented 4 years ago

This is 1.41E, I use extreme when i stream for the extra unit limit, but without magic bar and outposts etc. And that's where i am displaying these stats (over the game for viewers) I'm guessing you should be able to use one of the values you already know, and find the rest with offsets. Ie. If you have total buildings destroyed, and we have weighted kills 32 bytes away from that, you can move 32 bytes away from your memory location to find it. Note that 32 was just a random number, not sure the actual offset

@GRhin In your Google Doc, you have many "P1 Kills P1", "P1 Kills P2" etc. fields. Are these unit kills?

Yes. It is how many units each player has killed from each enemy

lawrencefoley commented 4 years ago

@GRhin That makes sense. I used that same offset method when finding the values for different versions of the game.

lawrencefoley commented 4 years ago

For the "score" value that determines the greatest lord; Isn't this based on kills and gold? Wasn't sure if it is affected by other things in the game.

GRhin commented 4 years ago

Nikhil is testing now to see what effects it. i can tell you that already he has found that gold and weighted buildings destroyed effects it. and resources dont effect it.

patel-nikhil commented 4 years ago

I've now added the greatest lord score calculation to my program. This is the greatest lord score for when the game has ended - greatest lord is calculated differently while the game is in progress.

The score is calculated based on the following factors:

The following is the calculation the game uses to calculate greatest lord score. Note A >> B is shift right, (also I believe, equal to integer division by 2), repeated B times

        const long multiplier = 0x66666667;
        long goldBonus = ((gold * multiplier) >> 32) / 4;
        long score = goldBonus + weightedKills + weightedBuildings * 100;
        score = score + (score * lordKills) / 4;
        Int32 dateBonus = (endYear - startYear) * 12;
        dateBonus -= startMonth;
        dateBonus += endMonth;

        if (dateBonus < 1)
        {
            dateBonus = 1;
        }
        Int32 bonusDivider = 200 + dateBonus;

        score = score * 200;
        score = score / bonusDivider;
        return score;

Here is a Python function I wrote that calculates the score. Not the cleanest, but I chose to write it that way as that was how it was done in disassembly. Also, I chose to hard code start year and month in my Python function for convenience; in practice my program reads all the values as they are stored in game.

GRhin commented 4 years ago

What is the multiplier? Looks like an address? Does the lordsKilled divisor change defendant on the number of players?

patel-nikhil commented 4 years ago

Multiplier is a fixed value in hexadecimal. The divide by 4s are actually shift arithmetic right (sar) 2 in the dissassembly -> also fixed The divider of 200 also appears to be fixed.

Calculation runs for each player and I didn't see any of those values changed in-between, so not dependent on other factors from what I saw

I'm pretty sure some of my test scenarios had different numbers of players, I'll go back and test again when I have time.

GRhin commented 4 years ago

What is that fixed value?

patel-nikhil commented 4 years ago

The fixed value is the one I use in the function. So 0x66666667 is the multiplier for gold. ie. the dissassembly does: mov eax, 0x66666667 and then imul (multiply) ecx

By fixed value I mean to say it's not loaded from another memory address. It's part of the instruction.

GRhin commented 4 years ago

But that is an address right? What is stored at that address? If it's an equation then it amounts to 0 as 0 x anything is 0, which wouldn't work. So it must be a pointer.

On Tue, 25 Feb. 2020, 1:06 pm Nikhil, notifications@github.com wrote:

The fixed values are the ones I use in the function. So 0x66666667 is the multiplier for gold. ie. the dissassembly does: mov eax, 0x66666667 and then imul (multiply) ecx

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/patel-nikhil/SHCLiveStatReader/issues/4?email_source=notifications&email_token=ALGGWTQ4H2H3X5BHHILEDMTRER4ITA5CNFSM4KV6R2T2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEM2IIYA#issuecomment-590644320, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALGGWTTLFXZVEW66UVKK2CTRER4ITANCNFSM4KV6R2TQ .

patel-nikhil commented 4 years ago

No, 0x66666667 is the number, as shown in the image, not the address of another number. 0x just means it's a hexadecimal number. And ecx register contains the total gold produced

image

GRhin commented 4 years ago

That's a massive multiplier. Can you tell me what (multiplier >> 32) equates to? As that is the effective multiplier...

patel-nikhil commented 4 years ago

multiplier >> 32 is equivalent to multiplier / 2^32

GRhin commented 4 years ago

Yea I meant the decimal result of that, all good will do soon when I have the opportunity

patel-nikhil commented 4 years ago

Comes out to 0.4

GRhin commented 4 years ago

Then divided by 4, so its effectively Gold bonus = gold/10

patel-nikhil commented 4 years ago

Yea that seems to be it. I never thought to compute the decimal value, just followed the same logic and calculation, using the hex values to remove any room for error

GRhin commented 4 years ago

I think we have found everything here that we are going to.... so will close ticket.