• Please note that we've updated the Mount & Blade II: Bannerlord save file system which requires you to take certain steps in order for your save files to be compatible with e1.7.1 and any later updates. You can find the instructions here.

You Shall Not Pass!

Users who are viewing this thread

Fire_and_Blood

Knight at Arms
How to add You Shall Not Pass to your own mod:
Part 1

This is the first release, so both these instructions and the code will probably be improved later on.

We will edit:
Module_parties
Module_constants
Module_game_menus
Module_scripts
Module_simple_triggers
The map

Module_constants:
Just add these anywhere
#F&B begin
slot_party_destination = 600
slot_portal_using = 601 
slot_would_portal_be_used_by_party = 602
slot_detached_from_center = 603
#F&B end
Module_parties:
Add these parties that serve as portals at the end, above “spawn_points_end:
#F&B begin
  ("1","Maras Castlewalls",  pf_disabled|pf_is_static, no_menu, pt_none, fac_neutral,0,ai_bhvr_hold,0,(-123.94, -18.74),[]),
  ("2","Maras Castlewalls",  pf_disabled|pf_is_static, no_menu, pt_none, fac_neutral,0,ai_bhvr_hold,0,(-124.22, -19.53),[]),
  ("3","Almerra Castlewalls",  pf_disabled|pf_is_static, no_menu, pt_none, fac_neutral,0,ai_bhvr_hold,0,(-8.88, -63.74),[]),
  ("4","Almerra Castlewalls",  pf_disabled|pf_is_static, no_menu, pt_none, fac_neutral,0,ai_bhvr_hold,0,(-9.33, -64.39),[]),
  ("5","Nelag Castlewalls",  pf_disabled|pf_is_static, no_menu, pt_none, fac_neutral,0,ai_bhvr_hold,0,(148.52, 51.44),[]),
  ("6","Nelag Castlewalls",  pf_disabled|pf_is_static, no_menu, pt_none, fac_neutral,0,ai_bhvr_hold,0,(148.1, 50.55),[]),
  ("7","Sungetche Castlewalls",  pf_disabled|pf_is_static, no_menu, pt_none, fac_neutral,0,ai_bhvr_hold,0,(109.94, 39.85),[]),
  ("8","Sungetche Castlewalls",  pf_disabled|pf_is_static, no_menu, pt_none, fac_neutral,0,ai_bhvr_hold,0,(110.4, 39.47),[]),
  ("9","Culmarr Castlewalls",  pf_disabled|pf_is_static, no_menu, pt_none, fac_neutral,0,ai_bhvr_hold,0,(-100.64, -23.17),[]),
  ("10","Culmarr Castlewalls",  pf_disabled|pf_is_static, no_menu, pt_none, fac_neutral,0,ai_bhvr_hold,0,(-100.14, -23.6),[]),
  ("11","Etrosq Castlewalls",  pf_disabled|pf_is_static, no_menu, pt_none, fac_neutral,0,ai_bhvr_hold,0,(-101.25, -31.91),[]),
  ("12","Etrosq Castlewalls",  pf_disabled|pf_is_static, no_menu, pt_none, fac_neutral,0,ai_bhvr_hold,0,(-101.76, -32.29),[]),
#F&B end
Injecting the script everywhere:

We start by adding call_script calculate_distances to every script & trigger, event, where the ai receives a command to move. This is in a lot of places.  In Notepad++, use the “Search in files” option and search through your whole module system for “party_set_ai_object”, hash tag that line, so it gets ignored and above it add the three bolded line:
          (party_set_ai_behavior,":result",ai_bhvr_travel_to_party),
(assign, "$g_party_no", ":result"),
(assign, "$g_target_center", ":spawn_center"),
(call_script, "script_calculate_distances"),
#F&B injected
  #          (party_set_ai_object,":result",":spawn_center"),
Other times the code will look like this. Adjust (assign, “$g_party_no”, “:party_no”), and (assign, “$g_target_center”, “:spawn_center”) Sometimes these local variables are called differently, so change the bolded variables to the one used in that specific location:
            (party_set_ai_behavior, ":party_no", ai_bhvr_travel_to_party),
(assign, "$g_party_no", ":party_no"),
(assign, "$g_target_center", ":target_center"),
(call_script, "script_calculate_distances"), #F&B injected
#            (party_set_ai_object, ":party_no", ":target_center"),

Module_scripts
Places this script anywhere in module_scripts, I put it add the end. This enables ai the use of portals.
  #Script checking whether it's shorter to use portal
