Jump to content

Modifying elements in the Personnel UI screen?


TheRealSFlo

Recommended Posts

Hey there, Nexus forum-goers,

 

As the title says, I'm trying to alter the UI in the personnel screen to add additional bits of information in certain places. More specifically, I'm trying to take the "Status" section for each staff member, raise the position that the status text and timers are drawn within their respective boxes up slightly, then use the newly created space to draw an additional line of text.

 

http://i.imgur.com/N5BxRyG.jpg

The vanilla personnel page, as seen in the Armory.

 

 

I thought I'd use Amineri's GameState Component method to add on the existing UI and started digging around in the source code to try and figure out how the list is actually drawn to the screen, but I can't seem to figure out how the classes are actually working, and it's driving me insane. After dissecting several other mods that toy with the UI and getting nowhere, I'm lost and I'm unsure how to proceed.

 

Basically, I was kind of expecting that in at least one those classes (UIPersonnel.uc, UIPersonnel_ListItem.uc, UIPersonnel_SoldierListItem.uc, etc.) there'd be some bit of code that was specifying the maximum width of each piece of unit information (Flag, Name, Class, etc.) along with specifying the positions where the text and images in a button are drawn to the screen. Everything in those classes just seem to be sending text/image data to generic classes that are somehow sorting all of this out.

 

The game draws soldier names using two lines after a soldier gets a nickname, so I know it can at least handle this, but I'm deeply confused by Firaxis's code at the moment. I'd greatly appreciate it if somebody could point me in the right direction or explain what's going on here.

 

Thanks!

Link to comment
Share on other sites

I've been agonizing over some similar issues. I suspect that the answer is this stuff is specified in Flash, not in the UnrealScript files.

 

Sorry I couldn't help more. I haven't dug much into the details of that particular screen.

Edited by bunnytrain
Link to comment
Share on other sites

MC is the component talking to flash.
So when any UI function end in a MC call, you know it's handled by flash.

For example (UIPersonel.uc) :

m_arrTabButtons[m_eCurrentTab].MC.FunctionVoid("onReceiveFocus"); 

Will call the flash function OnReceiveFocus on the current tab.

Basically what most "complex" UIPanel in the game does is handle the logic (should we display scientist or engineer, order the list, ect, ect) and then sends the data to MC for flash to display.
So there's no way (for now) to edit a flash UI.

Though any UI made by flash binds to a parent UIPanel, which when its X/Y/Width/Height changes reflects on flash. (As in messes up the flash which expected to be exactly like before)

Edited by Superd22
Link to comment
Share on other sites

We've had quite a bit of success for LW when "fixing" Flash components and script logic. XMarksTheSpot did a lot of features (including Stats & symbols section underneath names in the Barracks list & other places) for the team while SpazmoJones was responsible for properly adding the EXP/Combo in the Status column.

I also was able to correctly manipulate the Flash side to add various HUD elements where needed... Deploy/Formations mod is one of those.

 

Essentially, we'd hack our ways into the tiny bits and outright edit (while resizing the gfx in place to re-locate the referencing code within any UPK host) anything else using JPEXS --- https://www.free-decompiler.com/flash/.

 

Some modders already are able to add extensive HUD elements quite easily (Uniforms, ShowMeTheSkills, LifetimeStats, etc) and i suspect my upcoming LAByrinth project (( and certainly GeoscApps ! )) will do as well.

 

Ideally though... i really wish Firaxis would just hand-over a stand-alone SDK toolset to properly access (and specifically, dive into ActionScript) whatever we'd like within Flash assets. Don't hold your breath about it though.. Adobe is a freakish hurdle of copyright issues.

 

PS; In the meantime for the OP needs.. i'd have to recommend a quick JPEXS inspection of that gfx component to get a feel of related issues as it would certainly offer exact details. The file in this case is -- gfxSoldierList.upk :: SoldierList.swfmovie... and, here's the whole script class/function that controls pretty much anything on that screen while the "SoldierListItem" class/function handles each individual slots;

 

 

 

