azxeus Posted November 26, 2015 Share Posted November 26, 2015 with special characters gaining perks and training roulette making duplicate ones i was thinking of making a mod that will check which perks the character already has and not put them into the perk tree.problem is, im not exactly sure how to do this.i know i could find the perk(s) using a loop to check for each perk in the enum such as:if i < 170 loop {if char.hasupgrade(i) then do somethingi++} but im not sure where to go from there and would like some pointers? Link to comment Share on other sites More sharing options...
tracktwo Posted November 27, 2015 Share Posted November 27, 2015 XGStrategySoldier.AssignRandomPerks is the one that handles training roulette IIRC. You can put a check for perks the character already has there, or in IsRandomPerkValidToAdd(), which is called by AssignRandomPerks. But this presupposes that the custom perks are assigned to the character before the perk trees are rolled, which I'm not sure is the case. If that's the case though you can possibly call AssignRandomPerks again after the custom perk has been added, or special case certain perks in IsRandomPerkValidToAdd based on soldier name. Link to comment Share on other sites More sharing options...
azxeus Posted November 27, 2015 Author Share Posted November 27, 2015 the perk trees are rolled when a class is chosen, you can see this when you take a class defining perk away from a solider then give it back to them in the barracks, even if the perk is the same one, the game thinks they changed class and so assigns them a new perk tree (in training roulette of course).This means that unless they use console to give a perk after a class is picked checking for perks at this point should be fine, not that it would really be possible to do anything about perks been given after the tree is set anyway.But since training roulette alone wouldn't include special soldiers and the code wouldn't be entered if the SW option wasn't on to make this work for Zhang, Doorn. etc in a normal game I was thinking of putting something into the XGStrategySoldier.SetSoldierClass (which is what calls AssignRandomPerks) That seems to be what checks which perk is picked from a supra class to determine which subclass to assign.. but I can't see where it's creating the perk tree Link to comment Share on other sites More sharing options...
azxeus Posted December 10, 2015 Author Share Posted December 10, 2015 so i think i found the function that i need my check to be in which is XGStrategySoldier.GetPerkInClassTree but there aren't any available variables for me to use my perk checking loop:var = 0;if var < 172 loopif{ if m_kSoldier.HasPerk(var) { //check against GetPerkInTree here } ++var} help? Dx Link to comment Share on other sites More sharing options...
tracktwo Posted December 11, 2015 Share Posted December 11, 2015 (edited) I'm not entirely sure I follow your loop there, but you should be to steal the "I" variable as it's only used in the non training roulette case: I = m_arrRandomPerks[3*(branch-1) + Option];while (m_kSoldier.HasPerk(I) { // I = roll a new random perk}return I; EDIT: However, just returning a random perk # here is probably not what you want as each time this function is called you'd get a different result. Worse, when it populates the tree in the UI it calls this function to get the perks and the soldier will obviously have the ones you've already chosen and it'd re-roll them. This really needs to be done at the point where the perk tree is rolled or when the "free" perks are added otherwise you can't distinguish between a perk they chose from an earlier rank and one that was granted for free. Edited December 11, 2015 by tracktwo Link to comment Share on other sites More sharing options...
azxeus Posted December 11, 2015 Author Share Posted December 11, 2015 (edited) Huh? i dont know what you are talking about, the variable I in GetPerkInClassTree is used to determine the class if(((IsOptionEnabled(4)) && !IsASuperSoldier()) && branch != 1) { return m_arrRandomPerks[(3 * (branch - 1)) + Option]; } I = GetClass(); // End:0x11F if(true) { // End:0x11F if((branch != 1) || IsAugmented()) { I = m_iEnergy; } This really needs to be done at the point where the perk tree is rolled or when the "free" perks are added otherwise you can't distinguish between a perk they chose from an earlier rank and one that was granted for free. It Shouldn't matter if the perk was from an earlier rank because you can't have the same perk twice, my loop should check every perk to see if the soldier already has it before looking at his tree and if he does stop it from being able to appear or be chosen from the tree, this would for example stop van doorn's promotion from being messed up when he gets to a rank that contains steadfast Edited December 11, 2015 by azxeus Link to comment Share on other sites More sharing options...
azxeus Posted December 11, 2015 Author Share Posted December 11, 2015 maybe it would be possible to repurpose I.. suchas if((branch != 1) || IsAugmented()){ return PERKS().GetPerkInTree(byte(m_iEnergy), branch, Option, bIsPsiTree);}else{ return PERKS().GetPerkInTree(byte(GetClass()), branch, Option, bIsPsiTree);} Link to comment Share on other sites More sharing options...
azxeus Posted December 11, 2015 Author Share Posted December 11, 2015 (edited) maybe it would be possible to repurpose I.. suchas if((branch != 1) || IsAugmented()){ return PERKS().GetPerkInTree(byte(m_iEnergy), branch, Option, bIsPsiTree);}else{ return PERKS().GetPerkInTree(byte(GetClass()), branch, Option, bIsPsiTree);}so i tested this with no other changes and it works fine but then i tried to add my loop: if((branch != 1) || IsAugmented()) { I = 0; J0xFD: // End:0x1D1 [Loop If] if(I < 172) { // End:0x1D1 if(m_kSoldier.HasPerk(I)) { // End:0x1D1 if(GetPerkInTree(byte(m_iEnergy), branch, Option, bIsPsiTree) = GetPerk(I)) { return PERKS().GetPerk(0); goto label_end } // End:0x271 } ++ I; // [Loop Continue] goto J0xFD; return PERKS().GetPerkInTree(byte(m_iEnergy), branch, Option, bIsPsiTree); goto J0x271; } return PERKS().GetPerkInTree(GetClass(), branch, Option, bIsPsiTree); } #label_end return ReturnValue; this seems to crash the game when i look at the abilities screen extra perk or not Edited December 12, 2015 by azxeus Link to comment Share on other sites More sharing options...
tracktwo Posted December 12, 2015 Share Posted December 12, 2015 I'm not entirely sure what you're trying to accomplish with that loop. It's going to loop over every perk in the game, and if you already have that perk and that perk is the one in the perk tree, it'll return an invalid perk. If the soldier doesn't have any perks it'll just run off the end of the loop (the check for HasUpgrade will never match) and I'm not sure what will happen cause I only see the snippet there and not the full function. But if I'm understanding your initial message correctly, you want to avoid special soldier dupes in TR. Like avoiding steadfast appearing in the TR perk tree on PVD. Like I said in a previous message, trying to change the perks returned by GetPerkInClassTree on-the-fly is going to be super buggy because that function is used all over the place, like as soon as you enter the abilities screen. It needs to use that function to populate the perk tree in the UI: this is how it knows which perks to put in the tree, including marking the perks you've already selected on promotion in the tree. Having the perk in the tree is also how the game decides whether or not a soldier is eligible for promotion: if you have enough XP for a rank but no perk from that level in the tree you can promote. So if you change GetPerkInClassTree to always return a different perk if you already have some perk in the tree things are going to get really weird really fast, like infinite promotion to all perks in the game weird. For the game to work properly GetPerkInClassTree() needs to return exactly the same perk every time if you call it with the same arguments. Consider it this way: as far as the game is concerned there is no difference between a regular soldier at LCPL rank with TR on where I rolled steadfast at the LCPL rank and manually chose it from PVD at LCPL rank where the game auto-assigned steadfast before I got a chance to choose something myself. In both cases the game sees the soldier has the steadfast perk and the steadfast perk appears at the LCPL level in the tree, but there is no way for it to tell whether the perk was assigned manually by the player or automatically by the game at that point. The only place where I can make that distinction are 1) when the perks are rolled or 2) when the auto-assigned perks are assigned. Since 1) happens before 2) this needs to be done at 2). Custom reward soldiers are awarded by XGFundingCouncil.GiveCustomSoldier, so that's where 2) happens. You can see the block for PVD near the bottom in the check for the nickname "The General" (Zhang and Annette are detected by their custom heads rather than their nicknames near the top of the function). Probably the thing to do is to add code here that walks the m_arrRandomPerks array for that soldier to see if the perk they are going to be auto-awarded is in there. if it is, replace it with some other random perk not already in their tree. Sadly there aren't really any free variables to use to iterate over the perks in the perk tree. But note that the very last statement in that function is Soldier.m_kChar.aStats[2] = 0, so that is as good a place as any. You can just re-roll that single perk, but then need to take care of ensuring it's a valid TR perk and that you don't already have it. Probably simpler is to just reroll the whole tree until you get one that doesn't have the auto perk. Pseudo-Code (untested): TopOfLoop: for (Soldier.m_kChar.aStats[2] = 0; Soldier.m_kChar.aStats[2] < Soldier.m_arrRandomPerks.Length; ++Soldier.m_kChar.aStats[2]) { if (Soldier.HasUpgrade(Soldier.m_arrRandomPerks[Soldier.m_kChar.aStats[2]]) { Soldier.AssignRandomPerks(); goto TopOfLoop; } } Link to comment Share on other sites More sharing options...
azxeus Posted December 12, 2015 Author Share Posted December 12, 2015 i've been trying to get this to work for non-TR games before i tackle TR (since it's easily possible to get this problem even with no random perks) i thought getperkinclasstree was the bast place to do this and put something separate somewhere else for TRwhat i posted is most of the file apart from the bit at the top about TR and what you described is what i want to happen.. but im not sure why it doesnt Link to comment Share on other sites More sharing options...
Recommended Posts