Jump to content

Tutorial (and library): Universal portrait packs


Recommended Posts

As part of our portrait pack revamp, I wrote a few macros that will help anyone else who also wants to make portrait packs that will provide portraits for any IE game, save PsT and PsTEE. You can find the library, cd_portrait_copy.tph, in any one of the G3 portrait packs. edit: Angelo v6 now has the most up-to-date library that includes the fourth function, cd_portrait_npc, or you can use the one attached to this post, though the portrait packs still include a ton of working examples of the functions. It includes some basic setup--building arrays for player portrait sizes based on the game--and then three macros that actually do the heavy lifting. I'll walk you through their basic usage.

Setting up your portraits for universality

The macros rely on naming your portraits in a specific way to indicate their size. Basically an underscore and then their height (in pixels) should be appended to the file name, e.g. foo_330.bmp is a 210x330 bitmap, foo_170.bmp is a 110x170 bitmap, etc. The base name of the portrait can not exceed seven characters, as the macros will need to append g/l/m/s to them as appropriate. All of the sizes used by all the games are summarized in this IESDP post. The upshot of all of this is that you'll want to generate the needed sizes and name them in advance--if the portraits are only for player characters, you can ignore the _266 and _84 variants as they're not needed; however they will be needed if they're going to be assigned to an NPC. In other words, you'll need five variants for PC portraits (330, 170, 60, 58, and 42) or seven for NPC portraits (previous five plus 266 and 84).

If you have Photoshop, I've attached a couple of action files for importation. One set will generate the smaller bitmaps from a _330 image; the other set from a _170 image. The latter is forced to upscale your images for the _330 and _266 variants, so some blurriness will unfortunately be unavoidable. It goes without saying that you should use the largest original images you can find for these processes. Be warned that both sets of actions will overwrite the image file, so use them on copies--e.g. make a copy of your _330 to _266 (or whatever) and then run the Photoshop action on the _266 file.

Since the 42x42 images for IWD2 are not the same aspect ration as the other images, you'll need to manually crop and edit them. Similarly, if you're making IWD-style portraits (large image is full body, smaller image is just the face) then you'll also need to crop them manually.

The macros themselves

There are three macros intended for the most common operations. All G3 portrait packs now utilize these macros so there are no shortage of examples for you to draw upon. Keep in mind that the macros will automatically determine which sizes, naming convention, and portrait folder location are needed for the game, so pretty much all you have to do is point them at the correct locations in your mod.

cd_portrait_bioware

This macro is used to preserve an NPC portrait as a player portrait, typically before overwriting them with a new version. For example, berelinde's Dragon Age: Origins Style Portraits has a component to preserve the NPC portraits before overwriting them with the new ones from the mod. Usage is straightforward; here's a sample usage from the aforementioned DA:

LAF cd_portrait_bioware STR_VAR source = ~nanomen~ destination = ~b_anob~ END

The 'source' is basically the in-game name of the portrait series, and destination is what you want them to be named in the player portrait folder. In this case the macro will look at Anomen's portraits (nanomenl.bmp, nanomenm.bmp, and nanomens.bmp) and copy over the needed sizes into the player portrait folder as a b_anob series.

cd_pc_portrait_copy

This macro will simply make portraits from your mod available as player portraits. There are three parameters:

LAF cd_pc_portrait_copy STR_VAR source = "file" destination = "bar" source_path = "mymod/portraits" END

Source is the root of your portrait names (e.g. use 'foo' for the foo_330, foo_170, etc. portraits) and source_path will be the folder where your portraits actually live. Utilize destination if you want the file name to change; if not it can be ommitted and the portraits will be copied with the same root name as the source. Since you'll typically have multiple portraits to copy, you can invoke this macro in bulk, as this example from the Infinity Collection Portrait Pack demonstrates:

ACTION_FOR_EACH file IN
  cdugdrf cdugmhf cdugmlf cduajan cduedwi cdusafa cdualor cdubran cducora cdudyna cdueldo cdufald cdugarr cduimoe cdujahe cdukaga cdukhal cduman1 cduman2 cdumins // bg-bg2 common
  cdumont cduquay cdvdorn cdvkiva cdvneer cdvnhor cdvrasa cdxclar cdvhelm cdvhvln cduwom1 cdushar cduskie cdutiax cduvico cduwom2 cduxan cduxzar cduyesl cdvskan
BEGIN
                        
  LAF cd_pc_portrait_copy STR_VAR source = EVAL "%file%" source_path = "cd_icpp/bg_common" END

END

cd_portrait_copy

This last macro is used to overwrite an NPC's existing portrait. It has the same parameters as cd_pc_portrait_copy; here's an example from the Amaurea's BG2 Portrait Pack used to replace Cernd's portrait:

LAF cd_portrait_copy STR_VAR source = "amcer1" destination = "ncernd" source_path = "amaureasbg2portraits/portraits" END 

As above, you can omit destination and the macro will use the source value for the root file name. This will use the appropriate amcer1_330 or amcer1_170, etc. to overwrite the existing ncerndl/ncerndm/ncernds portraits in the game, giving Cernd a new look.

cd_portrait_npc

This macro is used for mod NPCs to copy over the correct portrait sizes for their game. Since IWD and IWD2 don't support NPCs, it basically differentiates between a BGEE/BG2EE/EET install vs. oBG/oBG2/Tutu/BGT install. Here is usage from Angelo v6:

LAF cd_portrait_npc STR_VAR source = ~adangel~ source_path = ~angelo/portraits~ END

It does support a destination attribute; if not specified it will use source as the destination.

The files

Link to comment

We're still having issues with attachments on the forums - there's a support ticket out for it but it's still being looked at.

The library for the portrait packs is in all of our portrait mods now so you should be able to look at those for examples. We can send the PSD actions via some other method if someone needs them until our attachments are fixed. :)

Link to comment
8 hours ago, theacefes said:

 We can send the PSD actions via some other method if someone needs them until our attachments are fixed. :)

 

Ye.. But why not just:

    /*


https://www.gibberlings3.net/forums/topic/29922-on-portrait-sizes/
 portrait sizes:
  42 x  42 - IWD2 square, cropped small portraits 'S' for game screen
  36 x  58 - original IWD as game screen portrait as 'S'
  38 x  60 - original BG/BG2 game screen/dialogue as 'S' portrait
  54 x  84 - EE as 'S' portrait (unused?)
 110 x 170 - original BG2 record screen as 'M' portrait; original BG/IWD record screen as 'L' portrait
 169 x 266 - EE game screen/dialogue as 'M' portrait
 210 x 330 - original BG as 'G' portrait (unused?); original BG2 epilogue as 'L' portrait; original IWD as initial character selection portrait as 'G'; IWD2 as main portrait; EE epilogue/record screen as 'L' portrait
*/
 
ACTION_CLEAR_ARRAY ~cd_portrait_map~ // just in case
    ACTION_IF GAME_IS ~bgee bg2ee eet iwdee pstee~ BEGIN // EEs
  OUTER_SPRINT portrait_directory "%USER_DIRECTORY%/portraits" // e.g. My Documents/Baldur's Gate 2 Enhanced Edition/portraits
  ACTION_DEFINE_ASSOCIATIVE_ARRAY cd_portrait_map BEGIN
    330 => l
  END
END ELSE BEGIN  
  OUTER_SPRINT portrait_directory "portraits" // e.g. [game folder]/portraits
  ACTION_IF GAME_IS ~bg1 totsc~ BEGIN // original bg
    ACTION_DEFINE_ASSOCIATIVE_ARRAY cd_portrait_map BEGIN
       60 => s
      170 => l
    END
  END ELSE BEGIN
    ACTION_IF GAME_IS ~iwd how totlm~ BEGIN // original iwd
      ACTION_DEFINE_ASSOCIATIVE_ARRAY cd_portrait_map BEGIN
         58 => s
        170 => l
      END
    END ELSE BEGIN
      ACTION_IF GAME_IS ~iwd2~ BEGIN // original iwd2
        ACTION_DEFINE_ASSOCIATIVE_ARRAY cd_portrait_map BEGIN
           42 => s
          330 => l
        END  
      END ELSE BEGIN   // original bg2
        ACTION_DEFINE_ASSOCIATIVE_ARRAY cd_portrait_map BEGIN
           60 => s
          170 => m
        END  
      END
    END  
  END
