To conclude my trilogy of tutorials by beginners for beginners, here's one on caravans. My last tutorial didn't get a single comment; which, being an eternal optimist I interpreted as a sign that the tutorial was perfect and every veteran simply nodded his head approvingly while reading it.
As an aside, caravans were always something I was a bit dissappointed in in Fallout. I mean, they were a lot of fun, but they basically only existed as little more than a get rich quick scheme, whereas you would think a world where even plants and ants have mutated into giant killing machines, moving around from town to town would generally require armed caravans.
But anyway, let's say we want to make a caravan of trappers from Klamath to the Den, what do we do? As previously, I'm going to assume you understand the basics (this time I'm also going to assume you understand that whenever you add a new procedure/node/variable, you need to introduce it in the script).
1: There are no existing caravan routes from Klamath to the Den, so we need to make one in BHRNDDST.H. Start by adding the line:
Here we delineate the area in which our encounters will take place. Unless there's a worldmap with x and y coordinates lying around somewhere I don't know of, you just need to look at the city coordinates in city.txt to get an idea where you are on the world map (e.g. the example is a box with Klamath at the top left corner and the Den at the lower right corner). Also, check that the area doesn't overlap with an already existing one. Now for the route:
To the bottom of the file, add:
The x,y coordinates show where you end up on the world map if the caravan "fails", and which encounter is fired (so, since all the coordinates are within our Klamath to Den box, these are the encounters that are fired). You can of course have as many possible encounters as you like, but 2 sounds about right here.
2: Now for the encounters, go to BHRNDDST.SSL (so this time the script, not the header file) and add the line:
Now let's define the procedure The_Den_Encounter:
I've kept it simple here: there's two possible encounters (50/50 chance) on the caravan: klamath_rats and klamath_robbers, which we'll get to in a second. Encounter_Counter is what determines how many critters show up, though you shouldn't mistake it for the exact number (e.g. in this example, there won't be 8-12 rats). To see what it does mean, let's set up the Klamath_Rats procedure:
Suppose the Encounter_Counter comes out as 10, then the outcome will be 10*2/5 = 4 mole rats and 10*4/5 = 8 pig rats, so twelve in total (in case you're wondering, non-round numbers get rounded down).
The thing I still can't get a handle on is how critters are placed. In this example, we defined Encounter_Rotation as dude_cur_rot so with
you'd expect the enemies to get placed in front of where the player is facing; instead they end up all over the place. If anyone can tell me why I'd love to know.
3: Now to set up the caravan. First, make a global variable called TRAPPER_CARAVAN. Then, in the script of the trappers in Trapper Town (kctrapr.ssl), add the Start_Caravan procedure and have it called through dialogue or something:
As you can deduce, this caravan goes from Klamath to the Den, with 0 to 2 encounters (if you want more you need to add the coordinates to the header file in step 1), one caravan master, one cart (how many gecko pelts can they have), two brahmin, and two drivers.
4: Now, go back to BHRNDDST.ssl and add the following line to map_enter_p_proc:
For the Trapper_Caravan procedure:
Now, scroll down to the Build_Caravan_Team procedure. For my example, I just tried to replicate the three trappers in Trapper Town, but you can do whatever you feel like of course. For instance, for the first caravan driver I used:
This creates the leather jacket trapper with a pipe rifle (wielded) and some rounds. This is different from the system the script usually uses, which is in the form of a random male/female of a certain type, with a random weapon chosen from a few options. To simply copy this system is risky given that most models only support a few types of weapons. So, for instance, if I had used this system with either male or female trapper, with either a spear or a pipe gun, then the female trapper could end up with a pipe gun she couldn't use (because of no animation being there).
Finally, just add one additional procedure:
The only additional thing this really does in practice is let you decide the time that elapses between encounters.
And there you have it.
IMPORTANT NOTE: After hours of dealing with an incredibly annoying CTD problem when making a new caravan, I finally found the solution. If you look at the build_caravan procedure, you should take note of the fact that beneath the part where the guards are placed there's this line:
This gives a shortcut to having critters get and wield weapons. Somewhat counter-intuitively, this also apparently means that if you try to place a critter WITHOUT this shortcut in place (say, you try placing an unarmed critter), the game goes berserk. Just keep this in mind.
EDIT 2: Given that this is a very barebones tutorial, I didn't add a lot of features that are easy enough to implement (for instance, if you want to use a script different than the generic guard/master/driver ones, you should remember to add the commands that remove them from the caravan should they die, etc.). However, there's one last element of the caravan script that is counterintuitive enough to warrant an additional note, namely that the system used by the developers is that you automatically "fail" the run the moment an encounter takes place, and that you lose this failure the moment you kill all the baddies. This is to make sure you don't go to the next encounter once you leave the map during an encounter.
As an aside, caravans were always something I was a bit dissappointed in in Fallout. I mean, they were a lot of fun, but they basically only existed as little more than a get rich quick scheme, whereas you would think a world where even plants and ants have mutated into giant killing machines, moving around from town to town would generally require armed caravans.
But anyway, let's say we want to make a caravan of trappers from Klamath to the Den, what do we do? As previously, I'm going to assume you understand the basics (this time I'm also going to assume you understand that whenever you add a new procedure/node/variable, you need to introduce it in the script).
1: There are no existing caravan routes from Klamath to the Den, so we need to make one in BHRNDDST.H. Start by adding the line:
Code:
#define WM_In_Klamath_Den(x,y) ((x >= 300) and (x <500>= 100) and (y <= 300))
Here we delineate the area in which our encounters will take place. Unless there's a worldmap with x and y coordinates lying around somewhere I don't know of, you just need to look at the city coordinates in city.txt to get an idea where you are on the world map (e.g. the example is a box with Klamath at the top left corner and the Den at the lower right corner). Also, check that the area doesn't overlap with an already existing one. Now for the route:
To the bottom of the file, add:
Code:
// Klamath --> Den, 1 Encounter Only
#define Klamath_Den_1_1_x (420)
#define Klamath_Den_1_1_y (175)
// Klamath --> Den, 2 Encounters
#define Klamath_Den_2_1_x (390)
#define Klamath_Den_2_1_y (150)
#define Klamath_Den_2_2_x (450)
#define Klamath_Den_2_2_y (250)
The x,y coordinates show where you end up on the world map if the caravan "fails", and which encounter is fired (so, since all the coordinates are within our Klamath to Den box, these are the encounters that are fired). You can of course have as many possible encounters as you like, but 2 sounds about right here.
2: Now for the encounters, go to BHRNDDST.SSL (so this time the script, not the header file) and add the line:
Code:
else if (WM_In_Klamath_Den(worldmap_xpos,worldmap_ypos)) then \
call The_Den_Encounter;
Now let's define the procedure The_Den_Encounter:
Code:
procedure The_Den_Encounter begin
variable Encounter;
Encounter:=random(0,99);
// enc_00
if (Encounter < 50) then begin
debug_msg("Klamath_Encounter Table, Encounter 01");
display_msg(mstr(403));
Encounter_Counter:=random(8,12);
Encounter_Rotation:=dude_cur_rot;
call Klamath_Rats;
end
// enc_01
else if (Encounter < 100) then begin
debug_msg("Den_Encounter Table, Encounter 01");
display_msg(mstr(501));
Encounter_Counter:=random(1,3);
Encounter_Rotation:=dude_cur_rot;
call Klamath_Robbers;
end
end
I've kept it simple here: there's two possible encounters (50/50 chance) on the caravan: klamath_rats and klamath_robbers, which we'll get to in a second. Encounter_Counter is what determines how many critters show up, though you shouldn't mistake it for the exact number (e.g. in this example, there won't be 8-12 rats). To see what it does mean, let's set up the Klamath_Rats procedure:
Code:
procedure Klamath_Rats begin
variable Critter_Counter:=0;
variable Critter_Total;
//variable Critter;
variable Critter_Tile;
variable item;
Critter_Tile:=tile_num_in_direction(tile_num(dude_obj),Encounter_Rotation,dude_perception*2);
Critter_Total:=(Encounter_Counter*2)/5;
Critter_Counter:=0;
if (Critter_Total < 1) then
Critter_Total:=1;
while (Critter_Counter < Critter_Total) do begin
Create_Enemy(PID_MOLE_RAT,-1,SCRIPT_ECRAT);
inc_map_var(MVAR_Hostile_Total);
end
Critter_Total:=(Encounter_Counter*4)/5;
Critter_Counter:=0;
if (Critter_Total < 1) then
Critter_Total:=1;
while (Critter_Counter < Critter_Total) do begin
Create_Enemy(PID_PIG_RAT,-1,SCRIPT_ECRAT);
inc_map_var(MVAR_Hostile_Total);
end
end
Suppose the Encounter_Counter comes out as 10, then the outcome will be 10*2/5 = 4 mole rats and 10*4/5 = 8 pig rats, so twelve in total (in case you're wondering, non-round numbers get rounded down).
The thing I still can't get a handle on is how critters are placed. In this example, we defined Encounter_Rotation as dude_cur_rot so with
Code:
Critter_Tile:=tile_num_in_direction(tile_num(dude_obj),Encounter_Rotation,dude_perception*2);
you'd expect the enemies to get placed in front of where the player is facing; instead they end up all over the place. If anyone can tell me why I'd love to know.
3: Now to set up the caravan. First, make a global variable called TRAPPER_CARAVAN. Then, in the script of the trappers in Trapper Town (kctrapr.ssl), add the Start_Caravan procedure and have it called through dialogue or something:
Code:
procedure StartCaravan begin
variable Caravan_Carts;
variable Caravan_Encounters;
variable Caravan_Guards;
set_global_var(GVAR_CARAVAN_START, CARAVAN_KLAMATH);
set_global_var(GVAR_CARAVAN_END, CARAVAN_THE_DEN);
set_global_var(GVAR_TRAPPER_CARAVAN,CARAVAN_STATUS_ON_JOB);
set_caravan_status(CARAVAN_STATUS_ON_JOB);
Caravan_Encounters := random( 0, 2 );
set_caravan_encounters( Caravan_Encounters );
//debug_msg("ENCOUNTERS=" + k);
if (global_var(GVAR_CARAVAN_ENCOUNTERS_TOTAL) == 0) then begin
Caravan_Guards := 1;
set_caravan_guards( Caravan_Guards );
game_time_advance(6*ONE_GAME_DAY);
load_map(MAPSTR_DEBBUS1,0);
end
else begin
Caravan_Carts:=1;
Caravan_Guards:=0;
set_caravan_masters(1);
set_caravan_guards( Caravan_Guards );
set_caravan_carts( Caravan_Carts );
set_caravan_brahmin( 2 * Caravan_Carts );
set_caravan_drivers( 2 * Caravan_Carts );
load_map(MAPSTR_BHRNDDST,11); //<-robs map script ignores this index...must be above 10
//however to put caravan in center of map
end
end
As you can deduce, this caravan goes from Klamath to the Den, with 0 to 2 encounters (if you want more you need to add the coordinates to the header file in step 1), one caravan master, one cart (how many gecko pelts can they have), two brahmin, and two drivers.
4: Now, go back to BHRNDDST.ssl and add the following line to map_enter_p_proc:
Code:
else if (global_var(GVAR_TRAPPER_CARAVAN) == CARAVAN_STATUS_ON_JOB) then begin
call Trapper_Caravan;
end
For the Trapper_Caravan procedure:
Code:
procedure Trapper_Caravan begin
variable Encounter_Number;
call Klamath_Den_Encounters;
call Build_Caravan_Team;
end
Now, scroll down to the Build_Caravan_Team procedure. For my example, I just tried to replicate the three trappers in Trapper Town, but you can do whatever you feel like of course. For instance, for the first caravan driver I used:
Code:
else if (global_var(GVAR_TRAPPER_CARAVAN) == CARAVAN_STATUS_ON_JOB) then begin
Critter:=create_object_sid(PID_MALE_TRAPPER,0,0,SCRIPT_RCCVNGRD);
add_obj_to_inven(Critter,create_object(PID_10MM_JHP,0,0));
item:=create_object(PID_SPRINGER_RIFLE,0,0);
end
This creates the leather jacket trapper with a pipe rifle (wielded) and some rounds. This is different from the system the script usually uses, which is in the form of a random male/female of a certain type, with a random weapon chosen from a few options. To simply copy this system is risky given that most models only support a few types of weapons. So, for instance, if I had used this system with either male or female trapper, with either a spear or a pipe gun, then the female trapper could end up with a pipe gun she couldn't use (because of no animation being there).
Finally, just add one additional procedure:
Code:
procedure Klamath_Den_Encounters begin
variable Encounter_Number;
Encounter_Number:=total_encounters - encounters_left;
if (total_encounters == 1) then begin
set_caravan_pos(Klamath_Den_1_1_x,Klamath_Den_1_1_y);
set_exit_grids(0,-2,0,20100,0); // Exit grids on elevation 0 goto Worldmap
game_time_advance(6*ONE_GAME_DAY);
check_area;
end
else if (total_encounters == 2) then begin
if (Encounter_Number == 0) then begin // this is the first encounter
set_caravan_pos(Klamath_Den_2_2_x,Klamath_Den_2_2_y);
set_exit_grids(0,-2,0,20100,0); // Exit grids on elevation 0 goto Worldmap
game_time_advance(3*ONE_GAME_DAY);
check_area;
end
else if (Encounter_Number == 1) then begin // this is the second encounter
set_caravan_pos(Klamath_Den_2_1_x,Klamath_Den_2_1_y);
set_exit_grids(0,-2,0,20100,0); // Exit grids on elevation 0 goto Worldmap
game_time_advance(3*ONE_GAME_DAY);
check_area;
end
end
end
The only additional thing this really does in practice is let you decide the time that elapses between encounters.
And there you have it.
IMPORTANT NOTE: After hours of dealing with an incredibly annoying CTD problem when making a new caravan, I finally found the solution. If you look at the build_caravan procedure, you should take note of the fact that beneath the part where the guards are placed there's this line:
Code:
add_obj_to_inven(Critter,item);
wield_obj_critter(Critter,item);
This gives a shortcut to having critters get and wield weapons. Somewhat counter-intuitively, this also apparently means that if you try to place a critter WITHOUT this shortcut in place (say, you try placing an unarmed critter), the game goes berserk. Just keep this in mind.
EDIT 2: Given that this is a very barebones tutorial, I didn't add a lot of features that are easy enough to implement (for instance, if you want to use a script different than the generic guard/master/driver ones, you should remember to add the commands that remove them from the caravan should they die, etc.). However, there's one last element of the caravan script that is counterintuitive enough to warrant an additional note, namely that the system used by the developers is that you automatically "fail" the run the moment an encounter takes place, and that you lose this failure the moment you kill all the baddies. This is to make sure you don't go to the next encounter once you leave the map during an encounter.