Good Hero Picker
A Plotscript by Mike Willis

CONTENTS:
I - The Goal and the Plan
II - The Scripts
III - Using the Scripts

I - The Goal and the Plan
If you have ever tried to plotscript any form of hero management, such as a special plotscripted healing item or a customized party selection screen, you have probably had to make use of the command "Pick Hero".  This command calls a menu where the player can choose which hero for the plotscript to affect.  However, this menu does not show any stats for the heroes.  This is problematic for things like plotscripted healing, where the player would like to see the HP of the heroes he is choosing between.

The goal of this Plotscript of the Month is to construct a 'Good Hero Picker' that will behave exactly like the "Pick Hero" command, but will be able to show the stats of the heroes for the player to see when choosing.  Which stats?  Well, ideally, that should be up to the author, so we will construct the plotscript to accept arguments like so:

Good Hero Picker (stat, captionID)

Calls a hero menu showing the stats of each hero according to the 'stat' argument.  This argument can be in the form "stat:stat name" using the constants from your game included in your .hsi file.  Send -1 for the 'stat' argument to show no stats.  The captionID argument will be the ID number of a string to be the caption of the menu.  If this argument is ignored, the menu will use a default caption defined in the menu editor in custom.exe.  The command returns the position of the chosen hero in the party.

Here is the basic plan.  The "Good Hero Picker" will use a custom menu to be the hero-picking menu.  Each hero choice on this menu will trigger a second plotscript that will affect a global variable.  The "Good Hero Picker" will then use this global variable to decide which hero slot (if any) was picked.  It will then return this value, just like "Pick Hero" would.  Unfortunately, since we cannot predict what heroes the player will have in his party, or in what order, the hero-picking menu will have to be constructed on the fly within the "Good Hero Picker" plotscript.  Here we go!


II - The Scripts
First of all, using these scripts will require one free global variable (it will be called "HeroGV" in these examples) and five free string ID's in a row(these scripts will assume we have string IDs #6-10).  We will also need a new menu defined and named in custom (it will be called "Good Hero Menu" in these examples).  As explained above, there are actually two plotscripts at work here:

HERE ARE THE SCRIPTS WITHOUT COMMENTS
global variable (???, HeroGV) #assign an unused global variable ID

script,Good Hero Picker,stat=-1,captionID=0,begin
variable(n,mnu)
HeroGV:=-1
mnu:=openmenu(menu:Good Hero Menu)
if(captionID>>0),then
 (set menuitem caption (first menuitem(topmenu), captionID))
for(n,3,0,-1),do
 begin
  if(herobyslot(n)<>-1),then
   begin
    getheroname(n+6,n)   #THE SIX INDICATES THE FIRST OF THE STRING ID'S 6-10.  CHANGE ACCORDINGLY.
    if(stat<>-1),then
     begin
      $10=" - "   #THE TEN INDICATES THE LAST STRING ID OF 6-10.  CHANGE ACCORDINGLY
      concatenatestrings(n+6,10)   #CHANGE THE SIX AND TEN ACCORDINGLY
      appendnumber(n+6,getherostat(n,stat))   #CHANGE THE SIX ACCORDINGLY.
      if(stat==stat:HP, or ,stat==stat:MP),then   #IF YOU HAVE DIFFERENT NAMES FOR HP AND MP,
       begin                                      #CHANGE THIS ACCORDINGLY.
        $10=" / "   #CHANGE THE TEN ACCORDINGLY.
        concatenatestrings(n+6,10)   #CHANGE THE SIX AND TEN ACCORDINGLY.
        appendnumber(n+6,getherostat(n,stat,maximumstat))   #CHANGE THE SIX ACCORDINGLY.
       end
     end
    set menuitem caption(menuitem by slot(topmenu,n+1),n+6)   #CHANGE THE SIX ACCORDINGLY.
   end

  else
   begin
    deletemenuitem( menuitem by slot(topmenu,n+1) )
   end
 end
while(menuisopen(mnu)),do
 (wait(1))
return(HeroGV)
end
#-----------

plotscript,Hero Picker Menu Script,MChandle=0,begin
HeroGV:=get menuitem extra(MChandle,0)
closemenu(topmenu)
end
#-----------

I have also included a commented version of the script if people would like to better understand the plotscripting involved.  The reader will need a strong understanding of the following:
• local and global variables
• for loops
• arguments
• return values
• string storing and manipulating (not displaying), especially via the command "get hero name"

  HERE ARE THE SCRIPTS WITH COMMENTS
global variable (???, HeroGV) #assign an unused global variable ID

script,Good Hero Picker,stat=-1,captionID=0,begin
#The arguments' default values make it so that if we use the Good Hero Picker command
#without passing any arguments, the menu will show no stats and no caption.

