Here's what I have so far, with uninteresting unknown values removed, and some of the more interesting unknown fields left in.
Code: Select all
PrisonerStruct [size=488]:
+0008 = DWORD UnknownDword1
+000C = DWORD UnknownDword2
+0010 = DWORD ID_u
+0014 = DWORD ID_i
+0018 = DWORD EntityType (?)
+001C = DWORD SubType
+0020 = float Position_X
+0024 = float Position_Y
+0028 = float Or_X // rotation x: -1.0 = lean left, 0.0 = look straight ahead, +1.0 = lean right
+002C = float Or_Y // rotation y: 0 = face forwards, -1.0 = face backwards. large values (5, -5) make handcuffs appear in funny places.
+0038 = float UnknownFloat1
+003C = float Damage // 0.0 = healthy, 1.0 = dead
+0044 = void* UnknownPtr1
+0048 = void* UnknownPtr2
+004C = void* UnknownPtr3
+0050 = void* UnknownPtr4
+0060 = DWORD UnknownDword3
+009C = void* PtrToStartOfList
+00B0 = float NextPosition_X // this is a guess - the values are almost identical to Position X/Y
+00B4 = float NextPosition_Y // just have to assume that this is their position on the next frame / waypoint?
+00BC = DWORD UnknownID_u
+00C0 = DWORD UnknwonID_i
+00E0 = float UnknownFloat2
+00EC = float Destination_X
+00F0 = float Destination_Y
+00FC = float Velocity_X
+0100 = float Velocity_Y
+0110 = DWORD Cell_u
+0114 = DWORD Cell_i
+0134 = float UnknownFloat3
+0144 = char[16] Forename
+0154 = DWORD ForenameLength
+0158 = DWORD ForenameLengthMax
+0160 = char[16] Surname
+0170 = DWORD SurnameLength
+0174 = DWORD SurnameLengthMax
+0178 = float Age
+017C = DWORD UnknownDword4
+0180 = DWORD UnknownDword5
+0184 = DWORD UnknownDword6
+018C = float GangTimer
+0190 = DWORD GangID
+019C = DWORD PrisonerNeedCount
+01A0 = PrisonerNeedStruct** NeedsList // Pointer to a list of PrisonerNeedStruct entries
+01A8 = float UnknownFloat5
+01C4 = DWORD UnknownDword7
+01C8 = DWORD UnknownDword8
The NeedsList entry is a pointer to an array of PrisonerNeedStruct entries, which describe the prisoner's needs. From what I can work out, ActionPoint is the level when the need becomes immediate, e.g. "I have to go to the toilet". Charge is the current level that this prisoner is currently at, for this need. TimeToAction is the amount of time before Charge = ActionPoint, so I guess the rate is deduced from this. Not exactly sure how TimeToFailure works, but it looks like the amount of time before the prisoner gets angry about not having fulfilled this need.
Code: Select all
PrisonerNeedStruct [size=96]:
+0004 DWORD UnknownDword1
+0008 DWORD UnknownDword2
+000C DWORD Id_u
+0010 DWORD Id_i
+0014 DWORD NeedType // see PrisonerNeedTypes
+0018 float ActionPoint
+001C float TimeToAction
+0020 float TimeToFailure
+0024 float Charge
Here's the PrisonerNeedType values (they're DWORDs):
Code: Select all
bladder = 1
bowels = 2
sleep = 3
food = 4
hygiene = 5
comfort = 6
excercise = 7
defense = 8
freedom = 9
family = 10
recreation = 11
[dev]weapon = 12
I've not got fully reliable pointer paths to the prisoner array yet, but I'm working on it. Right now I'm using some code injection techniques to leak the base pointer, which is pretty reliable.
Hopefully this will help someone else if they're creating similar tools