("calculate_distances",
[(assign, ":party_no", "$g_party_no"),
(assign, ":target_center", "$g_target_center"),
(store_distance_to_party_from_party, ":dist_portal_1", ":party_no", "p_1"),
(store_distance_to_party_from_party, ":dist_portal_2", ":party_no", "p_2"),
(store_distance_to_party_from_party, ":dist_portal_3", ":party_no", "p_3"),
(store_distance_to_party_from_party, ":dist_portal_4", ":party_no", "p_4"),
(store_distance_to_party_from_party, ":dist_portal_5", ":party_no", "p_5"),
(store_distance_to_party_from_party, ":dist_portal_6", ":party_no", "p_6"),
(store_distance_to_party_from_party, ":dist_portal_7", ":party_no", "p_7"),
(store_distance_to_party_from_party, ":dist_portal_8", ":party_no", "p_8"),
(store_distance_to_party_from_party, ":dist_portal_9", ":party_no", "p_9"),
(store_distance_to_party_from_party, ":dist_portal_10", ":party_no", "p_10"),
(store_distance_to_party_from_party, ":dist_portal_11", ":party_no", "p_11"),
(store_distance_to_party_from_party, ":dist_portal_12", ":party_no", "p_12"),
################## Getting the xy coordinates of party, target & portals
(party_get_position, pos0, ":party_no"),
(position_get_x, ":party_x", pos0),
(position_get_y, ":party_y", pos0),
(party_get_position, pos1, ":target_center"),
(position_get_x, ":target_x", pos1),
(position_get_y, ":target_y", pos1),
(party_get_position, pos2, "p_1"), #only getting the coordinates from one part of each portal, since they are close together, so similar coordinates
(position_get_x, ":portal_1_x", pos2),
(position_get_y, ":portal_1_y", pos2),
(party_get_position, pos3, "p_3"),
(position_get_x, ":portal_2_x", pos3),
(position_get_y, ":portal_2_y", pos3),
(party_get_position, pos4, "p_5"),
(position_get_x, ":portal_3_x", pos4),
(position_get_y, ":portal_3_y", pos4),
(party_get_position, pos5, "p_7"),
(position_get_x, ":portal_4_x", pos5),
(position_get_y, ":portal_4_y", pos5),
(party_get_position, pos6, "p_9"),
(position_get_x, ":portal_5_x", pos6),
(position_get_y, ":portal_5_y", pos6),
(party_get_position, pos7, "p_11"),
(position_get_x, ":portal_6_x", pos7),
(position_get_y, ":portal_6_y", pos7),
################################ Creating an offset for the xy coordinates defined by party and target, to make the created rectangle larger, i.e. the portal can lay slightly outside and still be considered.
(try_begin), #this sets the lower limit lower and the upper limit higher. Used for the portal range check.
(le, ":party_x", ":target_x"),
(val_sub, ":party_x", 20),          #in m. Ingame it uses cm though.
(val_add, ":target_x", 20), #the portal can be 20m outside of the range of party and target and still be considered for travel.
(else_try),
(val_sub, ":target_x", 20),
(val_add, ":party_x", 20),
(try_end),
(try_begin),
(le, ":party_y", ":target_y"),
(val_sub, ":party_y", 20),
(val_add, ":target_y", 20),
(else_try),
(val_sub, ":target_y", 20),
(val_add, ":party_y", 20),
(try_end),
##############################
(try_begin), #Checking if Portal 1 is inside rectangle
(this_or_next|is_between, ":portal_1_x", ":party_x", ":target_x"),
(is_between, ":portal_1_x", ":target_x", ":party_x"),
(this_or_next|is_between, ":portal_1_y", ":party_y", ":target_y"),
(is_between, ":portal_1_y", ":target_y", ":party_y"),
(assign, ":portal_1_in_range", 1),
(try_end),
(try_begin), #Checking if Portal 2 is inside rectangle
(this_or_next|is_between, ":portal_2_x", ":party_x", ":target_x"),
(is_between, ":portal_2_x", ":target_x", ":party_x"),
(this_or_next|is_between, ":portal_2_y", ":party_y", ":target_y"),
(is_between, ":portal_2_y", ":target_y", ":party_y"),
(assign, ":portal_2_in_range", 1),
(try_end),
(try_begin), #Checking if Portal 3 is inside rectangle
(this_or_next|is_between, ":portal_3_x", ":party_x", ":target_x"),
(is_between, ":portal_3_x", ":target_x", ":party_x"),
(this_or_next|is_between, ":portal_3_y", ":party_y", ":target_y"),
(is_between, ":portal_3_y", ":target_y", ":party_y"),
(assign, ":portal_3_in_range", 1),
(try_end),
(try_begin), #Checking if Portal 4 is inside rectangle
(this_or_next|is_between, ":portal_4_x", ":party_x", ":target_x"),
(is_between, ":portal_4_x", ":target_x", ":party_x"),
(this_or_next|is_between, ":portal_4_y", ":party_y", ":target_y"),
(is_between, ":portal_4_y", ":target_y", ":party_y"),
(assign, ":portal_4_in_range", 1),
(try_end),
(try_begin), #Checking if Portal 5 is inside rectangle
(this_or_next|is_between, ":portal_5_x", ":party_x", ":target_x"),
(is_between, ":portal_5_x", ":target_x", ":party_x"),
(this_or_next|is_between, ":portal_5_y", ":party_y", ":target_y"),
(is_between, ":portal_5_y", ":target_y", ":party_y"),
(assign, ":portal_5_in_range", 1),
(try_end),
(try_begin), #Checking if Portal 6 is inside rectangle
(this_or_next|is_between, ":portal_6_x", ":party_x", ":target_x"),
(is_between, ":portal_6_x", ":target_x", ":party_x"),
(this_or_next|is_between, ":portal_6_y", ":party_y", ":target_y"),
(is_between, ":portal_6_y", ":target_y", ":party_y"),
(assign, ":portal_6_in_range", 1),
(try_end),

####################################### checking whether the party would use a portal only if it is in range
(try_begin), #Would Party use Portal 1?
(eq, ":portal_1_in_range", 1),
(store_faction_of_party, ":faction_party", ":party_no"),
(store_faction_of_party, ":faction_portal", "p_castle_14"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(try_begin),
(eq, ":faction_party", ":faction_portal"),
(assign, ":relation", 100),
(try_end),
(ge, ":relation", 0), #min relation requires to use this portal
(store_distance_to_party_from_party, ":dist_party_target", ":party_no", ":target_center"),
(try_begin),
(le, ":dist_portal_1", ":dist_portal_2"),
(assign, ":dist_party_entry", ":dist_portal_1"), # this makes the closer portal the entry and the other the out
(store_distance_to_party_from_party, ":dist_portal_out_target", "p_2", ":target_center"),
(party_set_slot, "p_1", slot_would_portal_be_used_by_party, ":party_no"),
(else_try),
(assign, ":dist_party_entry", ":dist_portal_2"),
(store_distance_to_party_from_party, ":dist_portal_out_target", "p_1", ":target_center"),
(party_set_slot, "p_2", slot_would_portal_be_used_by_party, ":party_no"),
(try_end),
(assign, ":dist6", ":dist_portal_out_target"),
(assign, ":dist8", ":dist_party_target"),
(val_add, ":dist_portal_out_target", ":dist_party_entry"), #Combine party->portal+portal->target
(try_begin), #This little fella makes units prioritize the portal, if they, or their target is near a portal
(this_or_next|le, ":dist_portal_1", 15),
(le, ":dist6", 15),
(val_mul, ":dist_party_target", 5),
(else_try),
(this_or_next|le, ":dist_portal_1", 30),
(le, ":dist6", 30),
(val_mul, ":dist_party_target", 3),
(else_try),
(this_or_next|le, ":dist_portal_1", 50),
(le, ":dist6", 50),
(val_mul, ":dist_party_target", 1.5),
(else_try),
(this_or_next|le, ":dist_portal_1", 100),
(le, ":dist6", 100),
(val_mul, ":dist_party_target", 1.2),
(else_try),
(val_mul, ":dist_party_target", 1),
(try_end),

(try_begin),
(this_or_next|le, ":dist8", ":dist6"),
(this_or_next|le, ":dist8", ":dist_portal_1"),
(le, ":dist_party_target", ":dist_portal_out_target"), #
(party_set_slot, "p_1", slot_would_portal_be_used_by_party, 0),
(party_set_slot, "p_2", slot_would_portal_be_used_by_party, 0),
(try_end),
(try_end),
##################################################
(try_begin), #Would Party use Portal 2?
(eq, ":portal_2_in_range", 1),
(store_faction_of_party, ":faction_party", ":party_no"),
(store_faction_of_party, ":faction_portal", "p_castle_16"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(try_begin),
(eq, ":faction_party", ":faction_portal"),
(assign, ":relation", 100),
(try_end),
(ge, ":relation", 0), #min relation requires to use this portal
(store_distance_to_party_from_party, ":dist_party_target", ":party_no", ":target_center"),
(try_begin),
(le, ":dist_portal_3", ":dist_portal_4"),
(assign, ":dist_party_entry", ":dist_portal_3"), # this makes the closer portal the entry and the other the out
(store_distance_to_party_from_party, ":dist_portal_out_target", "p_4", ":target_center"),
(party_set_slot, "p_3", slot_would_portal_be_used_by_party, ":party_no"),
(else_try),
(assign, ":dist_party_entry", ":dist_portal_3"),
(store_distance_to_party_from_party, ":dist_portal_out_target", "p_3", ":target_center"),
(party_set_slot, "p_4", slot_would_portal_be_used_by_party, ":party_no"),
(try_end),
(assign, ":dist6", ":dist_portal_out_target"),
(assign, ":dist8", ":dist_party_target"),
(val_add, ":dist_portal_out_target", ":dist_party_entry"), #Combine party->portal+portal->target
(try_begin), #This little fella makes units prioritize the portal, if they, or their target is near a portal
(this_or_next|le, ":dist_portal_3", 15),
(le, ":dist6", 15),
(val_mul, ":dist_party_target", 5),
(else_try),
(this_or_next|le, ":dist_portal_3", 30),
(le, ":dist6", 30),
(val_mul, ":dist_party_target", 3),
(else_try),
(this_or_next|le, ":dist_portal_3", 50),
(le, ":dist6", 50),
(val_mul, ":dist_party_target", 1.5),
(else_try),
(this_or_next|le, ":dist_portal_3", 100),
(le, ":dist6", 100),
(val_mul, ":dist_party_target", 1.2),
(else_try),
(val_mul, ":dist_party_target", 1),
(try_end),

(try_begin),
(this_or_next|le, ":dist8", ":dist6"),
(this_or_next|le, ":dist8", ":dist_portal_3"),
(le, ":dist_party_target", ":dist_portal_out_target"),
(party_set_slot, "p_3", slot_would_portal_be_used_by_party, 0),
(party_set_slot, "p_4", slot_would_portal_be_used_by_party, 0),
(try_end),
(try_end),
########################
(try_begin), #Would Party use Portal 3?
(eq, ":portal_3_in_range", 1),
(store_faction_of_party, ":faction_party", ":party_no"),
(store_faction_of_party, ":faction_portal", "p_castle_29"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(try_begin),
(eq, ":faction_party", ":faction_portal"),
(assign, ":relation", 100),
(try_end),
(ge, ":relation", 0), #min relation requires to use this portal
(store_distance_to_party_from_party, ":dist_party_target", ":party_no", ":target_center"),
(try_begin),
(le, ":dist_portal_5", ":dist_portal_6"),
(assign, ":dist_party_entry", ":dist_portal_5"), # this makes the closer portal the entry and the other the out
(store_distance_to_party_from_party, ":dist_portal_out_target", "p_6", ":target_center"),
(party_set_slot, "p_5", slot_would_portal_be_used_by_party, ":party_no"),
(else_try),
(assign, ":dist_party_entry", ":dist_portal_6"),
(store_distance_to_party_from_party, ":dist_portal_out_target", "p_5", ":target_center"),
(party_set_slot, "p_6", slot_would_portal_be_used_by_party, ":party_no"),
(try_end),
(assign, ":dist6", ":dist_portal_out_target"),
(assign, ":dist8", ":dist_party_target"),
(val_add, ":dist_portal_out_target", ":dist_party_entry"), #Combine party->portal+portal->target
(try_begin), #This little fella makes units prioritize the portal, if they, or their target is near a portal
(this_or_next|le, ":dist_portal_5", 15),
(le, ":dist6", 15),
(val_mul, ":dist_party_target", 5),
(else_try),
(this_or_next|le, ":dist_portal_5", 30),
(le, ":dist6", 30),
(val_mul, ":dist_party_target", 3),
(else_try),
(this_or_next|le, ":dist_portal_5", 50),
(le, ":dist6", 50),
(val_mul, ":dist_party_target", 1.5),
(else_try),
(this_or_next|le, ":dist_portal_5", 100),
(le, ":dist6", 100),
(val_mul, ":dist_party_target", 1.2),
(else_try),
(val_mul, ":dist_party_target", 1),
(try_end),

(try_begin),
(this_or_next|le, ":dist8", ":dist6"),
(this_or_next|le, ":dist8", ":dist_portal_5"),
(le, ":dist_party_target", ":dist_portal_out_target"), #
(party_set_slot, "p_5", slot_would_portal_be_used_by_party, 0),
(party_set_slot, "p_6", slot_would_portal_be_used_by_party, 0),
(try_end),
(try_end),
########################
(try_begin), #Would Party use Portal 4?
(eq, ":portal_4_in_range", 1),
(store_faction_of_party, ":faction_party", ":party_no"),
(store_faction_of_party, ":faction_portal", "p_castle_7"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(try_begin),
(eq, ":faction_party", ":faction_portal"),
(assign, ":relation", 100),
(try_end),
(ge, ":relation", 0), #min relation requires to use this portal
(store_distance_to_party_from_party, ":dist_party_target", ":party_no", ":target_center"),
(try_begin),
(le, ":dist_portal_7", ":dist_portal_8"),
(assign, ":dist_party_entry", ":dist_portal_7"), # this makes the closer portal the entry and the other the out
(store_distance_to_party_from_party, ":dist_portal_out_target", "p_8", ":target_center"),
(party_set_slot, "p_7", slot_would_portal_be_used_by_party, ":party_no"),
(else_try),
(assign, ":dist_party_entry", ":dist_portal_8"),
(store_distance_to_party_from_party, ":dist_portal_out_target", "p_7", ":target_center"),
(party_set_slot, "p_8", slot_would_portal_be_used_by_party, ":party_no"),
(try_end),
(assign, ":dist6", ":dist_portal_out_target"),
(assign, ":dist8", ":dist_party_target"),
(val_add, ":dist_portal_out_target", ":dist_party_entry"), #Combine party->portal+portal->target
(try_begin), #This little fella makes units prioritize the portal, if they, or their target is near a portal
(this_or_next|le, ":dist_portal_7", 15),
(le, ":dist6", 15),
(val_mul, ":dist_party_target", 5),
(else_try),
(this_or_next|le, ":dist_portal_7", 30),
(le, ":dist6", 30),
(val_mul, ":dist_party_target", 3),
(else_try),
(this_or_next|le, ":dist_portal_7", 50),
(le, ":dist6", 50),
(val_mul, ":dist_party_target", 1.5),
(else_try),
(this_or_next|le, ":dist_portal_7", 100),
(le, ":dist6", 100),
(val_mul, ":dist_party_target", 1.2),
(else_try),
(val_mul, ":dist_party_target", 1),
(try_end),

(try_begin),
(this_or_next|le, ":dist8", ":dist6"),
(this_or_next|le, ":dist8", ":dist_portal_7"),
(le, ":dist_party_target", ":dist_portal_out_target"), #
(party_set_slot, "p_7", slot_would_portal_be_used_by_party, 0),
(party_set_slot, "p_8", slot_would_portal_be_used_by_party, 0),
(try_end),
(try_end),
########################
(try_begin), #Would Party use Portal 5?
(eq, ":portal_5_in_range", 1),
(store_faction_of_party, ":faction_party", ":party_no"),
(store_faction_of_party, ":faction_portal", "p_castle_1"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(try_begin),
(eq, ":faction_party", ":faction_portal"),
(assign, ":relation", 100),
(try_end),
(ge, ":relation", 0), #min relation requires to use this portal
(store_distance_to_party_from_party, ":dist_party_target", ":party_no", ":target_center"),
(try_begin),
(le, ":dist_portal_9", ":dist_portal_10"),
(assign, ":dist_party_entry", ":dist_portal_9"), # this makes the closer portal the entry and the other the out
(store_distance_to_party_from_party, ":dist_portal_out_target", "p_10", ":target_center"),
(party_set_slot, "p_9", slot_would_portal_be_used_by_party, ":party_no"),
(else_try),
(assign, ":dist_party_entry", ":dist_portal_10"),
(store_distance_to_party_from_party, ":dist_portal_out_target", "p_9", ":target_center"),
(party_set_slot, "p_10", slot_would_portal_be_used_by_party, ":party_no"),
(try_end),
(assign, ":dist6", ":dist_portal_out_target"),
(assign, ":dist8", ":dist_party_target"),
(val_add, ":dist_portal_out_target", ":dist_party_entry"), #Combine party->portal+portal->target
(try_begin), #This little fella makes units prioritize the portal, if they, or their target is near a portal
(this_or_next|le, ":dist_portal_9", 15),
(le, ":dist6", 15),
(val_mul, ":dist_party_target", 5),
(else_try),
(this_or_next|le, ":dist_portal_9", 30),
(le, ":dist6", 30),
(val_mul, ":dist_party_target", 3),
(else_try),
(this_or_next|le, ":dist_portal_9", 50),
(le, ":dist6", 50),
(val_mul, ":dist_party_target", 1.5),
(else_try),
(this_or_next|le, ":dist_portal_9", 100),
(le, ":dist6", 100),
(val_mul, ":dist_party_target", 1.2),
(else_try),
(val_mul, ":dist_party_target", 1),
(try_end),

(try_begin),
(this_or_next|le, ":dist8", ":dist6"),
(this_or_next|le, ":dist8", ":dist_portal_9"),
(le, ":dist_party_target", ":dist_portal_out_target"), #
(party_set_slot, "p_9", slot_would_portal_be_used_by_party, 0),
(party_set_slot, "p_10", slot_would_portal_be_used_by_party, 0),
(try_end),
(try_end),
########################
(try_begin), #Would Party use Portal 6?
(eq, ":portal_6_in_range", 1),
(store_faction_of_party, ":faction_party", ":party_no"),
(store_faction_of_party, ":faction_portal", "p_castle_33"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(try_begin),
(eq, ":faction_party", ":faction_portal"),
(assign, ":relation", 100),
(try_end),
(ge, ":relation", 0), #min relation requires to use this portal
(store_distance_to_party_from_party, ":dist_party_target", ":party_no", ":target_center"),
(try_begin),
(le, ":dist_portal_11", ":dist_portal_12"),
(assign, ":dist_party_entry", ":dist_portal_11"), # this makes the closer portal the entry and the other the out
(store_distance_to_party_from_party, ":dist_portal_out_target", "p_12", ":target_center"),
(party_set_slot, "p_11", slot_would_portal_be_used_by_party, ":party_no"),
(else_try),
(assign, ":dist_party_entry", ":dist_portal_12"),
(store_distance_to_party_from_party, ":dist_portal_out_target", "p_11", ":target_center"),
(party_set_slot, "p_12", slot_would_portal_be_used_by_party, ":party_no"),
(try_end),
(assign, ":dist6", ":dist_portal_out_target"),
(assign, ":dist8", ":dist_party_target"),
(val_add, ":dist_portal_out_target", ":dist_party_entry"), #Combine: party->portal + portal->target
(try_begin), #This little fella makes units prioritize the portal, if they, or their target is near a portal
(this_or_next|le, ":dist_portal_11", 15),
(le, ":dist6", 15),
(val_mul, ":dist_party_target", 5),
(else_try),
(this_or_next|le, ":dist_portal_11", 30),
(le, ":dist6", 30),
(val_mul, ":dist_party_target", 3),
(else_try),
(this_or_next|le, ":dist_portal_11", 50),
(le, ":dist6", 50),
(val_mul, ":dist_party_target", 1.5),
(else_try),
(this_or_next|le, ":dist_portal_11", 100),
(le, ":dist6", 100),
(val_mul, ":dist_party_target", 1.2),
(else_try),
(val_mul, ":dist_party_target", 1),
(try_end),

(try_begin),
(this_or_next|le, ":dist8", ":dist6"),
(this_or_next|le, ":dist8", ":dist_portal_11"),
(le, ":dist_party_target", ":dist_portal_out_target"), #
(party_set_slot, "p_11", slot_would_portal_be_used_by_party, 0),
(party_set_slot, "p_12", slot_would_portal_be_used_by_party, 0),
(try_end),
(try_end),
###################################################################
########## Calculating which if any of the portals that the party would use is closest
(assign, ":closest_portal", 999999),
(try_for_range, ":portal", "p_1", "p_spawn_points_end"),
(party_slot_eq, ":portal", slot_would_portal_be_used_by_party, ":party_no"),
(store_distance_to_party_from_party, ":distance", ":party_no", ":portal"),
(lt, ":distance", ":closest_portal"),
(assign, ":closest_portal", ":portal"),
(try_end),
###########calc closest portal end

##################################### This checks, which portal entry has been assigned as the closest portal and then tells the party to move there.
(try_begin), #larger loop to assign slot_party_destination once at the end
(try_begin),
(eq, ":closest_portal", "p_1"),
(assign, ":target_portal", "p_1"),
(party_set_slot, ":party_no", slot_portal_using, 1),
(else_try),
(eq, ":closest_portal", "p_2"),
(assign, ":target_portal", "p_2"),
(party_set_slot, ":party_no", slot_portal_using, 2),
(else_try),
(eq, ":closest_portal", "p_3"),
(assign, ":target_portal", "p_3"),
(party_set_slot, ":party_no", slot_portal_using, 3),
(else_try),
(eq, ":closest_portal", "p_4"),
(assign, ":target_portal", "p_4"),
(party_set_slot, ":party_no", slot_portal_using, 4),
(else_try),
(eq, ":closest_portal", "p_5"),
(assign, ":target_portal", "p_5"),
(party_set_slot, ":party_no", slot_portal_using, 5),
(else_try),
(eq, ":closest_portal", "p_6"),
(assign, ":target_portal", "p_6"),
(party_set_slot, ":party_no", slot_portal_using, 6),
(else_try),
(eq, ":closest_portal", "p_7"),
(assign, ":target_portal", "p_7"),
(party_set_slot, ":party_no", slot_portal_using, 7),
(else_try),
(eq, ":closest_portal", "p_8"),
(assign, ":target_portal", "p_8"),
(party_set_slot, ":party_no", slot_portal_using, :cool:,
(else_try),
(eq, ":closest_portal", "p_9"),
(assign, ":target_portal", "p_9"),
(party_set_slot, ":party_no", slot_portal_using, 9),
(else_try),
(eq, ":closest_portal", "p_10"),
(assign, ":target_portal", "p_10"),
(party_set_slot, ":party_no", slot_portal_using, 10),
(else_try),
(eq, ":closest_portal", "p_11"),
(assign, ":target_portal", "p_11"),
(party_set_slot, ":party_no", slot_portal_using, 11),
(else_try),
(eq, ":closest_portal", "p_12"),
(assign, ":target_portal", "p_12"),
(party_set_slot, ":party_no", slot_portal_using, 12),
(else_try),
(assign, ":target_portal", ":target_center"), #safety
(try_for_range, ":portal", "p_1", "p_spawn_points_end"),
(party_set_slot, ":portal", slot_would_portal_be_used_by_party, 0),
(try_end),
(try_end),
(party_set_slot, ":party_no", slot_party_destination, ":target_center"),
(party_set_ai_object, ":party_no", ":target_portal"),
(try_end),
]),
 

Fire_and_Blood

Knight at Arms
Part 2:
Module_simple_triggers:
Place these anywhere in simple_triggers. These triggers teleport a unit from one portal to the other and send them on their way to their original destination. The last trigger is a bug workaround, if lords get stuck on mountain terrain, that trigger will relocate them to the nearest portal.
#F&B begin relocate party to other portal
#for portal 1
(0.5,
[(try_for_parties, ":party_no"),
(party_slot_eq, ":party_no", slot_portal_using, 1),
(store_distance_to_party_from_party, ":cur_distance", "p_1", ":party_no"),
(neq, ":party_no", "p_1"),   
(le, ":cur_distance", 0),
(try_begin),
(store_faction_of_party, ":faction_party", ":party_no"), #This is another relation check, in case the castle has been taken by another faction.
(store_faction_of_party, ":faction_portal", "p_castle_14"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(ge, ":relation", 0), #min relation requires to use this portal
(party_relocate_near_party, ":party_no", "p_2",0),
(try_end),
(party_get_slot, ":target_center", ":party_no", slot_party_destination),
(party_set_ai_behavior, ":party_no", ai_bhvr_travel_to_party),
(party_set_ai_object, ":party_no", ":target_center"),
(party_set_slot, ":party_no", slot_party_ai_object, ":target_center"),
(party_set_slot, ":party_no", slot_party_destination, 0),
(party_set_slot, ":party_no", slot_portal_using, 0),
(try_end)]),
#for portal 2
(0.5,
[(try_for_parties, ":party_no"),
(party_slot_eq, ":party_no", slot_portal_using, 2),
(store_distance_to_party_from_party, ":cur_distance", "p_2", ":party_no"),
(neq, ":party_no", "p_2"),   
(le, ":cur_distance", 0),
(try_begin),
(store_faction_of_party, ":faction_party", ":party_no"), #This is another relation check, in case the castle has been taken by another faction.
(store_faction_of_party, ":faction_portal", "p_castle_14"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(ge, ":relation", 0), #min relation requires to use this portal
(party_relocate_near_party, ":party_no", "p_1",0),
(try_end),
(party_get_slot, ":target_center", ":party_no", slot_party_destination),
(party_set_ai_behavior, ":party_no", ai_bhvr_travel_to_party),
(party_set_ai_object, ":party_no", ":target_center"),
(party_set_slot, ":party_no", slot_party_ai_object, ":target_center"),
(party_set_slot, ":party_no", slot_party_destination, 0),
(party_set_slot, ":party_no", slot_portal_using, 0),
(try_end)]),
#for portal 3
(0.5,
[(try_for_parties, ":party_no"),
(party_slot_eq, ":party_no", slot_portal_using, 3),
(store_distance_to_party_from_party, ":cur_distance", "p_3", ":party_no"),
(neq, ":party_no", "p_3"),   
(le, ":cur_distance", 0),
(try_begin),
(store_faction_of_party, ":faction_party", ":party_no"), #This is another relation check, in case the castle has been taken by another faction.
(store_faction_of_party, ":faction_portal", "p_castle_16"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(ge, ":relation", 0), #min relation requires to use this portal
(party_relocate_near_party, ":party_no", "p_4",0),
(try_end),
(party_get_slot, ":target_center", ":party_no", slot_party_destination),
(party_set_ai_behavior, ":party_no", ai_bhvr_travel_to_party),
(party_set_ai_object, ":party_no", ":target_center"),
(party_set_slot, ":party_no", slot_party_ai_object, ":target_center"),
(party_set_slot, ":party_no", slot_party_destination, 0),
(party_set_slot, ":party_no", slot_portal_using, 0),
(try_end)]),
#for portal 4
(0.5,
[(try_for_parties, ":party_no"),
(party_slot_eq, ":party_no", slot_portal_using, 4),
(store_distance_to_party_from_party, ":cur_distance", "p_4", ":party_no"),
(neq, ":party_no", "p_4"),   
(le, ":cur_distance", 0),
(try_begin),
(store_faction_of_party, ":faction_party", ":party_no"), #This is another relation check, in case the castle has been taken by another faction.
(store_faction_of_party, ":faction_portal", "p_castle_16"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(ge, ":relation", 0), #min relation requires to use this portal
(party_relocate_near_party, ":party_no", "p_3",0),
(try_end),
(party_get_slot, ":target_center", ":party_no", slot_party_destination),
(party_set_ai_behavior, ":party_no", ai_bhvr_travel_to_party),
(party_set_ai_object, ":party_no", ":target_center"),
(party_set_slot, ":party_no", slot_party_ai_object, ":target_center"),
(party_set_slot, ":party_no", slot_party_destination, 0),
(party_set_slot, ":party_no", slot_portal_using, 0),
(try_end)]),
#for portal 5
(0.5,
[(try_for_parties, ":party_no"),
(party_slot_eq, ":party_no", slot_portal_using, 5),
(store_distance_to_party_from_party, ":cur_distance", "p_5", ":party_no"),
(neq, ":party_no", "p_5"),   
(le, ":cur_distance", 0),
(try_begin),
(store_faction_of_party, ":faction_party", ":party_no"), #This is another relation check, in case the castle has been taken by another faction.
(store_faction_of_party, ":faction_portal", "p_castle_29"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(ge, ":relation", 0), #min relation requires to use this portal
(party_relocate_near_party, ":party_no", "p_6",0),
(try_end),
(party_get_slot, ":target_center", ":party_no", slot_party_destination),
(party_set_ai_behavior, ":party_no", ai_bhvr_travel_to_party),
(party_set_ai_object, ":party_no", ":target_center"),
(party_set_slot, ":party_no", slot_party_ai_object, ":target_center"),
(party_set_slot, ":party_no", slot_party_destination, 0),
(party_set_slot, ":party_no", slot_portal_using, 0),
(try_end)]),
#for portal 6
(0.5,
[(try_for_parties, ":party_no"),
(party_slot_eq, ":party_no", slot_portal_using, 6),
(store_distance_to_party_from_party, ":cur_distance", "p_6", ":party_no"),
(neq, ":party_no", "p_6"),   
(le, ":cur_distance", 0),
(try_begin),
(store_faction_of_party, ":faction_party", ":party_no"), #This is another relation check, in case the castle has been taken by another faction.
(store_faction_of_party, ":faction_portal", "p_castle_29"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(ge, ":relation", 0), #min relation requires to use this portal
(party_relocate_near_party, ":party_no", "p_5",0),
(try_end),
(party_get_slot, ":target_center", ":party_no", slot_party_destination),
(party_set_ai_behavior, ":party_no", ai_bhvr_travel_to_party),
(party_set_ai_object, ":party_no", ":target_center"),
(party_set_slot, ":party_no", slot_party_ai_object, ":target_center"),
(party_set_slot, ":party_no", slot_party_destination, 0),
(party_set_slot, ":party_no", slot_portal_using, 0),
(try_end)]),
#for portal 7
(0.5,
[(try_for_parties, ":party_no"),
(party_slot_eq, ":party_no", slot_portal_using, 7),
(store_distance_to_party_from_party, ":cur_distance", "p_7", ":party_no"),
(neq, ":party_no", "p_7"),   
(le, ":cur_distance", 0),
(try_begin),
(store_faction_of_party, ":faction_party", ":party_no"), #This is another relation check, in case the castle has been taken by another faction.
(store_faction_of_party, ":faction_portal", "p_castle_7"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(ge, ":relation", 0), #min relation requires to use this portal
(party_relocate_near_party, ":party_no", "p_8",0),
(try_end),
(party_get_slot, ":target_center", ":party_no", slot_party_destination),
(party_set_ai_behavior, ":party_no", ai_bhvr_travel_to_party),
(party_set_ai_object, ":party_no", ":target_center"),
(party_set_slot, ":party_no", slot_party_ai_object, ":target_center"),
(party_set_slot, ":party_no", slot_party_destination, 0),
(party_set_slot, ":party_no", slot_portal_using, 0),
(try_end)]),
#for portal 8
(0.5,
[(try_for_parties, ":party_no"),
(party_slot_eq, ":party_no", slot_portal_using, :cool:,
(store_distance_to_party_from_party, ":cur_distance", "p_8", ":party_no"),
(neq, ":party_no", "p_8"),   
(le, ":cur_distance", 0),
(try_begin),
(store_faction_of_party, ":faction_party", ":party_no"), #This is another relation check, in case the castle has been taken by another faction.
(store_faction_of_party, ":faction_portal", "p_castle_7"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(ge, ":relation", 0), #min relation requires to use this portal
(party_relocate_near_party, ":party_no", "p_7",0),
(try_end),
(party_get_slot, ":target_center", ":party_no", slot_party_destination),
(party_set_ai_behavior, ":party_no", ai_bhvr_travel_to_party),
(party_set_ai_object, ":party_no", ":target_center"),
(party_set_slot, ":party_no", slot_party_ai_object, ":target_center"),
(party_set_slot, ":party_no", slot_party_destination, 0),
(party_set_slot, ":party_no", slot_portal_using, 0),
(try_end)]),
#for portal 9
(0.5,
[(try_for_parties, ":party_no"),
(party_slot_eq, ":party_no", slot_portal_using, 9),
(store_distance_to_party_from_party, ":cur_distance", "p_9", ":party_no"),
(neq, ":party_no", "p_9"),   
(le, ":cur_distance", 0),
(try_begin),
(store_faction_of_party, ":faction_party", ":party_no"), #This is another relation check, in case the castle has been taken by another faction.
(store_faction_of_party, ":faction_portal", "p_castle_1"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(ge, ":relation", 0), #min relation requires to use this portal
(party_relocate_near_party, ":party_no", "p_10",0),
(try_end),
(party_get_slot, ":target_center", ":party_no", slot_party_destination),
(party_set_ai_behavior, ":party_no", ai_bhvr_travel_to_party),
(party_set_ai_object, ":party_no", ":target_center"),
(party_set_slot, ":party_no", slot_party_ai_object, ":target_center"),
(party_set_slot, ":party_no", slot_party_destination, 0),
(party_set_slot, ":party_no", slot_portal_using, 0),
(try_end)]),
#for portal 10
(0.5,
[(try_for_parties, ":party_no"),
(party_slot_eq, ":party_no", slot_portal_using, 10),
(store_distance_to_party_from_party, ":cur_distance", "p_10", ":party_no"),
(neq, ":party_no", "p_10"),   
(le, ":cur_distance", 0),
(try_begin),
(store_faction_of_party, ":faction_party", ":party_no"), #This is another relation check, in case the castle has been taken by another faction.
(store_faction_of_party, ":faction_portal", "p_castle_1"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(ge, ":relation", 0), #min relation requires to use this portal
(party_relocate_near_party, ":party_no", "p_9",0),
(try_end),
(party_get_slot, ":target_center", ":party_no", slot_party_destination),
(party_set_ai_behavior, ":party_no", ai_bhvr_travel_to_party),
(party_set_ai_object, ":party_no", ":target_center"),
(party_set_slot, ":party_no", slot_party_ai_object, ":target_center"),
(party_set_slot, ":party_no", slot_party_destination, 0),
(party_set_slot, ":party_no", slot_portal_using, 0),
(try_end)]),
#for portal 11
(0.5,
[(try_for_parties, ":party_no"),
(party_slot_eq, ":party_no", slot_portal_using, 11),
(store_distance_to_party_from_party, ":cur_distance", "p_11", ":party_no"),
(neq, ":party_no", "p_11"),   
(le, ":cur_distance", 0),
(try_begin),
(store_faction_of_party, ":faction_party", ":party_no"), #This is another relation check, in case the castle has been taken by another faction.
(store_faction_of_party, ":faction_portal", "p_castle_33"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(ge, ":relation", 0), #min relation requires to use this portal
(party_relocate_near_party, ":party_no", "p_12",0),
(try_end),
(party_get_slot, ":target_center", ":party_no", slot_party_destination),
(party_set_ai_behavior, ":party_no", ai_bhvr_travel_to_party),
(party_set_ai_object, ":party_no", ":target_center"),
(party_set_slot, ":party_no", slot_party_ai_object, ":target_center"),
(party_set_slot, ":party_no", slot_party_destination, 0),
(party_set_slot, ":party_no", slot_portal_using, 0),
(try_end)]),
#for portal 12
(0.5,
[(try_for_parties, ":party_no"),
(party_slot_eq, ":party_no", slot_portal_using, 12),
(store_distance_to_party_from_party, ":cur_distance", "p_12", ":party_no"),
(neq, ":party_no", "p_12"),   
(le, ":cur_distance", 0),
(try_begin),
(store_faction_of_party, ":faction_party", ":party_no"), #This is another relation check, in case the castle has been taken by another faction.
(store_faction_of_party, ":faction_portal", "p_castle_33"),
(store_relation, ":relation", ":faction_party", ":faction_portal"),
(ge, ":relation", 0), #min relation requires to use this portal
(party_relocate_near_party, ":party_no", "p_11",0),
(try_end),
(party_get_slot, ":target_center", ":party_no", slot_party_destination),
(party_set_ai_behavior, ":party_no", ai_bhvr_travel_to_party),
(party_set_ai_object, ":party_no", ":target_center"),
(party_set_slot, ":party_no", slot_party_ai_object, ":target_center"),
(party_set_slot, ":party_no", slot_party_destination, 0),
(party_set_slot, ":party_no", slot_portal_using, 0),
(try_end)]),

######### Trigger to unstuck detached lords

(0.5, #This trigger unstucks parties stuck on mountain
[(try_for_parties, ":party_no"),
(neg|party_slot_eq, ":party_no", slot_party_type, spt_castle),
(party_get_current_terrain, ":cur_terrain", ":party_no"),
(eq, ":cur_terrain", 1),
(try_begin),
(store_distance_to_party_from_party, ":dist", ":party_no", "p_castle_14"),
(le, ":dist", 1),
(party_relocate_near_party, ":party_no", "p_1"),
(party_set_slot, ":party_no", slot_detached_from_center, 0),
(else_try),
(store_distance_to_party_from_party, ":dist", ":party_no", "p_castle_16"),
(le, ":dist", 1),
(party_relocate_near_party, ":party_no", "p_3"),
(party_set_slot, ":party_no", slot_detached_from_center, 0),
(else_try),
(store_distance_to_party_from_party, ":dist", ":party_no", "p_castle_29"),
(le, ":dist", 1),
(party_relocate_near_party, ":party_no", "p_5"),
(party_set_slot, ":party_no", slot_detached_from_center, 0),
(else_try),
(store_distance_to_party_from_party, ":dist", ":party_no", "p_castle_7"),
(le, ":dist", 1),
(party_relocate_near_party, ":party_no", "p_7"),
(party_set_slot, ":party_no", slot_detached_from_center, 0),
(else_try),
(store_distance_to_party_from_party, ":dist", ":party_no", "p_castle_1"),
(le, ":dist", 1),
(party_relocate_near_party, ":party_no", "p_9"),
(party_set_slot, ":party_no", slot_detached_from_center, 0),
(else_try),
(store_distance_to_party_from_party, ":dist", ":party_no", "p_castle_33"),
(le, ":dist", 1),
(party_relocate_near_party, ":party_no", "p_11"),
(party_set_slot, ":party_no", slot_detached_from_center, 0),
(try_end),
(try_end)]),

Module_game_menus:
This adds a menu option to each of the 6 castles, which lets the player travel to the other side, ofc. only if he has no negative relation with the faction holding the castle.
Part 1: Search for "town_sneak” and place these lines above it.
#F&B begin
("portal", [(eq, "$current_town", "p_castle_14"),
(str_store_party_name, s2, "$current_town"),], # (Maras Castle)
"Attempt to cross {s2}",
[(store_faction_of_party, ":faction_party", "p_main_party"),
(store_faction_of_party, ":faction_portal_1", "p_castle_14"), #getting faction of current Castle.
(store_relation, ":relation", ":faction_party", ":faction_portal_1"),
(try_begin),
(ge, ":relation", 0),
(jump_to_menu, "mnu_use_portal_1"),
(else_try),
(str_store_faction_name, s0, ":faction_portal_1"),
(jump_to_menu, "mnu_portal_hostile"),
(try_end),
]),
("portal_2", [(eq, "$current_town", "p_castle_16"),
  (str_store_party_name, s2, "$current_town"),], #Almerra
"Attempt to cross {s2}",
[(store_faction_of_party, ":faction_party", "p_main_party"),
(store_faction_of_party, ":faction_portal_2", "p_castle_16"), #getting faction of current Castle.
(store_relation, ":relation", ":faction_party", ":faction_portal_2"),
(try_begin),
(ge, ":relation", 0),
(store_distance_to_party_from_party, "$g_dist_1", "p_main_party", "p_3"),
(store_distance_to_party_from_party, "$g_dist_2", "p_main_party", "p_4"),
(jump_to_menu, "mnu_use_portal_2"),
(else_try),
(str_store_faction_name, s0, ":faction_portal_2"),
(jump_to_menu, "mnu_portal_hostile"),
(try_end),
]),
("portal_3", [(eq, "$current_town", "p_castle_29"),
    (str_store_party_name, s2, "$current_town"),], #Nelag
"Attempt to cross {s2}",
[(store_faction_of_party, ":faction_party", "p_main_party"),
(store_faction_of_party, ":faction_portal_3", "p_castle_29"), #getting faction of current Castle.
(store_relation, ":relation", ":faction_party", ":faction_portal_3"),
(try_begin),
(ge, ":relation", 0),
(store_distance_to_party_from_party, "$g_dist_1", "p_main_party", "p_5"),
(store_distance_to_party_from_party, "$g_dist_2", "p_main_party", "p_6"),
(jump_to_menu, "mnu_use_portal_3"),
(else_try),
(str_store_faction_name, s0, ":faction_portal_3"),
(jump_to_menu, "mnu_portal_hostile"),
(try_end)]),
("portal_4", [(eq, "$current_town", "p_castle_7"),
  (str_store_party_name, s2, "$current_town"),], #Sungetche
"Attempt to cross {s2}",
[(store_faction_of_party, ":faction_party", "p_main_party"),
(store_faction_of_party, ":faction_portal_4", "p_castle_7"), #getting faction of current Castle.
(store_relation, ":relation", ":faction_party", ":faction_portal_4"),
(try_begin),
(ge, ":relation", 0),
(store_distance_to_party_from_party, "$g_dist_1", "p_main_party", "p_7"),
(store_distance_to_party_from_party, "$g_dist_2", "p_main_party", "p_8"),
(jump_to_menu, "mnu_use_portal_4"),
(else_try),
(str_store_faction_name, s0, ":faction_portal_4"),
(jump_to_menu, "mnu_portal_hostile"),
(try_end)
]),
("portal_5", [(eq, "$current_town", "p_castle_1"),
  (str_store_party_name, s2, "$current_town"),], #Culmarr
"Attempt to cross {s2}",
[(store_faction_of_party, ":faction_party", "p_main_party"),
(store_faction_of_party, ":faction_portal_5", "p_castle_1"), #getting faction of current Castle.
(store_relation, ":relation", ":faction_party", ":faction_portal_5"),
(try_begin),
(ge, ":relation", 0),
(store_distance_to_party_from_party, "$g_dist_1", "p_main_party", "p_9"),
(store_distance_to_party_from_party, "$g_dist_2", "p_main_party", "p_10"),
(jump_to_menu, "mnu_use_portal_5"),
(else_try),
(str_store_faction_name, s0, ":faction_portal_5"),
(jump_to_menu, "mnu_portal_hostile"),
(try_end)
]),
("portal_6", [(eq, "$current_town", "p_castle_33"),
  (str_store_party_name, s2, "$current_town"),], #Etrosq
"Attempt to cross {s2}",
[(store_faction_of_party, ":faction_party", "p_main_party"),
(store_faction_of_party, ":faction_portal_6", "p_castle_33"), #getting faction of current Castle.
(store_relation, ":relation", ":faction_party", ":faction_portal_6"),
(try_begin),
(ge, ":relation", 0), #min relation to cross
(store_distance_to_party_from_party, "$g_dist_1", "p_main_party", "p_11"),
(store_distance_to_party_from_party, "$g_dist_2", "p_main_party", "p_12"),
(jump_to_menu, "mnu_use_portal_6"),
(else_try),
(str_store_faction_name, s0, ":faction_portal_6"),
(jump_to_menu, "mnu_portal_hostile"),
(try_end),]),
#F&B end
Part 2: Search for (“join_tournament” and place the following above it
#F&B begin
("portal_1", [
(eq, "$current_town", "p_castle_14"),  #only show this menu at Portal 1 (Maras Castle)
(store_faction_of_party, ":faction_party", "p_main_party"),
(store_faction_of_party, ":faction_portal_1", "p_castle_14"), #getting faction of portaled Castle.
(store_relation, ":relation", ":faction_party", ":faction_portal_1"),
(ge, ":relation", 0) #min relation to cross
],
"Cross fortress",
[(jump_to_menu, "mnu_use_portal_1")]),
("portal_2", [
(eq, "$current_town", "p_castle_16"),  #Almerra
(store_faction_of_party, ":faction_party", "p_main_party"),
(store_faction_of_party, ":faction_portal_2", "p_castle_16"), #getting faction of portaled Castle.
(store_relation, ":relation", ":faction_party", ":faction_portal_2"),
(ge, ":relation", 0) #min relation to cross
],
"Cross fortress",
[(jump_to_menu, "mnu_use_portal_2")]),
("portal_3", [
(eq, "$current_town", "p_castle_29"),  #Nelag
(store_faction_of_party, ":faction_party", "p_main_party"),
(store_faction_of_party, ":faction_portal_3", "p_castle_29"), #getting faction of portaled Castle.
(store_relation, ":relation", ":faction_party", ":faction_portal_3"),
(ge, ":relation", 0) #min relation to cross
],
"Cross fortress",
[(jump_to_menu, "mnu_use_portal_3")]),
("portal_4", [
(eq, "$current_town", "p_castle_7"),  #Sungetche
(store_faction_of_party, ":faction_party", "p_main_party"),
(store_faction_of_party, ":faction_portal_4", "p_castle_7"), #getting faction of portaled Castle.
(store_relation, ":relation", ":faction_party", ":faction_portal_4"),
(ge, ":relation", 0) #min relation to cross
],
"Cross fortress",
[(jump_to_menu, "mnu_use_portal_4")]),
("portal_5", [
(eq, "$current_town", "p_castle_1"),  #Culmarr
(store_faction_of_party, ":faction_party", "p_main_party"),
(store_faction_of_party, ":faction_portal_5", "p_castle_1"), #getting faction of portaled Castle.
(store_relation, ":relation", ":faction_party", ":faction_portal_5"),
(ge, ":relation", 0) #min relation to cross
],
"Cross fortress",
[(jump_to_menu, "mnu_use_portal_5")]),
("portal_6", [
(eq, "$current_town", "p_castle_33"),  #Etrosq
(store_faction_of_party, ":faction_party", "p_main_party"),
(store_faction_of_party, ":faction_portal_6", "p_castle_33"), #getting faction of portaled Castle.
(store_relation, ":relation", ":faction_party", ":faction_portal_6"),
(ge, ":relation", 0) #min relation to cross
],
"Cross fortress",
[(jump_to_menu, "mnu_use_portal_6")]),
#F&B end
Part 3: Add this anywhere, I placed it at the end of game_menus
  #F&B begin
  ("use_portal_1", 0, "The guards of {s2} let you through.", "none",
[(store_distance_to_party_from_party, "$g_dist_1", "p_main_party", "p_1"),
(store_distance_to_party_from_party, "$g_dist_2", "p_main_party", "p_2"),],
[
("use_portal", [], "Cross {s2}", [
(leave_encounter),
(try_begin),
(lt, "$g_dist_1", "$g_dist_2"),
(party_relocate_near_party, "p_main_party", "p_2"),
(else_try),
(party_relocate_near_party, "p_main_party", "p_1"),
(try_end),]),
("leave",[],"Stay on this side of {s2}.",[(change_screen_return)]),
]),
  ("use_portal_2", 0, "The guards of {s2} let you through.", "none",
[(store_distance_to_party_from_party, "$g_dist_1", "p_main_party", "p_3"),
(store_distance_to_party_from_party, "$g_dist_2", "p_main_party", "p_4"),],
[
("use_portal", [], "Cross {s2}", [
(leave_encounter),
(try_begin),
(lt, "$g_dist_1", "$g_dist_2"),
(party_relocate_near_party, "p_main_party", "p_4"),
(else_try),
(party_relocate_near_party, "p_main_party", "p_3"),
(try_end),]),
("leave",[],"Stay on this side of {s2}.",[(change_screen_return)]),
]),
  ("use_portal_3", 0, "The guards of {s2} let you through.", "none",
[(store_distance_to_party_from_party, "$g_dist_1", "p_main_party", "p_5"),
(store_distance_to_party_from_party, "$g_dist_2", "p_main_party", "p_6"),],
[
("use_portal", [], "Cross {s2}", [
(leave_encounter),
(try_begin),
(lt, "$g_dist_1", "$g_dist_2"),
(party_relocate_near_party, "p_main_party", "p_6"),
(else_try),
(party_relocate_near_party, "p_main_party", "p_5"),
(try_end),]),
("leave",[],"Stay on this side of {s2}.",[(change_screen_return)]),
]),
("use_portal_4", 0, "The guards of {s2} let you through.", "none",
[(store_distance_to_party_from_party, "$g_dist_1", "p_main_party", "p_7"),
(store_distance_to_party_from_party, "$g_dist_2", "p_main_party", "p_8"),],
[
("use_portal", [], "Cross {s2}", [
(leave_encounter),
(try_begin),
(lt, "$g_dist_1", "$g_dist_2"),
(party_relocate_near_party, "p_main_party", "p_8"),
(else_try),
(party_relocate_near_party, "p_main_party", "p_7"),
(try_end),]),
("leave",[],"Stay on this side of {s2}.",[(change_screen_return)]),
]),
("use_portal_5", 0, "The guards of {s2} let you through.", "none",
[(store_distance_to_party_from_party, "$g_dist_1", "p_main_party", "p_9"),
(store_distance_to_party_from_party, "$g_dist_2", "p_main_party", "p_10"),],
[
("use_portal", [], "Cross {s2}", [
(leave_encounter),
(try_begin),
(lt, "$g_dist_1", "$g_dist_2"),
(party_relocate_near_party, "p_main_party", "p_10"),
(else_try),
(party_relocate_near_party, "p_main_party", "p_9"),
(try_end),]),
("leave",[],"Stay on this side of {s2}.",[(change_screen_return)]),
]),
("use_portal_6", 0, "The guards of {s2} let you through.", "none",
[(store_distance_to_party_from_party, "$g_dist_1", "p_main_party", "p_11"),
(store_distance_to_party_from_party, "$g_dist_2", "p_main_party", "p_12"),],
[
("use_portal", [], "Cross {s2}", [
(leave_encounter),
(try_begin),
(lt, "$g_dist_1", "$g_dist_2"),
(party_relocate_near_party, "p_main_party", "p_12"),
(else_try),
(party_relocate_near_party, "p_main_party", "p_11"),
(try_end),]),
("leave",[],"Stay on this side of {s2}.",[(change_screen_return)]),
]),
("portal_hostile", 0, "The guards of {s2} cross their weapons and are unwilling to let you pass, on grounds of your negative relation with {s0}.", "none",
[],
[
("leave", [], "Stay on this side of {s2}", [(change_screen_return)])]),
#F&B end



Now we get to the last part,
Editing the map:

Use the 3d editor of choice and open your map with it.

In order to block off a section of the map and still be able to get access to the castle in between, the castle needs to be placed on 1 small mountain face. If the mountain face, the castle is placed upon is too large, parties will get stuck trying to reach the castle, if it’s too small, you may not find it possible to place the castle on that face. If they castle is placed on either side of that mountain face, it will only be accessible from that side. To get this right, it requires some trial and error. But as a rule of thumb, you want to zoom in so far, that a neighboring face takes up the whole screen then make the mountain face a few centimeters large. Just experiment a little till it works.

Here’s a screenshot of how it has to look in Swyter’s Cartographer:
2j41w1k.png

Lastly, place the parties, which will serve as portals on the map.
The portals are used in pairs, 1&2, 3&4, 5&6, 7&8, etc.. Anything that goes into portal 1, comes out at portal 2. So position 1 at one side of a castle, 2 on the other side. Position 3 at one side of a castle, 4 at the other side, etc. In the screenshot above, you can see 5 being just above Nelag Castle, 6 is just below.

Hopefully you’re still alive :wink:
 

Blobmania

Grandmaster Knight
WBNW
Just came across this, it's a cool idea.

I've got an alternative theory on how you might be able to do it, if you're interested in other options;

If you create two new parties for each "pass" castle, and place them at the nearest locations to the castle that an enemy army could safely travel through (i.e. the nearest unblocked pass), you could change your check (whenever a new target location is assigned) to compare the distance between the army party, all of your potential crossing locations (all castles, and all of their 2x closest available crossing points), plus the distance between each of them and the target. If the crossing party with the lowest value at the end is an enemy castle, you set the next lowest number from that castle's closest crossing points as the current target. This should (if the logic in my head is correct) send all parties to take the shortest route avoiding enemy chokepoints, without having to worry about all of the portal type stuff.

Pseudo-code of the equation in my head is as follows:

CHECK (iterate through all pass castles and closest crossing points):

DISTANCE between ARMY and CROSSING/CASTLE + DISTANCE between CASTLE and TARGET

Store NEW RESULT and NEW RESULT PARTY ID

Compare PREVIOUS RESULT with NEW RESULT, replace PREVIOUS RESULT (and ID) with NEW RESULT (and ID) if NEW RESULT is LOWER

(repeat above for all castles & crossings)

IF (at completion of above iterations) RESULT PARTY ID is an enemy CASTLE, run a script to grab the closest free crossings (these could potentially be castles) and run a similar distance check. Check both results to see if they're an enemy CASTLE, and if one is, set the other as the current target. If neither is, set the shortest distance as the current target. If both are, run the check again for both of these new castles.

IF (at completion of the very first check) the lowest distance value isn't an enemy castle, you want to let the party choose its own path, as it *should* choose the shortest path anyway. The only issue I perceive with this option would be from Rivers and Mountains that don't have checks at their crossing points, as these affect the route the AI picks. Some more thought might need to go into how to fix that issue - I'm unsure how complex the native AI targeting calculations are. If your AI checks run every time an army changes direction (i.e. as they cross a river, or turn around the corner of a mountain range) then it won't be a problem, I've just never extensively looked into the campaign AI.

You'd need to add some tolerance to the distances in favour of the non-enemy crossing points just to allow for the width of the enemy-held passes (given that they have a distance width in themselves and cannot be accurately calculated for with a single point value).

I can't guarantee that it would work out - You probably know more about the campaign AI than I do, I've only ever really dabbled in MP troop AI before. I'm sure you can prove or disprove the theory with the knowledge you've got already.

Anyway, nice job.

- Blob
 

Fire_and_Blood

Knight at Arms
YSNP in action (the lag is from Fraps demanding too much from my poor pc :wink: ):


@Blobmania

While that idea would work, there are two reasons, why I didn't go such a route.
a) It disadvantages the ai, since the player is not limited by those pathing restrictions and can just walk through a pass, that would be blocked for the ai.
b) It involves more distance calculations, which would make such a script even more complicated that the current version is.

The portal stuff is the simple part:

(party_set_ai_object, ":party_no", ":portal_entry"),
and in a trigger, that fires at 0 distance between "party_no" and ":portal_entry"
(party_relocate_near_party, ":party_no", ":portal_exit"),

The complex part is the distance calculation, because there is no way to calculate the in-game path length between point a and point b. You can only measure air distance and use that number to estimate the actual distance. You also need to add enough checks, to make the estimate for the actual travel distance close to reality, otherwise it creates weird pathing behavior. So the more distances you measure and compare, the more prone to errors the whole calculation becomes.

What I'm doing is this:
-Check whether the party should and can cross any of the 6 portals (while there are 12 portal entries, I treat them in pairs for most calculations to make calculations shorter)
-If that fails, let engine decide on pathing

What you seem to suggest is this:
-Check whether the party should and can cross any of the 6 castles
-If not, check the 12 alternative routes to decide which one to use

That adds a whole lot of distance calculations, which can be skipped by using portals.

I'm sure, there is a way to deal with part b), but without engine hacking, it seems impossible to restrict the players worldmap movement the same way you restrict the ai movement.
 

Marko͘

Section Moderator
WBNWM&BWF&SVC
I think so,

Only parties that have a relation of 0 or above with the faction holding the castle can pass. This is true for ai and the player.
For the player to pass, he needs to first visit the castle and then select the option "cross fortress".

Even if it shows up, maybe the response/outcome is negative.
 

Cozur

Grandmaster Knight
WB
Fire_and_Blood said:
The option "Cross fortress" only shows up, if the relation is not negative.

Have you added another option that shows up when relation is negative? Might be a good fallback so people don't get confused.
 

Lord of Shadows

Sergeant Knight
WBNWVCWF&SM&B
Fire_and_Blood said:
The option "Cross fortress" only shows up, if the relation is not negative.

Ok, then, that makes sense.
I think it would be a good idea if player must pay a bit if he/she has neutral relation with the faction.
 

Fire_and_Blood

Knight at Arms
Cozur said:
Have you added another option that shows up when relation is negative? Might be a good fallback so people don't get confused.

Good point. An updated menu will be included in the next release. It should be obvious why a player can't cross, especially since it's possible to have negative relation with a faction without being at war with them.
 

Fire_and_Blood

Knight at Arms
Updated Part 1 & 3 of the module_game_menus section.

The menu is now more fluent and informative:
For player owned portaled castles:
Cross -> Cross "$current_town"
        -> Stay on this side of "$current_town"

For all other portaled castles:
Attempt to cross "$current town" -> if neg. relation -> The guards of "$current_town" cross their weapons and are unwilling to let you pass, on grounds of your negative relation with ":cur_faction"
                                                        if not neg. relation -> Cross "$current_town"
                                                                                    -> Stay on this side of "$current_town"

The game menu now automatically calculates, where the player has to be teleported to, when selecting "Cross "$current_town"".
 

cwr

Count
M&BWB
A minor thing, but perhaps relations with the lord of the castle could also prevent the player from crossing?
 

Marko͘

Section Moderator
WBNWM&BWF&SVC
I would not implement that, if you have peace treaties with the faction you should be able to cross. Denying it to you is a war cause, and then you'd have to always worry who owns the castle, free him when captured, not fight him blalala and it could get worse if the castle switches hands unexpectedly.
 

Fire_and_Blood

Knight at Arms
Just noticed, that the directions were in the wrong order. It makes more sense to inject call_script, "calculate_distances", before adding any scripts and triggers, that way it's not possible to add a (call_script, "script_calculate_distances") into itself, which the original instructions were advising to do.

Anyways, the instructions have been rearranged so that it will work, if followed in order.
 

Jesgard Gysson

will this work for bridges too? because i've made a castle scene that would be a great way to defend chokepoints in lowland with many rivers, also, is it possible to add a "sneak around" option? and in the case of getting caught, a small contigent of your army has to face a part of the enemy army
 

Michadr

Grandmaster Knight
WBM&BVC
Jesgard Gysson said:
Michadr said:
This is a awesome idea. Could this be used on "wall props" too?
what do you mean by that?
Say if you had a wall instead of a catle on the map. This could be used to stop parties from bypassing the wall.
 
Top Bottom