From aa685d7e56f1213096d991038a2305fb7906a53d Mon Sep 17 00:00:00 2001 From: ln-zookeeper Date: Tue, 9 Dec 2014 16:14:47 +0200 Subject: [PATCH] Scrap the random guard placement The guard placement randomization is practically impossible to write so that it'd guarantee a route through the map without making it too trivial. Now, there are 3 separate hardcoded guard layouts, one of which will be chosen at random. --- changelog | 2 + .../Liberty/scenarios/05_Hide_and_Seek.cfg | 327 +++++------------- players_changelog | 2 + 3 files changed, 99 insertions(+), 232 deletions(-) diff --git a/changelog b/changelog index 09e7ec5e374..659c187df67 100644 --- a/changelog +++ b/changelog @@ -56,6 +56,8 @@ Version 1.13.0-dev: * New animation for Ravanal's shadow wave. * Heir to the Throne: * Fixed missing message in 'The Siege of Elensefar'. + * Liberty: + * Fixed possibility of no viable routes around guards in 'Hide and Seek'. * Northern Rebirth: * Fixed Sister Thera and Father Morvin respawning into the recall list if the other is on the north or west map edges. diff --git a/data/campaigns/Liberty/scenarios/05_Hide_and_Seek.cfg b/data/campaigns/Liberty/scenarios/05_Hide_and_Seek.cfg index b4da04727a3..b74f83ae190 100644 --- a/data/campaigns/Liberty/scenarios/05_Hide_and_Seek.cfg +++ b/data/campaigns/Liberty/scenarios/05_Hide_and_Seek.cfg @@ -155,250 +155,113 @@ [/unit] #enddef - {SEEKER 3 42 (Iron Mauler)} - {SEEKER 15 37 (Shock Trooper)} - {SEEKER 17 38 (Shock Trooper)} {SEEKER 2 45 (Bowman)} {SEEKER 3 47 (Bowman)} - # Here we approximate the vision area extending around all units and - # initialize the loop variables, both of which we need when randomly - # placing the guards below + {RANDOM "a,b,c"} + [switch] + variable=random - [store_locations] - [filter] - [/filter] - - radius=6 - - [filter_radius] - terrain=Gg,R*,Re^Gvs,*^V*,C* - [/filter_radius] - - variable=total_vision_area - [/store_locations] - - {VARIABLE guards 1} - {VARIABLE loops 0} - - # This loop which places most of the guards works like this: - # - # - generate a new guard (at 1,1, no real location for it yet) - # - figure out the vision range of this unit (dependant on unit type and - # traits) and a few other helper variables - # - store all the locations on which the vision range of the new guard - # wouldn't touch the vision range of any other unit. - # - pick one of those locations randomly, and place the new guard there. - # - pick a random location which satisfies the same condition (but - # ignoring the vision range of the new guard) around the new guard, - # and place an assistant guard there, so guards are almost always - # paired. - # - update the total vision range with those of the new guards. - # - repeat until 20 guards are placed or we've repeated 25 times. - # - # Note that when calculating vision ranges of units, the vision range is - # only approximated, by only allowing the simulated vision range to - # penetrate terrain=Gg,R*,Re^Gvs,*^V*,C*. However, this is a good enough - # estimate when the map doesn't contain thin walls of other terrains. - # - # The result is the map filled with randomly placed pairs of guards, - # which all have a hex or two of space between their vision ranges, thus - # allowing the player to sneak through the map without being spotted. - # It might not be perfect, but it seems to work perfectly most of the - # time. - - [while] - [variable] - name=guards - less_than=20 - [/variable] - - [variable] - name=loops - less_than=25 - [/variable] - - [do] - {VARIABLE_OP guard_type rand "Shock Trooper"} - - [unit] - x,y=1,1 - side=2 - type=$guard_type - random_traits=yes - generate_name=yes - [/unit] - - [store_unit] - [filter] - x,y=1,1 - [/filter] - - kill=yes - variable=stored_guard - [/store_unit] - - [if] - [variable] - name=stored_guard.modifications.trait[0].id - not_equals=quick - [/variable] - - [variable] - name=stored_guard.modifications.trait[1].id - not_equals=quick - [/variable] - - [then] - {VARIABLE guard_MP $stored_guard.max_moves} - [/then] - - [else] - {VARIABLE guard_MP $stored_guard.max_moves} - {VARIABLE_OP guard_MP add 1} - [/else] - [/if] - - {VARIABLE guard_vision_range $guard_MP} - {VARIABLE_OP guard_vision_range add 1} - - {VARIABLE guard_vision_range_plus_1 $guard_vision_range} - {VARIABLE_OP guard_vision_range_plus_1 add 1} - - {VARIABLE guard_vision_range_plus_3 $guard_vision_range} - {VARIABLE_OP guard_vision_range_plus_3 add 3} + [case] + value=a [store_locations] - [and] - find_in=total_vision_area - radius=$guard_vision_range_plus_3 - - [filter_radius] - terrain=Gg,R*,Re^Gvs,*^V*,C* - [/filter_radius] - [/and] - - [not] - find_in=total_vision_area - radius=$guard_vision_range_plus_1 - - [filter_radius] - terrain=Gg,R*,Re^Gvs,*^V*,C* - [/filter_radius] - [/not] - - [and] - terrain=Gg,R*,Re^Gvs,*^V*,C* - [/and] - - variable=new_guard_locations + x= 7,19,24,30,17,25, 2, 6,18, 2,24,13,16, 3,15,17,30,19, 3,27, 9 + y=13, 9,10,13,18,21,22,23,27,28,30,32,32,37,37,38,38,41,42,43,47 + variable=guard_locs [/store_locations] + [/case] + + [case] + value=b + + [store_locations] + x= 2,25,14,30, 5,16,25, 6, 2,33,16,22,13, 3,15,17,28, 3, 7,21 + y=10,10,13,13,19,20,21,23,28,28,31,31,32,37,37,38,39,42,48,48 + variable=guard_locs + [/store_locations] + [/case] + + [case] + value=c + + [store_locations] + x=22, 7,16,26,15, 4,31,19,15,30, 5, 4, 8,15,17,27,19, 3,20 + y=12,13,13,15,18,22,23,26,27,29,32,35,35,37,38,39,41,42,46 + variable=guard_locs + [/store_locations] + [/case] + [/switch] + + {FOREACH guard_locs i} + # The guard positions are designed to work with 4MP guards only, so + # we need to make sure the guards cannot get the quick trait, and we + # do this by randomizing their traits manually. + [set_variables] + name=traits_without_quick + + [value] + {TRAIT_STRONG} + [/value] + [value] + {TRAIT_RESILIENT} + [/value] + [value] + {TRAIT_FEARLESS} + [/value] + [value] + {TRAIT_INTELLIGENT} + [/value] + [/set_variables] + + {VARIABLE_OP first_trait rand "0..3"} + [set_variables] + name=this_guard_traits + to_variable=traits_without_quick[$first_trait].trait + [/set_variables] + + # To prevent the same trait from being picked twice, we need to find + # and remove the first picked trait from the array. + {FOREACH traits_without_quick j} + [if] + [variable] + name=traits_without_quick[$j].trait.id + equals=$traits_without_quick[$first_trait].trait.id + [/variable] - {IF_VAR new_guard_locations.length greater_than 0 ( [then] - {VARIABLE_OP random_i rand "1..$new_guard_locations.length"} - {VARIABLE_OP random_i sub 1} - - {VARIABLE stored_guard.x $new_guard_locations[$random_i].x} - {VARIABLE stored_guard.y $new_guard_locations[$random_i].y} - - [unstore_unit] - variable=stored_guard - [/unstore_unit] - - [store_locations] - [and] - x,y=$stored_guard.x,$stored_guard.y - radius=2 - [/and] - - [not] - find_in=total_vision_area - radius=7 - - [filter_radius] - terrain=Gg,R*,Re^Gvs,*^V*,C* - [/filter_radius] - [/not] - - [not] - terrain=*^F*,Hh,Ww,Wo,Ss,Ds - [/not] - - variable=new_assistant_guard_locations - [/store_locations] - - {IF_VAR new_assistant_guard_locations.length greater_than 0 ( - [then] - {VARIABLE_OP random_i rand "1..$new_assistant_guard_locations.length"} - {VARIABLE_OP random_i sub 1} - - {VARIABLE_OP assistant_guard_type rand "Shock Trooper,Shock Trooper,Iron Mauler,Javelineer,Swordsman,Pikeman"} - - [unit] - type=$assistant_guard_type - side=2 - x,y=$new_assistant_guard_locations[$random_i].x,$new_assistant_guard_locations[$random_i].y - generate_name=yes - random_traits=yes - [/unit] - - [store_locations] - [and] - x,y=$new_assistant_guard_locations[$random_i].x,$new_assistant_guard_locations[$random_i].y - radius=6 - - [filter_radius] - terrain=Gg,R*,Re^Gvs,*^V*,C* - [/filter_radius] - [/and] - - [or] - find_in=total_vision_area - [/or] - - variable=total_vision_area - [/store_locations] - [/then] - )} - - [store_locations] - [and] - x,y=$stored_guard.x,$stored_guard.y - radius=$guard_vision_range - - [filter_radius] - terrain=Gg,R*,Re^Gvs,*^V*,C* - [/filter_radius] - [/and] - - [or] - find_in=total_vision_area - [/or] - - variable=total_vision_area - [/store_locations] - - {VARIABLE_OP guards add 1} + {CLEAR_VARIABLE traits_without_quick[$first_trait]} [/then] - )} + [/if] + {NEXT j} - {VARIABLE_OP loops add 1} - [/do] - [/while] + {VARIABLE_OP second_trait rand "0..2"} + [set_variables] + name=this_guard_traits + mode=append + to_variable=traits_without_quick[$second_trait].trait + [/set_variables] - {CLEAR_VARIABLE total_vision_area} - {CLEAR_VARIABLE new_guard_locations} - {CLEAR_VARIABLE new_assistant_guard_locations} - {CLEAR_VARIABLE guard_type} - {CLEAR_VARIABLE assistant_guard_type} - {CLEAR_VARIABLE stored_guard} - {CLEAR_VARIABLE guard_MP} - {CLEAR_VARIABLE guard_vision_range} - {CLEAR_VARIABLE guard_vision_range_plus_1} - {CLEAR_VARIABLE guard_vision_range_plus_3} - {CLEAR_VARIABLE guards} - {CLEAR_VARIABLE loops} + {RANDOM "Shock Trooper,Iron Mauler"} + + [unit] + type=$random + side=2 + x,y=$guard_locs[$i].x,$guard_locs[$i].y + generate_name=yes + random_traits=no + [modifications] + [insert_tag] + name=trait + variable=this_guard_traits + [/insert_tag] + [/modifications] + [/unit] + + {CLEAR_VARIABLE this_guard_traits} + {NEXT i} + + {CLEAR_VARIABLE guard_locs,traits_without_quick,first_trait,second_trait,random} [store_unit] [filter] diff --git a/players_changelog b/players_changelog index e61de118c8d..1944bba7219 100644 --- a/players_changelog +++ b/players_changelog @@ -15,6 +15,8 @@ Version 1.13.0-dev: * Eastern Invasion: * Updated maps for scenario 14, 16 and 17b. * New animation for Ravanal's shadow wave. + * Liberty: + * Fixed possibility of no viable routes around guards in 'Hide and Seek'. * Northern Rebirth: * Fixed Sister Thera and Father Morvin respawning into the recall list if the other is on the north or west map edges.