Scripting isn't as easy as I thought...

Discussion in 'Fallout General Modding' started by Robert B, Jun 3, 2017.

  1. Robert B

    Robert B Kitty's got some rads!

    May 29, 2017
    Okay, so forgive me as I work my way through creating my first more complex mod. I've decided to test out script snippets in the existing game files before I go creating my own from scratch. I've had no problem with more complex commands (like manipulating player inventory, updating stats, etc.); but this simple one appears to stump me.

    Say I want to have a message come up in the dialog screen every time someone comes into a specific map location. In this case, I'm editing ARTEMPLE.SSL for the sake of simplicity. I have written the following lines of code...

    procedure start
    begin
    display_msg("start test");
    end

    So that's good. It works in the start procedure and the message is displayed.

    Now for where things break. If I put the same command display_msg("start test"); into one of the other procedures, it doesn't work. For example, I put it in procedure Initial_Inven, I no longer get the text to come up, but the rest of the commands in that procedure execute.

    What inanely simple thing am I missing?

    Thanks in advance!

    RB.-

    Ah, okay, to refine the situation... The display message command works before I do my inventory adjustment; but not afterward. Here's how the procedure looks...

    procedure Initial_Inven
    begin
    variable LVar0 := 0;
    display_msg("Initial_Inven"); <-- This one works
    LVar0 := create_object_sid(1, 0, 0, -1);
    add_mult_objs_to_inven(dude_obj, LVar0, 1);
    display_msg("Initial_Inven End"); <-- This one doesn't
    end

    Ugh! Nevermind. It's suddenly working and I didn't change the code at all. Is this an indication that FO2 scripting is glitchy?
     
    Last edited by a moderator: Jun 15, 2017
  2. Lexx

    Lexx Lived Through the Heat Death
    Moderator

    Apr 24, 2005
    If you want to show a text on map enter, use the map_enter_p_proc procedure instead. It is called on every map enter (also on reload, so be sure to check for "if not game_loaded then..". start_p_proc gets only called when the script is created.

    No idea why your display_msg doesn't work after add_mult_... but what makes me wonder is your use of "LVar0" - did you decompile the script on your own? If so, why? You get the uncompiled scripts with the BIS mapper. You should also read up on this stuff, especially the scripting tutorials. Also - to learn - you should read through the original scripts and see how stuff is done.
     
  3. Robert B

    Robert B Kitty's got some rads!

    May 29, 2017
    Great advice @Lexx. I'm working it now. Obviously this has quite a learning curve to it. :)
     
  4. Lexx

    Lexx Lived Through the Heat Death
    Moderator

    Apr 24, 2005
    Writing scripts for Fo2 is actually extremely easy, you just have to know what the engine can and can't do. Also like I wrote above, it helps a lot to read the original scripts and see how stuff gets done there. Most "technics" are repeating themselves anyway after some time... like, making a villager run around randomly is usually always done the same way, or the way dialog works, etc... if you have a few basic programming skills, shit should be no trouble for you after a while.
     
  5. Robert B

    Robert B Kitty's got some rads!

    May 29, 2017
    Okay, things are improving... I figured out where my errors were in the prior scripts and am moving on to other commands. Currently I'm testing the utilization of
    critter_add_trait(int Critter, ObjectPtr, trait_type, trait, amount).

    So far, things have been pretty simple. If you enter zero into the trait type field, you can identify all of the perks in FO2. (all 118 of them)

    Perks are great, but I'm also interested in setting the traits like Bruiser and Bloody Mess. For that I anticipated I could enter a value of 1 into the trait_type field and get the traits; but that doesn't happen. I tried a few other values and had no luck there either.

    Am I using the correct command to identify and set traits on Dude_Obj? I've been digging through script examples to find someone else that has done this; but I'm coming up empty.

    Thanks a bundle,

    RB.-
     
  6. Lexx

    Lexx Lived Through the Heat Death
    Moderator

    Apr 24, 2005
    You're doing this way too complicated. All this stuff is defined in headers/define.h, you just have to look it up.

    [/code]
    #define TRAIT_fast_metabolism (0)
    #define TRAIT_bruiser (1)
    #define TRAIT_small_frame (2)
    #define TRAIT_one_hander (3)
    #define TRAIT_finesse (4)
    #define TRAIT_kamikaze (5)
    #define TRAIT_heavy_handed (6)
    #define TRAIT_fast_shot (7)
    #define TRAIT_bloody_mess (8)
    #define TRAIT_jinxed (9)
    #define TRAIT_good_natured (10)
    #define TRAIT_drug_addict (11)
    #define TRAIT_drug_resistant (12)
    #define TRAIT_sex_appeal (13)
    #define TRAIT_skilled (14)
    #define TRAIT_gifted (15)[/code]

    Not sure if you can give the player more traits this way (perks is a different story), because I never tried.
     
  7. Robert B

    Robert B Kitty's got some rads!

    May 29, 2017
    Well that simplifies life! I've slowly been going through the resources you suggested above but hadn't yet reached the article on the BIS Headers. To think, I spent several hours mapping out what all those perks were and it was already sitting (defined), in the DEFINE.H file. Ah well, some of us just have to learn the hard way!

    As for whether you can set the traits in script for Dude_obj, the answer is no. You can read the field values that exist, but you can't define them for an existing character. I guess I'll just have to stick to perk updates in my scripting. :)

    So, I'll be tackling a few more articles and digging into the header files before I do anymore coding. I appreciate you taking time to respond to my queries. It's very helpful.

    All the best,

    RB.-

    Alrighty, with @Lexx 's assistance, I've been able to get through all the helpful documentation at Valt-tec Labs website as well as dig into the modding resources with the tools I've already downloaded. It's a good start and I'm very appreciative of all the assistance.

    So now I've created several mod's that do simple things..

    - Set deathclaws loose in vault city so I could watch the carnage
    - Determine a toon's initial inventory based on a skill check
    - Perk and other attribute assignment to object Dude_Obj
    - Multiple changes to existing maps with and without attached scripts
    - Made some dialog changes for existing game characters

    That's all well and good; but my real objective is to create a complete replacement mod. In all the documentation I've reviewed, there's really not a "how to get started with a big ol' project like that..." Sooooo here's my plan of attack...

    1) I need to create a new starting map (Duh)... IN PROGRESS
    I've created a new map 00001.map along with a complementary script 00001.ssl (which is basically a straight copy of the artemple.ssl code). I'm developing the basics of it and will soon try to link multiple maps together using exit grids. (Wish me luck!) I've used the sFall config file to re-assign my map as the starting map for FO2....​
    2) I need to get rid of the Elder movie that will no longer be relevant for my replacement mod... NOT DONE
    I have no clue how to do this as I don't where this is scripted in the original game​
    3) I need to convert the model for the Dude_Obj from tribal to Vault13 suit. NOT DONE
    I've checked all the global variables I could find and don't see how this is accomplished​
    4) I need to map out the main quest-line so that I can build out the mod based on a fixed reference. IN PROGRESS
    This is going well. I'm a few pages into the outline and pretty happy with what I've put together so far.​

    So anyway, this is how I'm starting. Any suggestions for things I should be doing or pointers on additional references I should be reviewing?

    Thanks a bundle,

    RB.-
     
    Last edited by a moderator: Jun 15, 2017
  8. Lexx

    Lexx Lived Through the Heat Death
    Moderator

    Apr 24, 2005
    2) It's in the ddraw.ini as well.
    Code:
    Movie1=iplogo.mve
    Movie2=intro.mve
    Movie3=elder.mve
    Movie4=vsuit.mve
    Movie5=afailed.mve
    ...
    I have made a "blank.mve" movie file that is pretty much a 0kb renamed txt file. You can overwrite the existing videos with it.

    3) The player character switches his graphic after vsuit.mve is played (Movie4). Then he also gets the PipBoy. So you can replace the video with the above mentioned blank file and then trigger it via script on map enter ("play_gmovie(VSUIT_MOVIE);") or you just modify the ddraw.ini again:
    Code:
    PipBoyAvailableAtGameStart=1
    To change the player appearance, you'll have to edit the following lines:
    Code:
    ;To change the default and starting player models, uncomment the next four lines.
    ;The default models can also be changed ingame via script
    MaleStartModel=hmlthr
    MaleDefaultModel=hmlthr
    FemaleStartModel=hflthr
    FemaleDefaultModel=hflthr
    The above will have you start with leather armor visuals.


    Well, just some generic ones:
    - After you're done with outlining your story, create all your needed location maps as placeholder and get them into the game.
    - Make it possible to visit all locations (just put them right next to each other on the worldmap).
    - After this works, put down main story related template NPCs.
    - Give them very basic dialog that let's you click through the main story from the beginning to the end.

    Once this is done, you'll know if your story works ok or if it's a turd (also it helps with scripting, as you broke it down into tiny bits already and made it work). Then you can care about anything else. In my experience, though, it is always better to save the mapping and graphics part to a later time. Folks like to burn themselves out on graphics while scripts and dialog aren't making any progress. We had many Fallout mods die this way.
     
    Last edited: Jun 5, 2017
  9. Robert B

    Robert B Kitty's got some rads!

    May 29, 2017
    Great advice @Lexx! I will take it all to heart and approach the tasks as you recommend. I can really see how the graphics can burn people out. I've been rebuilding Shady Sands as part of my mod and it definitely is a time suck. (Importing the FO1 Map did not go seamlessly as they changed a lot of graphics from FO1 to FO2...) :D

    I'll let you know how it goes...

    All the best,

    RB.-
     
  10. areneusz23

    areneusz23 First time out of the vault

    Jun 30, 2013
    Robert is your surname is Balcerzak?
     
  11. Robert B

    Robert B Kitty's got some rads!

    May 29, 2017
    Nope @areneusz23.

    Alright, so today's scripting question goes to the function "Place Spatial Script" in the BIS Editor.

    What I'm trying to do: I'd like a floating message to pop up when the player approaches a specific location on the map

    What I did: I created a spatial script which is basically float_msg(dude_obj,"message",0) and placed it approximately 50 hexes from the map entrance with a radius of 2.

    What I observed: The spatial script I've created executes immediately upon player entry to the map no matter what radius I set. It also (when I walk within the radius set) executes properly after the initial script execution.

    What I've tried to do to figure this out myself: There's actually nothing about this function in the Fallout 2 Editor documentation so I dug around for other references. I searched NMA, NMA Archives and Vault-Tec Labs for any reference to Spatial Script. The only reference I found in tutorials was in relation to it's use in elevators by ColJack. I pulled up the script zselev01.int (which is assigned to level 1 elevator locations) to determine if there was some logic that prevented the script from executing based on distance. There doesn't appear to be.

    I also found many references on NMA and in the NMA archives to people actually using the spatial script function (along with their code); but nothing that indicated there might be problems with how/when a script would be executed. There was also nothing in the discussed scripts on limiting the execution based on distance.

    My questions: Is there another place I should be looking to find the answer as to why this function isn't working for me? If not, does anyone have any suggestion about a solution or an alternate approach to use?

    I'm thinking I COULD set a local variable and simply ignore the first execution of the script; but I don't know that the workaround is the proper approach.

    EDIT: You know, I think I might need a global variable. I think it's being reset every time the procedure is called. I'll try to figure that out. (I haven't used global variables yet...)

    Thank you in advance!

    RB.-
     
    Last edited by a moderator: Jun 15, 2017
  12. Lexx

    Lexx Lived Through the Heat Death
    Moderator

    Apr 24, 2005
    You have to check if the player (or any other critter) is triggering it.

    Code:
    #include "..\headers\define.h"
    
    #define NAME                    SCRIPT_GENMSG1
    #include "..\headers\command.h"
    
    procedure spatial_p_proc;
    procedure start;
    
    #define LVAR_Say_Once                     (0)
    
    #define float_dude_obj(x)                    float_msg(dude_obj, message_str(NAME,x), FLOAT_MSG_NORMAL)
    
    procedure start begin
    end
    
    procedure spatial_p_proc begin
       if (source_obj == dude_obj) then begin
          if (local_var(LVAR_Say_Once) == 0) then begin
             set_local_var(LVAR_Say_Once,1);
             float_dude_obj(251);
           end
       end
    end
    
    In theory you could also destroy the object after the message is triggered... then you don't have to set a local variable, but the script will be gone and can't be triggered ever again. Using a global variable for such a case is unnecessary.

    PS: If you're having scripting questions, it's best to post your stuff as example.
     
  13. Robert B

    Robert B Kitty's got some rads!

    May 29, 2017
    I never would have come up with that solution @Lexx, but it makes sense that the script would be triggered by ANYTHING that comes within range of the spatial script. I'll give the code a test next time I'm in the script editor.

    I actually would have thought I could set the local variable LVAR_Say_Once, by using the line of code:

    LVAR_Say_Once := LVAR_Say_Once +1;
    or
    LVAR_Say_Once := 1;​

    Is this an incorrect way to handle the variable? It's been over a decade since I programmed anything... I've been spoiled with modding other, newer games.

    EDIT: Perhaps it's because you used "Define" for the variable rather than "Variable"? I would have put:

    Variable LVAR_Say_Once :=0;
    I'm not sure of the difference in the two ways of handling this...
    Regardless, I'm slowly working my way through code examples and think I've finally completed my list of "operators" for if/then statements. To me it looks like it's all standard "C" code.

    10 > 5 TRUE
    6 < 15 TRUE
    8 >= 8 TRUE
    4 <= 8 TRUE
    3 == 3 TRUE
    4 != 5 TRUE

    It's just a slow process to learn everything by reviewing past forum entries. Especially because a lot of resources are no longer available. I'm going to continue digging and asking questions as needed. Thank you for all the help.
     
    Last edited: Jun 14, 2017
  14. Lexx

    Lexx Lived Through the Heat Death
    Moderator

    Apr 24, 2005
    No idea, all I know is what I've learned from the official scripts. Local variables are always done in the way that can be seen in my post above. somestuff := x; is always a temporary variable that will be "forgotten" once the map reloads. Global variables are the only ones that can be accessed from anywhere within the game. Map variables are unique to the very map they are used in, etc.
     
  15. Robert B

    Robert B Kitty's got some rads!

    May 29, 2017
    Cool. I tested both ways. Your script and my script both work. It's good to know there's more than one way to approach the problem. Thanks @Lexx.

    Code:
    procedure spatial_p_proc;
    procedure start;
    
    variable LVAR_Say_Once:=0;
    
    procedure start begin
    end
    
    procedure spatial_p_proc begin
       if (source_obj == dude_obj) then begin
          if (LVAR_Say_Once == 0) then begin
             LVAR_Say_Once := 1;
             float_msg(dude_obj,"You feel as if you leave this place you'll never find your way back...",0);
           end
       end
    end
    
     
    Last edited: Jun 15, 2017
  16. Darek

    Darek is currently unavailable

    Jan 7, 2008
    @Robert B , your way don't work if you only want the float to come up once, as the variable is not saved. Try to trigger the spatial script and then save and load your game, you'll see the float again (unless you destroy the script after it's been triggered).

    There are 3 types of local variables (inside one script).

    The first one is the local variables that gets saved. They are the ones mentioned in the scripts.lst file (If you have one local_var in your script you have to set it to at least 1 in the script list file).

    To use these in your script you either do as @Lexx suggested, or then you skip the "define" part and just write "if (local_var(0) == 0)" or "if (local_var(1) == 0)" etc. The first way is easier to read and the second is easier to write (and the way it comes out when compiled).


    The second variable typ is the one you used. It can be used in every procedure in the script, and the name of the variable will be preserved in the compiled script. However, the value of the variable will not be saved in your savegame.


    The third type is the variable that is only used locally within one procedure (not saved either).
    Code:
    procedure Node001 begin
       variable Object:=0;
       Object := obj_carrying_pid_obj(dude_obj, 89);
       rm_obj_from_inven(dude_obj, Object);
       destroy_object(Object);
    end
    When the script is compiled the variable name will get replaced with LVar0, LVar1 etc, depending on how many variable you add. So if you are lazy you can just write LVar0 directly instead.
     
  17. Robert B

    Robert B Kitty's got some rads!

    May 29, 2017
    This is brilliant! So there are 3 different local variables. Using Define and SCRIPTS.LST (as per @Lexx) gives you a retained variable in a save. My approach works for each time FO2 is active and is not saved in the saved game file. The third variable approach you listed is only active in the selected procedure.

    Nice. I appreciate the clarification @Darek. This helps a lot.
     
  18. Robert B

    Robert B Kitty's got some rads!

    May 29, 2017
    So this is a minor point, but I thought I'd see if anyone knows how to do this off the top of their head...

    In my mod, Shady Sands is showing up as a known location on the Vault-tec Map at the start of the game. I could swear I saw where I could turn this off sometime before I went on holiday. If I were just guessing, I would have thought it was in the CITY.TXT file; but now I'm poking around and don't see it. I'm probably just being an idiot and missing it.

    I've checked a variety of locations including Art/Intrface, Data and Text/Game as the most obvious locations for a file used to set this value. I've (of course) also checked the complimentary subdirectories under Data (Data/Art/Intrface, etc.).

    Please be gentle. I know this must be stupid easy. It could just be jet-lag; but I'm just not seeing it...
     
  19. Lexx

    Lexx Lived Through the Heat Death
    Moderator

    Apr 24, 2005
    Define "known location" - is it visible on the map as green circle or do you have it in the town list, without fog of war over the zone? City.txt file only has "is location hidden on the map or not", everything else was done directly in script. Dont know the commands of the top of my head right now.
     
  20. Robert B

    Robert B Kitty's got some rads!

    May 29, 2017
    Hey @Lexx, known location means "green circle is named on the map and in the town list with a red button next to it". If this is a scripting effort, then I'll add that to my investigation list for later. I am focused on building my maps and getting the basics in place for now.

    Thanks for the reply. 90% of the battle is just knowing where I need to look for a solution. :D

    EDIT#1: It's probably related to the town_known commands in the COMMAND.H file. I'll plan to look those over when the time comes.

    EDIT#2: I discovered the source of the problem. When I created my original template for location scripts, I failed to comment out one occurrence of the command mark_area_known. Once I corrected this error, everything worked as expected.
     
    Last edited: Aug 11, 2017