class SoldierListScreen extends Screen implements IDisposable
{
   static var SOLDIER_LIST_MAX = 15;
   function SoldierListScreen()
   {
      super();
      if(_global.debugging)
      {
         Environment.instance().ToggleMouseHitDebugging(this);
         Environment.instance().SetView(1280,720,0.15);
      }
   }
   function onLoad()
   {
      super.onLoad();
      trace("SoldierListScreen: onLoad()");
      this.SoldierTab.Hide();
      this.ScientistTab.Hide();
      this.EngineerTab.Hide();
      this.DeceasedTab.Hide();
      this.deceasedSort._visible = false;
      this.memorialCounters._visible = false;
      this.screenTitle._hideOnLoad = true;
      this.screenTitle._visible = false;
   }
   function SetMemorialHeaders(strTitle, strKills, strMissions, strLastOp, strDate)
   {
      this.deceasedSort._visible = true;
      this.deceasedSort.screenTitle.htmlText = strTitle;
      this.deceasedSort.killsTitle.htmlText = strKills;
      this.deceasedSort.missionsTitle.htmlText = strMissions;
      this.deceasedSort.lastOpTitle.htmlText = strLastOp;
      this.deceasedSort.dateTitle.htmlText = strDate;
   }
   function SetMemorialCounters(strSurvivalTitle, strSurvivalValue, strBodyTitle, strBodyValue, strReloadTitle, strReloadValue)
   {
      this.memorialCounters._visible = true;
      if(!(strSurvivalTitle == "") && !(strSurvivalTitle == undefined))
      {
         this.survivalCounter._visible = true;
         this.survivalCounter.theTitle.htmlText = strSurvivalTitle;
         this.survivalCounter.theValue.htmlText = strSurvivalValue;
      }
      else
      {
         this.survivalCounter._visible = false;
      }
      if(!(strBodyTitle == "") && !(strBodyTitle == undefined))
      {
         this.bodiesCounter._visible = true;
         this.bodiesCounter.theTitle.htmlText = strBodyTitle;
         this.bodiesCounter.theValue.htmlText = strBodyValue;
      }
      else
      {
         this.bodiesCounter._visible = false;
      }
      if(!(strReloadTitle == "") && !(strReloadTitle == undefined))
      {
         this.reloadCounter._visible = true;
         this.reloadCounter.theTitle.htmlText = strReloadTitle;
         this.reloadCounter.theValue.htmlText = strReloadValue;
      }
      else
      {
         this.reloadCounter._visible = false;
      }
   }
   function SetScreenHeader(newTitle)
   {
      this.screenTitle._hideOnLoad = false;
      this.screenTitle._visible = true;
      this.screenTitle.setText(newTitle,"");
      this.screenTitle.setWidth(980);
   }
   function SetEmptyLabel(label)
   {
      this.emptyLabel.htmlText = label;
   }
   function Show()
   {
      trace("SoldierListScreen: Show()");
      super.Show();
   }
   function dispose()
   {
      super.dispose();
   }
   function onPopulateDebugData()
   {
      var _loc3_ = undefined;
      var _loc2_ = 0;
      while(_loc2_ < SoldierListScreen.SOLDIER_LIST_MAX / 2)
      {
         _loc3_ = (SoldierListItem)Bind.movie(this.listAnchor,"SoldierListItem","soldierItem" + _loc2_);
         _loc3_._y = _loc3_._height * _loc2_;
         _loc2_ = _loc2_ + 1;
      }
      this.SoldierTab.setHTMLText("SOLDIERS");
      this.ScientistTab.setHTMLText("SCIENTISTS");
      this.personnelSort._visible = false;
      this.SetScreenHeader("SOLDIERS");
   }
   function OnChildMouseEvent(target, type)
   {
      switch(type)
      {
         case Input.MOUSE_UP:
         case Input.MOUSE_UP_DELAYED:
         case Input.MOUSE_DOUBLE_UP:
         case Input.MOUSE_IN:
            trace("SoldierListScreen: OnChildMouseEvent() _target=" + target + ", _type=" + type);
            flash.external.ExternalInterface.call("FlashRaiseMouseEvent",String(this),type,String(target));
            break;
      }
   }
   function onInput(code, action)
   {
      if(!_global.debugging)
      {
         return undefined;
      }
      switch(code)
      {
         case Input.DPAD_UP:
            var _loc4_ = undefined;
            var _loc3_ = SoldierListScreen.SOLDIER_LIST_MAX / 2;
            while(_loc3_ < SoldierListScreen.SOLDIER_LIST_MAX)
            {
               _loc4_ = (SoldierListItem)this.listAnchor["soldierItem" + _loc3_];
               trace("Soldier item: " + _loc4_);
               _loc4_.UpdateData("UPDATED DATA TEST","DESTROYER","CPL.","../AssetLibraries/RankIcons/rank_squaddie.tga","SUPPORT","../AssetLibraries/ClassIcons/class_ranger.tga","BUSY DOING STUFF","3","INFIRMARY","../AssetLibraries/CountryFlags/UIFlag_norway.tga",false,false,false);
               _loc3_ = _loc3_ + 1;
            }
            break;
         case Input.DPAD_DOWN:
            break;
         default:
            return false;
      }
      return true;
   }
}

 

 