END
    DEFINE_ACTION_FUNCTION cd_portrait_bioware // used to preserve (mod) NPC portraits as player-available portraits before overwriting them
  INT_VAR
  STR_VAR
      destination = "foo"
      source = "bar"
BEGIN
      ACTION_PHP_EACH cd_portrait_map AS size => suffix_dest BEGIN // read in array of needed size/names for PC portraits
 
    ACTION_FOR_EACH suffix_source IN g l m s BEGIN // iterate through known suffixes since we can not rely on mods to follow naming conventions
    
      OUTER_SET height = 0
      COPY_EXISTING ~%source%%suffix_source%.bmp~ ~override~ // check height, if file exists
        READ_LONG 0x16 height
        BUT_ONLY IF_EXISTS
      
      ACTION_IF height = size BEGIN    // if height matches the desired size, copy over as properly named file to player portrait folder
            COPY_EXISTING ~%source%%suffix_source%.bmp~ ~%portrait_directory%/%destination%%suffix_dest%.bmp~
        
      END
    
    END    
      END      
    END
    DEFINE_ACTION_FUNCTION cd_pc_portrait_copy // used to copy portraits as to make them player-available
  INT_VAR
  STR_VAR
      destination = ""
      source = ""
      source_path = "%MOD_FOLDER%/portraits"
BEGIN
      ACTION_IF ("%destination%" STRING_COMPARE_CASE "" = 0) BEGIN OUTER_SPRINT destination "%source%" END
      ACTION_PHP_EACH cd_portrait_map AS size => suffix BEGIN
        COPY ~%source_path%/%source%_%size%.bmp~ ~%portrait_directory%/%destination%%suffix%.bmp~
      END
    END
 
DEFINE_ACTION_FUNCTION cd_portrait_copy // used to copy portraits as to replace existing NPC portraits, e.g. a new portrait for Imoen
  INT_VAR
    debug = 0
  STR_VAR
    source = ""
    destination = ""
    source_path = "%MOD_FOLDER%/portraits"
  RET
    success  
BEGIN
      OUTER_SET success = 0
  ACTION_FOR_EACH suffix IN g l m s BEGIN
 
    ACTION_IF FILE_EXISTS_IN_GAME ~%destination%%suffix%.bmp~ BEGIN
    
      COPY_EXISTING ~%destination%%suffix%.bmp~ ~override~
        READ_LONG 0x16 height
        BUT_ONLY
      
      ACTION_IF FILE_EXISTS ~%source_path%/%source%_%height%.bmp~ THEN BEGIN
            COPY ~%source_path%/%source%_%height%.bmp~ ~override/%destination%%suffix%.bmp~
        OUTER_SET success = 1
          END ELSE BEGIN
            WARN ~%destination%%suffix%.bmp found, but no replacement available: looking for %source_path%/%source%_%height%.bmp~
          END // end local portrait check to copy/warn
        END ELSE BEGIN
          ACTION_IF debug BEGIN PRINT ~%destination%%suffix%.bmp not found~ END
        END // end portrait check
      END // end ACTION_PHP_EACH
    
END  // end function define
   

Besides, usually, it's best to restrict attachments to a single archive type... .zip. On Windows. You can add in the .tar.gz, but there's no point in allowing even .rar's for the simple reason that a .zip's can be opened by everyone, and they spare space like an animal from others such as .txt & .debug and others.

Edited by Jarno Mikkola
Link to comment

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...