Tutorial for Adding Party Members in Fallout 2 (Attempt)

Discussion in 'Fallout General Modding' started by JimTheDinosaur, Mar 17, 2013.

  1. JimTheDinosaur

    JimTheDinosaur Vault Dweller
    Modder

    736
    Mar 17, 2013
    I recently decided to give modding Fallout 2 another go and redid the hours-long routine of finding tutorials and modding tools, relearning them, etc. etc. Anyway, one recurring complaint has been that there aren't really any tutorials of intermediate difficulty. As in, there's the standard beginner stuff on compiling, and so on, and some very in depth stuff, but nothing on what you can actually do once you've set everything up in the first place. Specifically, there's (as far as I can tell) no tutorials on doing what everyone wants to do the second they start modding fallout: making weird extra party members and sending them into battle. The most common advice is to just copy what the designers did with existing party member x (which any beginner will know is nigh impossible).

    Now, I'm not much more than a beginner myself, so part of the goal of this tutorial is to hopefully get some pointers on which step is wrong/unnecessary/whatever (hence the attempt part). Also, I'm assuming you already know the absolute basics. Anyway, without further ado:

    Let's say you want to make Lucas in Arroyo (the fisticuffs guy) a potential party member, what to do?

    1: Right now Lucas doesn't have his own prototype (he's just another villager, while party members need to be *unique*), so you need to go to the critter proto folder, copy the villager proto file (i.e. 00000003.pro) and rename this copy to an available slot (e.g. 00000484.pro), which you have to also add at the end of the critter.lst file. Problem is, right now the proto file still "thinks" it's the old one, so use FUCK or some other critter changing program and change the ID number to 484 (and any other parameters you want to change of course).

    2: Now we should give this unique little prototype a name. Open the critrpid.h header file and add
    Code:
     #define PID_LUCAS		                (16777700) 
    (remember that pids are the proto number + 16777216)

    3: Now go to the party.h header file and just start copying, only with lucas instead op party member x.
    So, instead of
    Code:
     #define Sulik_Ptr                           party_member_obj(PID_SULIK) 
    you do
    Code:
     #define Lucas_Ptr                           party_member_obj(PID_LUCAS) 
    etc.

    4: Now go to the individual script file (i.e. acfist.ssl in the mapper scripts) and add
    Code:
    #define lucas_joins_party                 party_add_self;                                                   \
                                              critter_add_trait(self_obj,TRAIT_OBJECT,OBJECT_TEAM_NUM,TEAM_PLAYER)
                      
    and put lucas_joins_party at whichever point (e.g. in converstation) you want him to come in your party. Now put in some extra local variables you will need:

    Code:
     
    #define LVAR_WAITING                    (7)
    #define LVAR_FOLLOW_DISTANCE            (8)
    #define LVAR_TEAM                       (9)
    #define LVAR_Joined_Party_Before        (14)
    
    #define PARTY_NODE_X                      Node1000 
    Now add this line to the beginning of procedure map_enter_p_proc:

    Code:
    begin
       party_member_map_enter;
       if (Lucas_In_Party) then begin
          //do nothing
       end else... etc.
    so he doesn't join the arroyo team everytime you enter a map. Then at critter_p_proc add

    Code:
     
       else if (Lucas_In_Party) then begin
          if (party_is_waiting == false) then begin
          party_member_follow_dude
          end
       end 
    to get him to follow you around. Then add this line to the beginning of talk_p_proc:

    Code:
       if ( ( Lucas_Ptr != 0 ) or ( party_is_waiting ) ) then begin
           start_gdialog(NAME,self_obj,4,-1,-1);
           gSay_Start;
               call Node1000;
           gSay_End;
           end_dialogue;
       end 
    This calls the party options screen we all love so much. Just copy the nodes 1000-1100 from an existing party member script (don't forget to also introduce them at the beginning of the script, i.e. procedure Node1000; etc.) and change the sultik_party_member_options (and similar) to party_member_default_options (same with the gear and follow variants).

    Finally remove the
    Code:
     critter_add_trait(self_obj,TRAIT_OBJECT,OBJECT_AI_PACKET,AI_ARROYO_WARRIOR); 
    line, so that you can alter the ai through the party options later on.

    Now you should be able to compile.

    5: Go to the party.txt file and copy whichever existing party member you want him to resemble (i.e. in Lucas' case, Sulik) and add a new entry, changing the PID number and removing level up stuff so that you get:

    Code:
    [Party Member 26]   ; pMLucas_PID
    party_member_pid=16777700
    area_attack_mode=always, sometimes, be_careful
    attack_who=whomever_attacking_me, strongest, whomever, closest
    best_weapon=melee, melee_over_ranged, ranged_over_melee, unarmed
    chem_use=clean, stims_when_hurt_little, stims_when_hurt_lots, sometimes, anytime, always
    distance=stay_close, charge, snipe, on_your_own, stay
    run_away_mode=none, tourniquet, never
    disposition=none, custom, defensive, aggressive, berserk
    level_minimum=0
    level_up_every=0
    level_pids=-1
    Of course, if you happen to want Lucas to be able to level up to a martial arts master later on, make some more protos, edit them in FUCK, and add each consecutive pid number to "level_pids".

    6: Finally go into the mapper and replace Lucas' villager prototype with your new prototype, give him one of Sulik's AI's (i.e. Berserk or Aggressive or whatever, it's just the default setting you can change) and give him the acfist.int script again.

    Now F8 and it should work swimmingly!
     
    • [Rad] [Rad] x 1
  2. .Pixote.

    .Pixote. Antediluvian as Feck
    Modder

    Sep 14, 2009
  3. JimTheDinosaur

    JimTheDinosaur Vault Dweller
    Modder

    736
    Mar 17, 2013
    Sure, but I was just hoping to get word from one of the veterans first. I mean, everything *seems* to work fine when I test it, but who knows, this method might cause party members to tag along while you're having private time with Mrs. Bishop or whatever.

    If it gets the ok I'll see if I can put together a tutorial for what I think is the second most popular objective for beginning modders: putting together a set piece battle like the one between the Den gangs or the Ghostfarm showdown.
     
  4. MIB88

    MIB88 So Old I'm Losing Radiation Signs
    Modder

    Feb 22, 2005
    One more thing (if I remember correctly). You may have done this already and just not mentioned it, but it is important enough to specifically say:

    While you can copy/paste so much of the code for the scripts, you cannot just copy/rename a critter .pro file and include it. Be sure to use one of the critter editors. Even though you might change the name of the file to 0000484.pro, there is internal information in the file referencing the original .0000003.pro value. Fallout Utility for Critter tinKering is my tool of choice for editing this.
     
  5. JimTheDinosaur

    JimTheDinosaur Vault Dweller
    Modder

    736
    Mar 17, 2013
    Thanks, but as far as I can tell this internal information doesn't really interfere with the basics I outlined here. I mean, the point behind getting a fresh .pro file is to get a new PID number so that the game can tell whether an npc is in your party or not. And as far as I can tell the PID number *is* changed just by copying the .pro file as I outlined. For instance, the trigger for going to the party options screen is

    Code:
    if ( ( Lucas_Ptr != 0 ) or ( party_is_waiting ) ) then begin
    So if the game was still reading the old (0000003.pro) PID number, then the party member options screen shouldn't fire, because Lucas_Ptr would still be 0.

    Maybe the internal info only applies if you want to alter the prototype, and give more HP's or whatever. Or am I missing something?
     
  6. MIB88

    MIB88 So Old I'm Losing Radiation Signs
    Modder

    Feb 22, 2005
    That's my point: what you describe is not a "fresh" .pro file. A fresh one would be made from scratch, not just copied and renamed.

    What I mentioned has nothing to do with how the critter is added to the party. The script and numbering are all good. But, I'm saying you should change the internal number or else the .pro file itself may not be stable... Or, maybe it will be fine. However, Fallout 2 is... twitchy. I have had my share of headaches when I forgot to change the internal numbers for items. And I remember having a hard time with copied/renamed .pro files (items and critters) when that was all I did. Level-ups didn't always work properly. Corrupted maps. Maybe those issues had other causes. But, what good is adding a new critter if it is going to cause other issues down the road? (Something, again, I have some experience with.) But, it is an easy thing to change. Having the internal number wrong might not hurt the game... but having the internal number right definitely will not hurt the game.
     
  7. JimTheDinosaur

    JimTheDinosaur Vault Dweller
    Modder

    736
    Mar 17, 2013
    Ah, I understand. I tend to want to use as many shortcuts as possible, but Fallout 2 clearly doesn't take kindly to that type of attitude. I'll change the tutorial in a while. Thanks!
     
  8. Darek

    Darek is currently unavailable

    Jan 7, 2008
    First, know that the scripts in the mapper folder are from before any patches, so I would recommend getting the scripts that are updated to 1.02d from the download section (Haenlomal's work I believe). It's here.
    If you are using the unofficial patch or the RP, I would decompile and edit those scripts instead. (need to add references to the headers or write the code without macros.)

    Secondly, I would not recommend using another NPCs AI like that.
    There was a bug in the original game where Cassidy and Lenny had gotten someone else's AI in their base proto by mistake.
    That caused them to always lose their combat settings (you could temporarily change them, but the game couldn't save them so they would get reset).
    Maybe you unknowingly avoided that by also removing the old Lucas from the map and replacing him with yours (So the base proto and the critter on the map have the same AI). I don't know if that is enough, but I guess you'll find out.
     
  9. Endocore

    Endocore Look, Ma! Two Heads!
    Modder

    362
    Mar 14, 2010
  10. JimTheDinosaur

    JimTheDinosaur Vault Dweller
    Modder

    736
    Mar 17, 2013
    I don't think that should be part of the tutorial, mapper updates being the "absolute basics" and all.

    I never heard about this problem. Has this been fixed with one of the unofficial patches? I also don't fully understand how the relationship between the proto and the AI figures into this; how can proto's affect the AI they carry (maybe a stupid question)?

    Yeah, that's pretty much what I meant with the "very indepth stuff" I was trying to avoid ;). I'm pretty happy with the tutorial as it is, I just need to download FUCK and figure out how to change those internal figures and then it's done. At least, unless the thing Darek mentions is important enough to change the AI stuff.
     
  11. Darek

    Darek is currently unavailable

    Jan 7, 2008
    http://www.nma-fallout.com/forum/viewtopic.php?p=667722
    The unofficial patch and the RP fixes this by injecting a proper pro file into the master.dat

    As for how the protos affect the AI, I don't know exactly. It depends on how and where the combat settings are stored.
    I guess it gets the AI number from the base proto and then adds the settings to Function 12 in Save.dat, from the AI text file.

    I'm not saying you will run into trouble sharing AI's between NPCs, just that you should be on the look out, and if it don't work you will know why.
    A lot of Fallout modding is done by trial and error.
     
  12. JimTheDinosaur

    JimTheDinosaur Vault Dweller
    Modder

    736
    Mar 17, 2013
    Ah, I think I understand now, thanks! I didn't know there was a "base" proto other than the one used in the map (I already checked the AI on Cassidy in Vault City and was confused to find it being the proper one). I'm guessing the main problems of not saving settings are caused by the conflict between the base "wrong" AI and the map "correct" AI interfering. If that's the case, stealing AI's for different npc's *shouldn't* be a problem, but I'm just speculating at this point.

    Once I get my computer to stop thinking FUCK is a trojan I'll see what I can do there.

    EDIT: Okay, I got the program working but it clearly doesn't show anything like a "base" AI I can change, so I still don't really know how that works. Do only party members have base protos with AI's mysteriously attached (or does Lucas also have an Arroyo Warrior AI hidden beneath somewhere)? Do party members *need* such a base proto to begin with? I guess I just don't really understand how all this base proto stuff works.
     
  13. Darek

    Darek is currently unavailable

    Jan 7, 2008
    If you set up the mapper correctly you should be able to find text file of the protos you have edited in here: "C:\Fallout2\dev\proto\critters".
    Lucas should have "ai_packet: 1" as standard but if you changed it to Sulik_Custom it will obviously be something else.

    Everybody has a base proto(first), it's just that NPCs who can level up have extra, one per level.

    The special thing about base protos for NPCs (everyone listed in party.txt) is that the game will add a copy of them in your save game slot and then add info from their extra ones on level up.These base protos cannot be write protected as then the copies in the save game slot will also be write protected, preventing them from getting updated when needed (level up, armor changes and drug use).
    Now, the game deletes protos that are not write protected from the data folder which is no good. At the moment the only solution is to inject an edited/added base proto of an NPCs from party.txt into master.dat.
    It is possible it could work to put the new base proto into a patch file, but I was not successful when i tried (not an expert so I might have messed something up). No one else bothered to look into it so who knows.

    Can't help you with FUCK, was a long time ago I looked at it and my anti-virus program has removed it a long time ago (thanks Norton), but if you open the pro file with a hex editor it's offset 27 you want to edit.
     
  14. JimTheDinosaur

    JimTheDinosaur Vault Dweller
    Modder

    736
    Mar 17, 2013
    Ah, thanks a lot for the explanation, though I have to admit I'm too stupid to understand some of the finer points. Do I understand correctly (I undoubtedly don't) that it's impossible to insert new multi-level npc's to the game without putting them in the master.dat? Or does it also apply to non-leveling npc's (I mean, these would be in party.txt, but their protos wouldn't need to be write protected because they wouldn't level up, right?). I hope I'm not wearing your patience.
     
  15. Darek

    Darek is currently unavailable

    Jan 7, 2008
    Well as far as I know, yes you do need to add any NEW party member to the master.dat. Only the first proto though, and with the right tool it's not that hard to do.
    NPCs that don't level up still would still need need to have their protos in the save slot updated in regards to armor and drugs.

    I'll try to explain it again...
    Protos in "...\DATA\Proto\Critters" needs to be write protected or they will be deleted from the game, that's because the game uses that folder as a temp folder, and wants to clear files after they have been used.

    Because the base (first) proto of a party member is copied over to the save game and the copy protection is retained, it will make updating of that proto impossible later.

    So that is a big problem and why you can't really have the first proto of any party member in "...\DATA\Proto\Critters".

    If you make a party member from a critter that is already in the game (where you don't have to edit the proto) you wont have this problem.
    The proto don't contain any AI information, just a reference to the AI packet number. So in theory you could edit the AI text instead (probably needs to be a critter with a unique AI though).
     
  16. JimTheDinosaur

    JimTheDinosaur Vault Dweller
    Modder

    736
    Mar 17, 2013
    Thanks again for explaining things to me; I'll just see what happens once I gather the courage to start Fallout 2 and then see for myself (like you said, trial and error) what the effects are of my approach.
     
  17. damonicos

    damonicos First time out of the vault

    18
    Jan 5, 2015
    Im Trying to learn Mapping/Scripting 1 small step at a time, And the plethora of Tutorials have been both a blessing and a burden. I like this Step By Step for
    doing exactly what I want to do eventually, which is change the npcs etc and I can see results (Not get too dissuaded)
    However Step 4 lost me (seemingly because its the no brainer step)
    So i will ask the most noobie scripting question about implementing step 4. You said

    4: Now go to the individual script file (i.e. acfist.ssl in the mapper scripts) and add
    Code:
    #define lucas_joins_party party_add_self; \
    critter_add_trait(self_obj,TRAIT_OBJECT,OBJECT_TEAM_NUM,TEAM_PLAYER)
    and put lucas_joins_party at whichever point (e.g. in converstation) you want him to come in your party.

    I dont know where to do this. I just want to make one of my answer in dialogue cause him to join me, For Instance here (i think) is where id like him to join

    Code:
    procedure Node003 begin   Reply(mstr(112)+obj_name(dude_obj)+mstr(113));
    
    
       NOption(114,Node017a,004), Klint_joins_party);
       NOption(115,Node004,004);
       NOption(116,Node005,004);
      
    
    end
    This of course didnt work... (Am I showing how new to this I am yet?)

    Thank you for this step by step! The only things I want to learn right now is how to add an NPC or 2 (replace if need be) Change some dialogue etc.. This is a perfect start.

    Damon

    (btw I was lazy and attempted it with Klint as opposed to Lucas because Klint is Right there at Artemple...Guess that was my first mistake)
     
    Last edited: Jan 27, 2015
  18. JimTheDinosaur

    JimTheDinosaur Vault Dweller
    Modder

    736
    Mar 17, 2013
    Hey @damonicos, sorry for the way too late response!
    Code:
    #define lucas_joins_party party_add_self; \
    critter_add_trait(self_obj,TRAIT_OBJECT,OBJECT_TEAM_NUM,TEAM_PLAYER)
    just put this at the top of the script, where you find procedures and variables "declared" that get used further down (e.g. near Procedure Node001; ).

    Code:
    procedure Node003 begin   Reply(mstr(112)+obj_name(dude_obj)+mstr(113));
    
    
       NOption(114,Node017a,004), Klint_joins_party);
       NOption(115,Node004,004);
       NOption(116,Node005,004);
      
    
    end
    You can't call klint_joins_party (or anything else really) that way dude: all that a define does it make a shortcut for the code that follows it. So, what you've actually written there is:

    Code:
    procedure Node003 begin   Reply(mstr(112)+obj_name(dude_obj)+mstr(113));
    
    
       NOption(114,Node017a,004), [FONT=Verdana]party_add_self;[/FONT]
    [FONT=Verdana]critter_add_trait(self_obj,TRAIT_OBJECT,OBJECT_TEA M_NUM,TEAM_PLAYER)[/FONT]);
       NOption(115,Node004,004);
       NOption(116,Node005,004);
      
    
    end
    
    On top of that party_add_self is also a shortcut (macro) for a larger piece of code, which you can find in the PARTY.H header: so this actually says:

    Code:
    procedure Node003 begin Reply(mstr(112)+obj_name(dude_obj)+mstr(113));
    
    
    NOption(114,Node017a,004), if (is_critter_dead(self_obj) == false) then begin                            \                                               
     if (local_var(LVAR_FOLLOW_DISTANCE) == 0) then begin                       \
                                                       set_default_party_follow;                                               \
                                                    end                                                                        \
                                                    set_local_var(LVAR_WAITING, 0);                                            \
                                                    store_party_team                                                           \
                                                    critter_add_trait(self_obj, TRAIT_OBJECT, OBJECT_TEAM_NUM, TEAM_PLAYER);   \
                                                    party_add(self_obj);                                                       \
                                                 end                                                                           \
                                                 debug_msg("join party: " + self_name)[FONT=Verdana];      \[/FONT]
    [FONT=Verdana]critter_add_trait(self_obj,TRAIT_OBJECT,OBJECT_TEA M_NUM,TEAM_PLAYER)[/FONT]);
    NOption(115,Node004,004);
    NOption(116,Node005,004);
    
    
    end
    With the backslashes denoting an end of line. I'm just showing all of this to point out how careful you have to be with what it is you call: most things in Fallout scripting stand for something else. So, instead, you should've done this:

    Code:
    procedure Node003 begin Reply(mstr(112)+obj_name(dude_obj)+mstr(113));
    
    Klint_joins_party;
    NOption(114,Node017a,004);
    NOption(115,Node004,004);
    NOption(116,Node005,004);
    
    
    end
    This way, the code, when unraveled, looks completely proper:

    Code:
    procedure Node003 begin Reply(mstr(112)+obj_name(dude_obj)+mstr(113));
    
    if (is_critter_dead(self_obj) == false) then begin                            \                                               
     if (local_var(LVAR_FOLLOW_DISTANCE) == 0) then begin                       \
                                                       set_default_party_follow;                                               \
                                                    end                                                                        \
                                                    set_local_var(LVAR_WAITING, 0);                                            \
                                                    store_party_team                                                           \
                                                    critter_add_trait(self_obj, TRAIT_OBJECT, OBJECT_TEAM_NUM, TEAM_PLAYER);   \
                                                    party_add(self_obj);                                                       \
                                                 end                                                                           \
                                                 debug_msg("join party: " + self_name)[FONT=Verdana];      \[/FONT]
    [FONT=Verdana]critter_add_trait(self_obj,TRAIT_OBJECT,OBJECT_TEA M_NUM,TEAM_PLAYER)[/FONT];
    NOption(114,Node017a,004);
    NOption(115,Node004,004);
    NOption(116,Node005,004);
    
    
    end
    Sorry for the elaborate examples, but it's really something you need to keep in mind. Also, don't go adding additional arguments (like you did by adding a comma and stuff after NOption); NOption takes three arguments, that's the max ;).
     
    Last edited: Feb 13, 2015
  19. JimTheDinosaur

    JimTheDinosaur Vault Dweller
    Modder

    736
    Mar 17, 2013