Edited by Zyxpsilon
Link to comment
Share on other sites

Technically ALL of them. UE3 has a knack for taking over the core components at nearly every levels. XC2 makes no exception to this inherent form of control, AFAIC.

 

A good hint about the "unmoddable screens" can be resumed in a very simple theory, David; if it isn't given a "Library" call set ( while also being declared by INI dispatch methods via Engine definition(s) ) -- then, no flash accessing principles are necessary directly or otherwise.

Edited by Zyxpsilon
Link to comment
Share on other sites

As i said in my first post, look through the UI Classe files.
If you see a UIPanel Spawn, then it's something you can edit.

If you see the logic ending in a MC.FunctionVoid(); call then it's flash doing the display.

ShowMeTheSkills for example edits the SquadSelect_listItem classes, which has a DynamicContainer child which is entirely displayed via flash.
So you cannot change the layout of this dynamicContainer, you can however add children to that UIPanel and do whatever you want. That's how SMTS works.

(I'm the author of ShowMeTheskills btw, hi Zyxpsilon)

Edited by Superd22
Link to comment
Share on other sites

Well then, this is significantly more complicated than I had bargained for. Still, I want to thank you guys for the help. You're all awesome.

 

That being said, I'm thinking of implementing more of a roundabout approach to this now for simplicity's sake. Not exactly elegant, I'll admit, but I'm interested in what you guys think.

 

I might be able to alter the strings being passed to the status section in the personnel list and just append an additional string to it (although a cursory look at this suggests that all the functions governing those string are static, so it might be tricky to find a spot that I can hook into). User would have to wait for the text to scroll if in cases where a unit was doing something like Psi training or being Shaken due to the string length getting crazy, but it'd work, at least.

 

Alternatively, I may have to take a similar approach to that seen in the Upgrade Reminder mod and use UIScreenListener to check for the personnel screen and grab unit IDs from it, then just draw an icon and a bit of text to specific coordinates on the screen (logic might get a little hairy, but I'm at least experienced with that). The personnel screen's already cramped though, so any additional information would have to be done through a small font/icon size to avoid overlap. May or may not be viable, depending on how many free pixels I can work with.

 

What are your guy's thoughts on the matter? Either of the two approaches I proposed worthwhile? Or would my time be better served if I just start poking around with JPEXS as suggested by Zxypsilon?

Link to comment
Share on other sites

Well, my philosophy regarding UI currently is :

"You can't edit stuff, so don't try, just add stuff".

 

I've been working on a UIPersonel mod, as a follow up to my SMTS. I didn't try to edit the layout, rather i just added what i wanted on-top of it.

http://i.imgur.com/Ycc1xLf.png

 

(this is an early prototype, excuse the uglyness.)

The workflow for that is rather easy.

  • Listen to the UIPersonel screen
  • Foreach the m_klist (= list of people displayed) which are all UIPersonel_ListItem
  • Append a custom 'UIMoreStats' to UIPersonnel_ListItem
  • 'UIMoreStats' has a Header component
  • this header is in fact an instance of a class that extends UISoldierHeader, i overwrite functions to get the stats, without having to do all the logic again.
    Note: i did extend UISoldierHeader but i did not overwrite it, thus it's compatible with any and every mods
  • 'UIMoreStats' uses the info provided by the extended uisoldierHeader to populate itselfs.

 

tl;dr :

Listen for A Screen

Get the element you want

ADD to this element

You can extends other classes so you don't have to recode logic that already exists.

 

I never even heard of JPEXS tbh, so no clue on this end, but i definitely think you should at least try and go native and go the other way only if you *must*

 

Edit : Though, Zyxpsilon, that opens up a whole new world of possibilities :blush: :blush: (i'm like a kid in candy store right now)

Edited by Superd22
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...