variable(n,mnu)
HeroGV:=-1
#This is our global variable.  It defaults to -1 because that is what it will return
#if the player cancels the menu, just like the "Pick Hero" command

mnu:=openmenu(menu:Good Hero Menu)
#This stores a reference to the Good Hero Menu in our local variable, mnu
#Menu commands were written to use menu references, just like NPC commands can use NPC references

if(captionID>>0),then
 (set menuitem caption (first menuitem(topmenu), captionID))
#If we sent a string ID as the second argument, we set that string to be the caption
#at the top of our hero-picking menu

#The upcoming for loop is processed backwards because we will be deleting menu entries that
#do not correspond to a hero.  Any time you run a for loop where you might be deleting
#things along the way, you should do it backwards like this.
for(n,3,0,-1),do
 begin
  if(herobyslot(n)<>-1),then  #Checks to make sure a hero is in slot #n
   begin
    getheroname(n+6,n)  #The n+6 has us use strings starting from ID #6
    if(stat<>-1),then
         #If we sent a stat as the first argument, we should
         #add onto the name to show "name - stat value"
     begin
      $10=" - "   #Notice the spaces
      concatenatestrings(n+6,10)
      appendnumber(n+6,getherostat(n,stat))
      if(stat==stat:HP, or ,stat==stat:MP),then
           #If the stat we're showing is HP or MP, we should
           #show the stat out of it's maximum value like "name - stat / max"
       begin
        $10=" / "   #Notice the spaces
        concatenatestrings(n+6,10)
        appendnumber(n+6,getherostat(n,stat,maximumstat))
       end
     end
    set menuitem caption(menuitem by slot(topmenu,n+1),n+6)  #After setting up the string we can
                                                             #finally set it as the caption for
                                                             #the menu choice
   end

  else  #This else block runs if the herobyslot command returned -1
        #in other words, there was no hero in slot n
   begin
    deletemenuitem( menuitem by slot(topmenu,n+1) )
   end
 end
while(menuisopen(mnu)),do
 (wait(1))   #This waits for the player to make his choice before returning the value
             #of the global variable, which will be affected by the player's choice via
             #the script below
return(HeroGV)
end
#-----------

plotscript,Hero Picker Menu Script,MChandle=0,begin
#This script will be run from the custom menu, which automatically
#sends an argument called a menu-choice-handle.  This is a reference
#that tells the plotscript which choice was picked.

HeroGV:=get menuitem extra(MChandle,0)
#This sets the global variable HeroGV to 0,1,2,or3 depending on which slot the player
#chose.  This depends on setting up the menu correctly in custom.  See Section III below.

closemenu(topmenu)
#This will close the custom menu, allowing the while loop from the previous
#script to terminate.

end

III - Using the Scripts
To use the "Good Hero Picker" we will need a very specfic custom menu in the menu editor in custom.exe.  Go to the menu editor and create a new menu.  Name this new menu "Good Hero Menu".  We need the following bitsets turned on for this menu:
• Allow gameplay
• Suspend player even if gameplay allowed
• Prevent main menu activation

(The first two allow the plotscripts to alter the menu while suspending hero controls, and the third is self-explanatory.)  Now go to "Edit Items..." in the menu editor.  This menu should have five items.  The first one should be type 0 (Caption) and subtype 1 (Not selectable).  This will be the caption for the menu.  You can enter a default caption like "Which hero?", but this will be overwritable with strings when using the plotscript.  This first menu item does not need any other bitsets or data.

The other four menu items will be the hero slots.  They don't need captions, but each one needs to be type 4 (Run script) with subtype "Heropickermenuscript".  They should also use the 'extra data 0' spot to describe which heroslot they are referring to.  The first of these four menu items should leave its extra data 0 as zero, but the next one should set it to 1, the third one should set it to 2, and the fourth one should set it to 3 (this corresponds with heroslots 0, 1, 2, and 3).  No other bitsets or data should be set.

The plotscript is now ready to use!  Basically you would use it anywhere that you would use the "Pick Hero" command, but now you can assign a caption using strings, and assign a stat to be shown!  Here is an example where a plotscripted item is to be used to restore MP:

EXAMPLE SCRIPT EXCERPT
#...
$23="Who needs the Magic Water?"   #storing this into string ID 23, for example
variable(who)   #variable to store the player's choice
who:=Good Hero Picker (stat:MP, 23)   #the stat:MP will be shown, and string 23 will
                                      #overwrite the menu's caption.

if(who<>-1),then   #make sure the player did not cancel out of the menu
 begin
  set hero stat (who, stat:MP, get hero stat (who, stat:MP, maximumstat))
 end
#...

Hopefully this is enough to get started with.  Any questions, comments, or corrections can be mailed to msw188@gmail.com