Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bonus power inaccessible after unlocking too many powers #176

Closed
MintyFreshGandalf opened this issue Nov 16, 2022 · 3 comments
Closed

Bonus power inaccessible after unlocking too many powers #176

MintyFreshGandalf opened this issue Nov 16, 2022 · 3 comments

Comments

@MintyFreshGandalf
Copy link

Describe the bug
The infamous "too many powers" bug- once a certain amount of powers is reached (through using the bonus power slot for an active power), another power becomes inaccessible from the pause HUD. This leaves several blank slots on the action bar, with no way to access the power unless you had put it on the quickbar in the top left beforehand. Affects both Shepard and companions (though you can't negate the bug through the quickbar with companions).

To Reproduce

  1. Create a Shepard of a class with a lot of powers (Sentinel, Engineer, or Adept).
  2. Select an active bonus power (I.E. Singularity).
  3. Unlock all powers with skill points.
  4. Pull up the pause menu. A power should be missing from the action bar.

Expected behavior
Ideally, a fix would allow all powers to exist on the action bar. With the glitch, there is obviously an empty spot where the power was, so it's an issue with the game's limits and not the number of power slots.

@henbagle
Copy link
Owner

Investigating this. Specifically as it relates to Liara not being able to use Overload. This will likely require a lot of editing of the underlying actionscript of the power UI.

The issue for liara is as follows - the game sends the powers to the UI in a specific order with indices. The UI displays them in that order, leaving any gaps. When Liara has all powers unlocked, the following is called
image
Barrier is in slot 2, etc, Overload is in slot 8. There are only seven slots on the squadmate UI, and nothing is in slot 1. Overload is not shown. The function that calls this in Unrealscript side is native and can't be edited or looked at, so we likely have to adjust from the scaleform side of things while maintaining the order and data that the Unrealscript expects. Continuing to investigate.

@henbagle
Copy link
Owner

henbagle commented May 24, 2023

Okay, I have the bug fixed for squadmates and partially fixed for Shepard. The middle top slot that's usually empty is now the first slot to get filled for Shepard, which allows you have nine powers (I believe the max possible in the vanilla game). The tenth (bottom right) slot is still unavailable even when you add a tenth power as another bonus skill with the console command. I'm investigating this still.

But generally the bug is fixed. I'll post a full write-up with all the code changed when I am finished. This will be included in our next content update coming later this week.

The most noticeable change is that squadmate power slots will all shift down to use as many slots as possible, there will be no empty slots until you run out of powers. Powers fill up from top to bottom for squadmates. First row to second row for shepard, working out from the middle first.

image
Liara has all her powers. Shepard has nine powers available.

@henbagle henbagle added this to the 1.4.1 milestone May 24, 2023
@henbagle
Copy link
Owner

henbagle commented May 26, 2023

Fixed in PC_ME_HUD as well as ME_HUD for squadmates and for Shepard. One power slot remains unusable for Shepard, investigation will be done in the future.

Fixed distributed in the HUDFixes.m3m merge mod along other GUI fixes.

All fixes are minimal ActionScript changes only. Full source code files are attached.

PC_ME_HUD

Edits are based off the fixed DropTheSquid version of this script in #219, this includes the fixes in #24

New global variable added (at the bottom of the script)

// stores the next free squad power slot
var nextSquadPowerSlot = new Array(1, 11, 21);

New function correctSquadmatePowerIndex() added

// LE1CP: Given a power index, returns a corrected index where the power is slotted into the earliest available position
function correctSquadmatePowerIndex(selectedMember, index)
{
    var i = nextSquadPowerSlot[selectedMember];
    nextSquadPowerSlot[selectedMember] = nextSquadPowerSlot[selectedMember] + 1;

    if (i > (selectedMember + 1) * 10)
    {
        return -1 //too many powers, overflowing into squadmate power space
    }
    return i;
}

The first section of PopulateMapPowerItem() updated to read the following

function PopulateMapPowerItem(selectedMember, index, powerName, powerActivatable, powerIcon, barType, barLength, consumableQuantity, markAsFavourite, infoStr, initializationCall)
{
    var _loc7_ = initializationCall || selectedMember > -1 && squadMemberHealth.length > selectedMember && !mapBlockMemberPowerDisplay[selectedMember] && (squadMemberHealth[selectedMember] > 0 || squadMemberHealth[selectedMember] == -1);
    index += selectedMember * (maxMapPowerListSize / 3);

    // LE1CP: Remove "holes" in power order for squadmates.
    // This fixes the Liara overload bug, as well as potential future issues with mod bonus powers
    var originalIndex = index;
    if(powerName != "")
    {
        index = correctSquadmatePowerIndex(selectedMember, index);
        if(index == -1) return; // return early if index is out of bounds
    }
    mapPowerList[index].originalIndex = originalIndex; // for lookup of index game is expecting

    mapPowerList[index].powerName = powerName;
    mapPowerList[index].powerActivatable = powerActivatable;
    mapPowerList[index].powerIcon = powerIcon;
    mapPowerList[index].detailedInfo = infoStr;
    // remainder of the function continues unedited

The start of CreateMapPowerList() edited to the following

function CreateMapPowerList(selectedMember, squadNameFrame, bBlockDisplay, sBlockDisplayLabel)
{
    mapBlockMemberPowerDisplay[selectedMember] = bBlockDisplay;
    nextSquadPowerSlot = new Array(1, 11, 21);
   // remainder of the function continues unedited

activatePower() and setupPower() changed to the following. One line has been added, one line changed, but the full text of both functions is provided here.

function activatePower(i)
{
    var squadMember = int((i - 1) / 10);
    var index = (i - 1) % 10 + 1;
	var pcmc = PCPowers[i];
    if(pcmc == undefined || pcmc.mc == undefined || !pcmc.mc._visible || pcmc.mc.powerIconMC.subPowerIconMC._currentframe == 7)
    {
        return undefined;
    }
    if(highlightedIcon != i)
    {
        return undefined;
    }
    var oSubPowerIconMC = pcmc.mc.powerIconMC.subPowerIconMC;
    if(mapPowerList[i].powerActivatable && squadMemberHealth.length > squadMember && squadMemberHealth[squadMember] > 0 && !mapBlockMemberPowerDisplay[squadMember])
    {
        if(powerQueuedForActivate[squadMember] != index)
        {
            if(powerQueuedForActivate[squadMember] > -1)
            {
                var previousMasterListIndexForMember = i - index + powerQueuedForActivate[squadMember];
                if(mapPowerList[previousMasterListIndexForMember].powerActivatable)
                {
                    lstPCSquadIcons[previousMasterListIndexForMember].powerIconMC.subPowerIconMC.gotoAndStop("selectable");
                }
                else
                {
                    lstPCSquadIcons[previousMasterListIndexForMember].powerIconMC.subPowerIconMC.gotoAndStop("inactive");
                }
                powerQueuedForActivate[squadMember] = -1;
            }
            var mcLast;
            var sqmui = squadMCPrefixes[squadMember];
            var wi = 1;
            while(wi < 5)
            {
                mcLast = eval(sqmui + ".squadMC.weapon" + squadMember + pad(wi,2));
                if(mcLast._visible && mcLast.weaponGrow._currentframe == 13)
                {
                    mcLast.weaponGrow.gotoAndStop(1);
                    weaponWheelStates[wi - 1 + sqm * maxWeaponListSize / 3] = 1;
                }
                wi++;
            }
            oSubPowerIconMC.gotoAndStop("activated");
            powerQueuedForActivate[squadMember] = index;
            getURL("FSCommand:" add com.UnrealMessages.PlaySound,"HUDPowerWheelQueueingHighlightedPowerForActivation");
            // LE1CP: Fix to use saved index of actual power instead of UI index
            var gameIndex = (mapPowerList[i].originalIndex - 1) % 10 + 1;
            getURL("FSCommand:" add com.UnrealMessages.SelectPowerHUD,gameIndex - 1 + "," + squadMember);
        }
        else if(powerQueuedForActivate[squadMember] == index)
        {
            if(mapPowerList[i].powerActivatable)
            {
                pcmc.mc.powerIconMC.subPowerIconMC.gotoAndStop(1);
            }
            else
            {
                pcmc.mc.powerIconMC.subPowerIconMC.gotoAndStop(15);
            }
            powerQueuedForActivate[squadMember] = -1;
            getURL("FSCommand:" add com.UnrealMessages.SelectPowerHUD,"-1," + squadMember);
        }
    }
    showPowerInformation(false);
}
// def used
function setupPower(pcmc, i, squadMember, index)
{
    var mc = lstPCSquadIcons[i];
    mc.onRollOver = function()
    {
        if(!usingMouse || mapBlockMemberPowerDisplay[squadMember])
        {
            return undefined;
        }
        highlightPower(i);
    };
    mc.onRollOut = function()
    {
        if(!usingMouse || mapBlockMemberPowerDisplay[squadMember])
        {
            return undefined;
        }
        dehighlightPower(i);
    };
    mc.tabEnabled = false;
    mc.onPress = function()
    {
        if(!usingMouse || mapBlockMemberPowerDisplay[squadMember])
        {
            return undefined;
        }
        if(mc.powerIconMC.subPowerIconMC._currentframe == 7)
        {
            return undefined;
        }
        if(squadMember != 0)
        {
            return undefined;
        }
        mc.onMouseMove = function()
        {
            delete mc.onMouseMove;
            mc.onMouseMove = function()
            {
                doPowerDrag();
            };
            // LE1CP: Fix to use saved index of actual power instead of UI index
            var gameIndex = (mapPowerList[i].originalIndex - 1) % 10 + 1;
            startPowerDrag(true,gameIndex - 1,squadMember,mc.powerIconMC.subPowerIconMC.iconMC._currentframe);
        };
    };
    mc.onReleaseOutside = function()
    {
        if(!usingMouse || mapBlockMemberPowerDisplay[squadMember])
        {
            return undefined;
        }
        delete mc.onMouseMove;
        if(isDragging)
        {
            mc.onRollOut();
            stopPowerDrag(true);
        }
    };
    mc.onRelease = function()
    {
        if(!usingMouse || mapBlockMemberPowerDisplay[squadMember])
        {
            return undefined;
        }
        if(isDragging)
        {
            stopPowerDrag(false);
        }
        delete mc.onMouseMove;
        activatePower(i);
    };
}

ME_HUD

Vanilla script re-compiles fine, edits are based off of that.

New global variable added (at the bottom of the script)

// stores the next free squad power slot
var nextSquadPowerSlot = new Array(1, 11, 21);

New function correctSquadmatePowerIndex() added

// LE1CP: Given a power index, returns a corrected index where the power is slotted into the earliest available position
function correctSquadmatePowerIndex(selectedMember, index)
{
    var i = nextSquadPowerSlot[selectedMember];
    nextSquadPowerSlot[selectedMember] = nextSquadPowerSlot[selectedMember] + 1;

    if (i > (selectedMember + 1) * 10)
    {
        return -1 //too many powers, overflowing into squadmate power space
    }
    return i;
}

The first section of PopulateMapPowerItem() updated to read the following

function PopulateMapPowerItem(selectedMember, index, powerName, powerActivatable, powerIcon, barType, barLength, consumableQuantity, markAsFavourite, infoStr, initializationCall)
{
    var _loc7_ = initializationCall || selectedMember > -1 && squadMemberHealth.length > selectedMember && !mapBlockMemberPowerDisplay[selectedMember] && (squadMemberHealth[selectedMember] > 0 || squadMemberHealth[selectedMember] == -1);
    index += selectedMember * (maxMapPowerListSize / 3);

    // LE1CP: Remove "holes" in power order for squadmates.
    // This fixes the Liara overload bug, as well as potential future issues with mod bonus powers
    var originalIndex = index;
    if(powerName != "")
    {
        index = correctSquadmatePowerIndex(selectedMember, index);
        if(index == -1) return; // return early if index is out of bounds
    }
    mapPowerList[index].originalIndex = originalIndex; // for lookup of index game is expecting

    mapPowerList[index].powerName = powerName;
    mapPowerList[index].powerActivatable = powerActivatable;
    mapPowerList[index].powerIcon = powerIcon;
    mapPowerList[index].detailedInfo = infoStr;
    // remainder of the function continues unedited

The start of CreateMapPowerList() edited to the following

function CreateMapPowerList(selectedMember, squadNameFrame, bBlockDisplay, sBlockDisplayLabel)
{
    mapBlockMemberPowerDisplay[selectedMember] = bBlockDisplay;
    nextSquadPowerSlot = new Array(1, 11, 21);
   // remainder of the function continues unedited

The start of selectWeaponOrPowerInTacticalMode() edited to the following

function selectWeaponOrPowerInTacticalMode(keyCode)
{
   if(keyCode == com.XInput.ButtonA)
   {
      var aPressed = true;
      var xPressed = false;
   }
   else if(keyCode == com.XInput.ButtonX)
   {
      var aPressed = false;
      var xPressed = true;
   }
   if(HUDMode == _TacticalPowerMode)
   {
      var lastMasterListIndex = lastSelectedWheelIndex + selectedSquadMember * (maxMapPowerListSize / 3);
      var mcLast = lstSquadIcons[lastMasterListIndex];
      if(mcLast != undefined)
      {
         var oSubPowerIconMC = eval(mcLast + ".powerIconMC.subPowerIconMC");
         if(aPressed && mapPowerList[lastMasterListIndex].powerActivatable && squadMemberHealth.length > selectedSquadMember && squadMemberHealth[selectedSquadMember] > 0 && !mapBlockMemberDisplay[selectedSquadMember])
         {
            if(powerQueuedForActivate[selectedSquadMember] > -1)
            {
               var previousMasterListIndexForMember = lastMasterListIndex - lastSelectedWheelIndex + powerQueuedForActivate[selectedSquadMember];
               if(mapPowerList[previousMasterListIndexForMember].powerActivatable)
               {
                  lstSquadIcons[previousMasterListIndexForMember].powerIconMC.subPowerIconMC.gotoAndStop("selectable");
               }
               else
               {
                  lstSquadIcons[previousMasterListIndexForMember].powerIconMC.subPowerIconMC.gotoAndStop("inactive");
               }
            }
            oSubPowerIconMC.gotoAndStop("activated");
            powerQueuedForActivate[selectedSquadMember] = lastSelectedWheelIndex;
            getURL("FSCommand:" add com.UnrealMessages.PlaySound,"HUDPowerWheelQueueingHighlightedPowerForActivation");
            // LE1CP: Fix to use saved index of actual power instead of UI index
            var gameIndex = (mapPowerList[lastMasterListIndex].originalIndex - 1) % 10 + 1;
            getURL("FSCommand:" add com.UnrealMessages.SelectPowerHUD,gameIndex - 1 + "," + selectedSquadMember + ",0");
         }
         else if(xPressed && mapPowerList[lastMasterListIndex].powerIcon > 1)
         {
            var i = 0;
            while(i < lstSquadIcons.length)
            {
               if(lstSquadIcons[i] != undefined)
               {
                  lstSquadIcons[i].powerIconMC.subPowerIconMC.XClick._visible = false;
               }
               i++;
            }
            lstSquadIcons[lastSelectedWheelIndex].powerIconMC.subPowerIconMC.XClick._visible = true;
            getURL("FSCommand:" add com.UnrealMessages.PlaySound,"HUDPowerWheelMapOnePower");
            // LE1CP: Fix to use saved index of actual power instead of UI index
            var gameIndex = (mapPowerList[lastMasterListIndex].originalIndex - 1) % 10 + 1;
            getURL("FSCommand:" add com.UnrealMessages.SelectPowerHUD,gameIndex - 1 + "," + selectedSquadMember + ",1");
         }
         else
         {
            getURL("FSCommand:" add com.UnrealMessages.PlaySound,"GuiError");
         }
      }
   }
   // remainder of the function continues unedited

Full source code files are linked here:
ME_HUD Power Layout Bug.txt
PC_ME_HUD Power Layout Bug.txt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants