Amineri Posted January 21, 2014 Author Share Posted January 21, 2014 (edited) So I was looking through Monjul's posted changes, and I'm a little confused about the change to XGAIBehavior_Psi.HasPredeterminedAbility. For starters I couldn't apply it as there was an error in the BEFORE_HEX header (the memory size in what was posted was B9 03 00 00 and appears to me that it should be BD 03 00 00). The only change to the code appears to be the removal of AddBestPsiAbilityToList(m_arrPsiAbilities, 40) // 40 = eAbility_PsiPanic However, there are still the lines : if(FindPriorityAbility(m_kPredeterminedAbility)) { m_kTargetToView = m_kPlayer.m_kMindFrayTarget return true } AddBestPsiAbilityToList(m_arrPsiAbilities, 39) // 39 = eAbility_PsiControl FindPriorityAbility may be okay, as it allows the setting of priority targets at the XGAIPlayer level. FindPriorityAbility sets MindFray as predetermined under the condition: if((kAbility_Out == none) && m_kPlayer.m_kPriorityUnit == m_kUnit) { kAbility_Out = XGAbility_Targeted(m_kUnit.FindAbility(57, m_kPlayer.m_kMindFrayTarget)); } If that doesn't happen, then there are backups to set Psi Control (39) and Psi Panic (40) via : if((kAbility_Out == none) && m_kPlayer.m_kPsiAttacker == m_kUnit) { kAbility_Out = XGAbility_Targeted(m_kUnit.FindAbility(39, m_kPlayer.m_kMindFrayTarget)); if((kAbility_Out == none) || !kAbility_Out.CheckAvailable()) { kAbility_Out = XGAbility_Targeted(m_kUnit.FindAbility(40, m_kPlayer.m_kMindFrayTarget)); } } These depend on the current unit being designated as either the m_kPlayer.m_kPriorityUnit (for MindFray), or m_kPlayer.m_kPsiAttacker (for psi control or psi panic). Regardless of whether the XGAIPlayer predetermined abilities are kept, I think that the automatic selection of PsiControl should also be removed. Here is a modified version of the change (which changes a smaller portion of the function) : MODFILEVERSION=4 UPKFILE=XComGame.upk GUID=5B 06 B8 18 67 22 12 44 85 9B A8 5B 9D 57 1D 4B // XComGame_EW_patch1.upk FUNCTION=HasPredeterminedAbility@XGAIBehavior_Psi // remove AI using predetermined psi powers and instead use them based on scoring // keep the XGAIPlayer designated predetermined selection of psi powers for designated unit(s) [BEFORE_HEX] [CODE] //AddBestPsiAbilityToList(m_arrPsiAbilities, 39) 1B E2 01 00 00 00 00 00 00 01 80 A0 00 00 2C 27 4A 16 //kDrainTarget = GetDrainTarget() 0F 00 B3 A0 00 00 1B 4F 38 00 00 00 00 00 00 16 //if(kDrainTarget != none) 07 5D 01 77 00 B3 A0 00 00 2A 16 //kAbility = XGAbility_Targeted(m_kUnit.FindAbility(45, kDrainTarget)) 0F 00 B4 A0 00 00 2E BA 8A 00 00 19 01 8F 9A 00 00 15 00 7F 3A 00 00 00 1B C1 32 00 00 00 00 00 00 2C 2D 00 B3 A0 00 00 16 //if((kAbility != none) && kAbility.CheckAvailable()) 07 5D 01 82 77 00 B4 A0 00 00 2A 16 18 20 00 19 00 B4 A0 00 00 0A 00 69 89 00 00 00 1C 6A 89 00 00 16 16 //m_arrPsiAbilities.AddItem(kAbility) 55 01 80 A0 00 00 0A 00 00 B4 A0 00 00 16 //if(m_arrPsiAbilities.Length == 1) 07 5D 01 9A 36 01 80 A0 00 00 26 16 //m_kTargetToView = kDrainTarget 0F 01 59 9A 00 00 00 B3 A0 00 00 //AddBestPsiAbilityToList(m_arrPsiAbilities, 40) 1B E2 01 00 00 00 00 00 00 01 80 A0 00 00 2C 28 4A 16 [/CODE] [/BEFORE_HEX] [AFTER_HEX] [CODE] //AddBestPsiAbilityToList(m_arrPsiAbilities, 39) -- replace with null ops of same memory/file size 01 80 A0 00 00 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B //kDrainTarget = GetDrainTarget() 0F 00 B3 A0 00 00 1B 4F 38 00 00 00 00 00 00 16 //if(kDrainTarget != none) 07 5D 01 77 00 B3 A0 00 00 2A 16 //kAbility = XGAbility_Targeted(m_kUnit.FindAbility(45, kDrainTarget)) 0F 00 B4 A0 00 00 2E BA 8A 00 00 19 01 8F 9A 00 00 15 00 7F 3A 00 00 00 1B C1 32 00 00 00 00 00 00 2C 2D 00 B3 A0 00 00 16 //if((kAbility != none) && kAbility.CheckAvailable()) 07 5D 01 82 77 00 B4 A0 00 00 2A 16 18 20 00 19 00 B4 A0 00 00 0A 00 69 89 00 00 00 1C 6A 89 00 00 16 16 //m_arrPsiAbilities.AddItem(kAbility) 55 01 80 A0 00 00 0A 00 00 B4 A0 00 00 16 //if(m_arrPsiAbilities.Length == 1) 07 5D 01 9A 36 01 80 A0 00 00 26 16 //m_kTargetToView = kDrainTarget 0F 01 59 9A 00 00 00 B3 A0 00 00 //AddBestPsiAbilityToList(m_arrPsiAbilities, 40) -- replace with null ops of same memory/file size 01 80 A0 00 00 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B [/CODE] [/AFTER_HEX] Edited January 21, 2014 by Amineri Link to comment Share on other sites More sharing options...
monju125 Posted January 22, 2014 Share Posted January 22, 2014 Huh, must have been a copy error (B9 03 00 00 is the post change memory size). I think I applied the change directly to the UPK and then copied it to the UPK modder file, but never applied it through that. As far as mind control goes, that's entirely up to you. We hadn't really discussed whether or not we it should be removed from HasPredeterminedAbility. In practice you typically won't see Sectoids using mind control as a predetermined skill, as it has a very low chance to hit (unless you've altered MIND_CONTROL_DIFFICULTY) since there's a control in AddBestPsiAbilityToList that will skip an ability if it has less than a 20% chance to hit: if((kAbility != none) && kAbility.CheckAvailable()) { kTarget = kAbility.GetPrimaryTarget(); // End:0x136 if(((kTarget == none) || !kTarget.IsAliveAndWell()) || kAbility.GetHitChance() < 20) { continue; } My feeling is that if somehow a Sectoid or other psionic user does find themselves with a greater than 20% chance of mind controlling a unit, it might not be too unreasonable for them to try it. Link to comment Share on other sites More sharing options...
monju125 Posted January 22, 2014 Share Posted January 22, 2014 Ah, I see, we're talking about eAbility_PsiControl, not eAbility_MindControl. I would actually keep the line for eAbility_PsiControl in HasPredeterminedAbility and assign eAbility_PsiControl to Ethereals and EtherealUbers (and any other units you want to have stronger psionic abilities) because it isn't affected by MIND_CONTROL_DIFFICULTY and will be used as a predetermined ability when available. eAbility_MindControl is different; it doesn't have an entry in HasPredeterminedAbility and has its efficacy modified by MIND_CONTROL_DIFFICULTY, thus I would grant it to lesser psionic users such as Sectoids. Link to comment Share on other sites More sharing options...
Amineri Posted January 22, 2014 Author Share Posted January 22, 2014 Ohhhh.... right on. I hadn't savvied to the fact that psi control didn't have the -20 will malus like mind control does. Those are some interesting points to ponder. I still have to work out how to dynamically grant Sectoids abilities as the campaign progresses (currently this can only be done via the DGC.ini Characters= entry). I think I'd like to see them start out with Psi Panic, then get access to MindFray, and finally access to mindcontrol/psicontrol (not sure which). As a side note, Mindfray applies a -50 will malus, so a Mindfrayed target is quite easy to mind control, but it isn't always terribly useful to do so since the target is still suffering from the -50 aim and -50% mobility maluses. A combination of sectoids using MindFray + Mind Control would probably be more effective psychologically than in terms of actual potential damage (excepting the possible use of grenades). Link to comment Share on other sites More sharing options...
monju125 Posted January 22, 2014 Share Posted January 22, 2014 A change could be made to mind control that clears the effects of mindfray when its applied making that combo much stronger. That said, I know I sometimes use mind control just to remove a unit from the fight for a few turns, use its grenade, or just to scout for me, and you could argue that it is powerful enough as it is. Link to comment Share on other sites More sharing options...
Amineri Posted January 24, 2014 Author Share Posted January 24, 2014 I'm thinking that psi control / mind control is powerful enough as it is. If you have to use MindFray + Mind Control to improve your odds then you also have to live with the debilitated unit. ------------ In another area I'm a little less keen on having MindMerge as a Predetermined Ability. I just witnessed a sectoid move to a flanking position (taking the only flanking position available) and the decide to mindmerge its ally instead of taking the flanking shot. The mindmerged ally then didn't have a flanking position to move to. That said, there's a bunch of special code put in to prevent MindMerging when the unit is in a vulnerable position, which care would need to be taken to not break. Link to comment Share on other sites More sharing options...
monju125 Posted January 25, 2014 Share Posted January 25, 2014 On a slightly different topic, I've been considering tinkering with pod tactics and noticed something strange while looking through the XGTactic classes. This is in XGTactic_Hunt: function ChooseHuntPath() { // End:0x1C if(Roll(100)) { DirectHunt(); } // End:0x42 else { // End:0x38 if(Roll(50)) { WideHunt(); } // End:0x42 else { FlankHunt(); } } //return; } That means that there is a 100% chance that DirectHunt will be chosen instead of the other two. I'm not sure why they even bothered putting the rest of that code in there. Link to comment Share on other sites More sharing options...
Amineri Posted January 25, 2014 Author Share Posted January 25, 2014 I'd guess that either (a) they implemented all three but then found that the wide hunt and flank hunt code didn't work, so they effectively removed it with the Roll(100), or (b) it's a bug. Link to comment Share on other sites More sharing options...
monju125 Posted January 25, 2014 Share Posted January 25, 2014 Yeah, I just found it funny. XGTactic_Hunt is currently only ever used in the EXALT missions, so it's not all that noticeable anyway. I changed it to see what would happen, and I'll have to verify in the code, but it seemed like the pods were switching hunt paths every turn, which lead to some odd behavior. Leads me to believe they probably changed it on purpose. Link to comment Share on other sites More sharing options...
monju125 Posted January 26, 2014 Share Posted January 26, 2014 Verified. In XGOvermind.BeginTurn: if(UpdateActiveCapturePoint()) { // End:0x121 foreach m_arrPods(kPod,) { kPod.CompleteTactic(); } DetermineCaptureAndHoldTactics(); } else { // End:0x15F if(BattleDesc().m_iMissionType == 5) { DetermineCovertExtractionTactics(); } } Then DetermineCaptureAndHoldTactics and DetermineCovertExtractionTactics both create and initialize a new XGTactic_Hunt calling ChooseHuntPath in the process. So, every turn, each pod switches its hunt path. It's kind of funny to watch; they'll run directly toward the cap point one turn (Direct Hunt), then divert off to the side the next turn (Wide/Flank Hunt), and then just keep changing their minds until eventually they end up in the cap point. Link to comment Share on other sites More sharing options...
Recommended Posts