diff --git a/data/multiplayer/scenarios/2p_Dark_Forecast.cfg b/data/multiplayer/scenarios/2p_Dark_Forecast.cfg index 7c51b976a954..e4ea696a5484 100644 --- a/data/multiplayer/scenarios/2p_Dark_Forecast.cfg +++ b/data/multiplayer/scenarios/2p_Dark_Forecast.cfg @@ -6,1000 +6,13 @@ description= _ "Dark Forecast is a survival scenario for solitaire or two-player team-based play against randomly-spawned AI units. Victory is achieved by surviving and defeating all enemy waves. During the course of play, the terrain will change based on random weather effects. Note: You need to use the default map settings for the scenario to work right." - turns="45" - experience_modifier="100" + turns=-1 + experience_modifier=100 map_data="{multiplayer/maps/Dark_Forecast_basic.map}" victory_when_enemies_defeated=no - define=MULTIPLAYER_2P_DARK_FORECAST_LOAD - -#ifdef MULTIPLAYER_2P_DARK_FORECAST_LOAD -#define RANDOMIZE NUMBER - {VARIABLE_OP random rand 1..{NUMBER}} -#enddef - -#define RANDOMIZE_INDEX NUMBER - {VARIABLE_OP random rand 1..{NUMBER}} - {VARIABLE_OP random sub 1} -#enddef - -#define PLACE_SPAWN_GROUP X Y - {VARIABLE spawn_x {X}} - {VARIABLE spawn_y {Y}} - [if] - [variable] - name=spawn_x - equals="random" - [/variable] - [then] - {RANDOMIZE $location} - [store_locations] - variable=locs - [and] - x=$spawn_place[$random].x - y=$spawn_place[$random].y - radius=1 - [/and] - include_borders=no - [/store_locations] - {RANDOMIZE_INDEX $locs.length} - {VARIABLE spawn_x $locs[$random].x} - {VARIABLE spawn_y $locs[$random].y} - {CLEAR_VARIABLE locs} - [/then] - [/if] - [store_unit] - variable=spawns - kill=yes - [filter] - canrecruit=no - side=1,2 - [not] - x=1-15 - y=1-15 - [/not] - [/filter] - [/store_unit] - {FOREACH spawns id} - # store the original max_moves so they can be restored later - {VARIABLE spawns[$id].variables.original_max_moves $spawns[$id].max_moves} - - # give the unit only a third of its normal max movement for now - {VARIABLE_OP spawns[$id].max_moves multiply 0.33} - {VARIABLE_OP spawns[$id].max_moves add 1} - - {VARIABLE spawns[$id].side $timid_ai_side} - {VARIABLE spawns[$id].generate_name yes} - {VARIABLE spawns[$id].status.slowed yes} - {CLEAR_VARIABLE spawns[$id].name} - - [unstore_unit] - variable=spawns[$id] - [/unstore_unit] - - [object] - silent=yes - duration=forever - - [filter] - x,y=$spawns[$id].x,$spawns[$id].y - [/filter] - - [effect] - apply_to=movement_costs - replace=true - [movement_costs] - flat=1 - sand=2 - forest=2 - impassable=3 - unwalkable=3 - deep_water=3 - [/movement_costs] - [/effect] - [/object] - {NEXT id} - {CLEAR_VARIABLE spawns} - [store_unit] - variable=spawns - kill=yes - [filter] - canrecruit=no - side=1,2 - [not] - x=1-15 - y=1-15 - [/not] - [/filter] - [/store_unit] - {VARIABLE msg "Spawning: "} - {FOREACH spawns id} - {VARIABLE spawns[$id].x $spawn_x} - {VARIABLE spawns[$id].y $spawn_y} - {VARIABLE_OP spawns[$id].facing rand "sw,se,se"} - {VARIABLE msg "$msg - $spawns[$id].type"} - [if] - [variable] - name=unit_name - equals="none" - [/variable] - [else] - {VARIABLE spawns[$id].name $unit_name} - [/else] - [/if] - [unstore_unit] - variable=spawns[$id] - find_vacant=yes - animate=yes - [/unstore_unit] - {NEXT id} - {CLEAR_VARIABLE spawns} - ### DEBUG - #{VARIABLE msg "$msg - # - #total cost: $total_cost"} - #[message] - # speaker=narrator - # message=$msg - #[/message] -#enddef - - # copies the units over from FROM_SIDE to TO_SIDE - # and removes all temporary limitations of movement_type and max_moves -#define ADJUST_AGGRESSION FROM_SIDE TO_SIDE - [if] - [have_unit] - side={FROM_SIDE} - [/have_unit] - [then] - [store_unit] - variable=ai_unit - kill=yes - [filter] - side={FROM_SIDE} - [/filter] - [/store_unit] - {FOREACH ai_unit id} - {VARIABLE ai_unit[$id].side {TO_SIDE}} - {CLEAR_VARIABLE ai_unit[$id].movement_costs} - {VARIABLE ai_unit[$id].max_moves $ai_unit[$id].variables.original_max_moves} - - [unstore_unit] - variable=ai_unit[$id] - find_vacant=no - [/unstore_unit] - {NEXT id} - - {CLEAR_VARIABLE ai_unit} - [/then] - [/if] -#enddef - -#define SPAWN_UNIT SIDE TYPE ID TIER_NUMBER NUMBER - {VARIABLE y "$(15-{NUMBER})"} # 10 + 11 - NUMBER - {VARIABLE x 18} - {VARIABLE this_tier {TIER_NUMBER}} - [if] - [variable] - name=this_tier - greater_than=1 - [/variable] - [then] - {VARIABLE x 19} - [/then] - [/if] - [unit] - type={TYPE} - side={SIDE} - x=$x - y=$y - role=new_unit{TIER_NUMBER} - random_traits=no - name="none" - to_variable=new_unit - [/unit] - {VARIABLE_OP gold sub $new_unit.cost} - ### DEBUG - {VARIABLE_OP total_cost add $new_unit.cost} - [if] - [variable] - name=min_cost - greater_than=$new_unit.cost - [/variable] - [then] - {VARIABLE min_cost $new_unit.cost} - [/then] - [/if] - {VARIABLE_OP max_units sub 1} - {VARIABLE new_unit.variables.spawn_id {ID}} - {VARIABLE new_unit.role new_spawn{TIER_NUMBER}} - [unstore_unit] - variable=new_unit - [/unstore_unit] - {CLEAR_VARIABLE new_unit} -#enddef - -#define ADJUST_UNIT_LEVEL SIDE TIER_NUMBER - {VARIABLE next_tier {TIER_NUMBER}} - {VARIABLE_OP next_tier add 1} - {VARIABLE next_role "new_spawn$next_tier"} - [store_unit] - kill=yes - variable=new_spawn - [filter] - side={SIDE} - role=new_spawn{TIER_NUMBER} - [/filter] - [/store_unit] - {FOREACH new_spawn unit_id} - {VARIABLE spawn_id $new_spawn[$unit_id].variables.spawn_id} - {VARIABLE previous_cost $new_spawn.cost} - {VARIABLE advanceto $main_spawns[$group_id].spawn_type[$spawn_id].up{TIER_NUMBER}} - [if] - [variable] - name=advanceto - not_equals=null - [/variable] - [variable] - name=advanceto - not_equals=none - [/variable] - [then] - [if] - [variable] - name=advanceto - equals=more - [/variable] - [then] - {VARIABLE upgrade_cost $new_spawn[$unit_id].cost} - # add 2 gold to cost - {VARIABLE_OP upgrade_cost add 2} - {VARIABLE advanceto $new_spawn[$unit_id].type} - [if] - [variable] - name=gold - greater_than_equal_to=$upgrade_cost - [/variable] - [then] - {VARIABLE_OP gold sub $upgrade_cost} - ### DEBUG - {VARIABLE_OP total_cost add $upgrade_cost} - {SPAWN_UNIT {SIDE} $advanceto $spawn_id $next_role $max_units} - {VARIABLE new_spawn[$unit_id].role $next_role} - [/then] - [/if] - [/then] - [else] - [unit] - side={SIDE} - type=$advanceto - random_traits=no - name="none" - x=20 - y=15 - to_variable=advancement - [/unit] - {VARIABLE upgrade_cost $advancement.cost} - {VARIABLE_OP upgrade_cost sub $previous_cost} - # 25% surcharge - {VARIABLE_OP upgrade_cost multiply 1.25} - {CLEAR_VARIABLE advancement} - [if] - [variable] - name=gold - greater_than_equal_to=$upgrade_cost - [/variable] - [then] - {VARIABLE_OP gold sub $upgrade_cost} - ### DEBUG - {VARIABLE_OP total_cost add $upgrade_cost} - {VARIABLE new_spawn[$unit_id].role $next_role} - - {VARIABLE somehack_type $advanceto} - {VARIABLE use_somehack yes} - [/then] - [/if] - [/else] - [/if] - [/then] - [/if] - - [if] - [variable] - name=use_somehack - boolean_equals=yes - [/variable] - - [then] - [unit] - type=$somehack_type - side={SIDE} - x=$new_spawn[$unit_id].x - y=$new_spawn[$unit_id].y - role=new_unit{TIER_NUMBER} - random_traits=no - name="none" - [/unit] - - {VARIABLE use_somehack no} - [/then] - - [else] - [unstore_unit] - variable=new_spawn[$unit_id] - find_vacant=yes - [/unstore_unit] - [/else] - [/if] - {NEXT unit_id} - {CLEAR_VARIABLE new_spawn} -#enddef - -#define CLEAR_SPAWN_GROUP NUMBER - {CLEAR_VARIABLE main_spawns[{NUMBER}]} - {VARIABLE_OP main_group sub 1} -#enddef - -#define VICTORY_CHECK - [event] - name=die - [filter] - side=1,2 - [/filter] - [filter_condition] - [not] - [have_unit] - side=1,2 - x=1-15 - y=1-15 - [/have_unit] - [/not] - [/filter_condition] - - [music] - name=victory.ogg - play_once=yes - immediate=yes - [/music] - [message] - speaker=narrator - message= _"The screams and pleas for mercy are finally silenced, as you remove your blood soaked blade from the last of the rebels. There will be no more resistance from the local scum. Your reign has finally earned stability." - image=wesnoth-icon.png - [/message] - [endlevel] - result=victory - [/endlevel] - [/event] -#enddef - -#define FINAL_SPAWN - [if] - [variable] - name=fixed_groups_left - greater_than=0 - [/variable] - [then] - {VARIABLE_OP fixed_id rand "1..$fixed_group"} - {VARIABLE size $fixed_spawns[$fixed_id].spawn_number} - [while] - [variable] - name=size - less_than=1 - [/variable] - [do] - {VARIABLE_OP fixed_id add 1} - [if] - [variable] - name=fixed_id - greater_than=$fixed_group - [/variable] - [then] - {VARIABLE fixed_id 1} - [/then] - [/if] - {VARIABLE size $fixed_spawns[$fixed_id].spawn_number} - [/do] - [/while] - {VARIABLE id 1} - {VARIABLE y 9} - [while] - [variable] - name=id - less_than_equal_to=$size - [/variable] - [do] - {VARIABLE type $fixed_spawns[$fixed_id].spawn_type[$id].type} - [unit] - type=$type - side=2 - x=18 - y=$y - random_traits=no - name="none" - [/unit] - {VARIABLE_OP y add 1} - {VARIABLE_OP id add 1} - [/do] - [/while] - {PLACE_SPAWN_GROUP $fixed_spawns[$fixed_id].x $fixed_spawns[$fixed_id].y} - {VARIABLE fixed_spawns[$fixed_id].spawn_number 0} - {VARIABLE_OP fixed_groups_left sub 1} - [/then] - [/if] -#enddef - -#define REGULAR_RANDOM_SPAWNS SIDE INTERVAL_NUMBER SPAWN_NUMBER BASE_GOLD_AMOUNT GOLD_INCREMENT UNITS_AMOUNT GOLD_PER_UNIT_AMOUNT - # Calculate how many timed_spawn[] entries to define. - [if] - [variable] - name=main_group - less_then={SPAWN_NUMBER} - [/variable] - [then] - {VARIABLE spawn_limit $main_group} - [/then] - [else] - {VARIABLE spawn_limit {SPAWN_NUMBER}} - [/else] - [/if] - {VARIABLE spawn_id 0} - [while] - [variable] - name=spawn_id - less_than=$spawn_limit - [/variable] - [do] - {VARIABLE turns $spawn_id} - {VARIABLE_OP turns multiply {INTERVAL_NUMBER}} - {VARIABLE_OP turns add 3} - {VARIABLE_OP spawn_id add 1} # Loop control variable increment. - {VARIABLE gold {BASE_GOLD_AMOUNT}} - {VARIABLE gold_turns $turns} - {VARIABLE_OP gold_turns sub 3} - {VARIABLE_OP gold_turns multiply {GOLD_INCREMENT}} - {VARIABLE_OP gold add $gold_turns} - - # regular spawns - [if] - [variable] - name=spawn_id - greater_than=1 - [/variable] - [then] - {VARIABLE units $gold_turns} - # add a random amount of the basic gold - {RANDOMIZE {BASE_GOLD_AMOUNT}} - {VARIABLE gold1 $random} - {RANDOMIZE {BASE_GOLD_AMOUNT}} - [if] - [variable] - name=gold1 - less_than=random - [/variable] - [then] - {VARIABLE random $gold1} - [/then] - [/if] - {CLEAR_VARIABLE gold1} - {VARIABLE_OP units add $random} - {VARIABLE unit_increment {GOLD_PER_UNIT_AMOUNT}} - {VARIABLE unit_turns $turns} - {VARIABLE_OP unit_turns divide 1.5} - {VARIABLE_OP unit_increment add $unit_turns} - {VARIABLE_OP units divide $unit_increment} - ### DEBUG - {VARIABLE unit_increment $units} - ### END DEBUG - {VARIABLE_OP units add {UNITS_AMOUNT}} - {VARIABLE_OP random rand -1..2} - {VARIABLE_OP units add $random} - {RANDOMIZE 5} - [if] - [variable] - name=random - numerical_equals=1 - [/variable] - [then] - {VARIABLE_OP units sub 1} - [/then] - [/if] - {VARIABLE_OP random rand -1..1} - {VARIABLE_OP turns add $random} - [/then] - [else] - {VARIABLE units {UNITS_AMOUNT}} - {VARIABLE_OP units add 1} - ### DEBUG - {VARIABLE unit_increment 0} - ### END DEBUG - [/else] - [/if] - {VARIABLE timed_spawn[$spawn_id].units $units} - {VARIABLE timed_spawn[$spawn_id].turn $turns} - {VARIABLE timed_spawn[$spawn_id].gold $gold} - ### DEBUG - {VARIABLE timed_spawn[$spawn_id].units_added $unit_increment} - ### END DEBUG - [/do] - [/while] - {CLEAR_VARIABLE spawn_limit} - - {VARIABLE final_turns "$timed_spawn[{SPAWN_NUMBER}].turn"} - {VARIABLE_OP final_turns add 40} - {VARIABLE_OP final_turns divide 2} - {VARIABLE_OP final_turns round 0} - {VARIABLE fixed_groups_left $fixed_group} - {VARIABLE trigger_index 1} - # reduce gold and units for spawns - # after the final spawn - {VARIABLE spawn_id 0} - {VARIABLE end_spawn 0} - [while] - [variable] - name=spawn_id - less_than=$timed_spawn.length - [/variable] - [do] - [if] - [variable] - name=timed_spawn[$spawn_id].turn - greater_than_equal_to=$final_turns - [/variable] - [then] - {VARIABLE_OP timed_spawn[$spawn_id].gold divide "$($end_spawn+3)"} - {VARIABLE_OP timed_spawn[$spawn_id].units divide "$($end_spawn+4)"} - [if] - # two spawns added to the final - [variable] - name=end_spawn - greater_than=1 - [/variable] - [then] - {VARIABLE timed_spawn[$spawn_id].turn -1} - [/then] - [else] - {VARIABLE_OP end_spawn add 1} - [/else] - [/if] - [/then] - [/if] - {VARIABLE_OP spawn_id add 1} - [/do] - [/while] - [event] - name=new turn - first_time_only=no - [filter_condition] - [variable] - name=turn_number - greater_than=2 - [/variable] - [variable] - name=turn_number - numerical_equals=$timed_spawn[$trigger_index].turn - [/variable] - [/filter_condition] - - # normal spawn - {VARIABLE gold $timed_spawn[$trigger_index].gold} - {VARIABLE max_units $timed_spawn[$trigger_index].units} - {VARIABLE min_cost 100} - {VARIABLE_OP trigger_index add 1} - - ### DEBUG - {VARIABLE total_cost 0} - {VARIABLE_OP group_id rand 1..$main_group} - {VARIABLE size $main_spawns[$group_id].spawn_number} - [while] - [variable] - name=gold - greater_than=0 - [/variable] - [variable] - name=max_units - greater_than=0 - [/variable] - [do] - {RANDOMIZE $size} - [if] - [variable] - name=random - greater_than=0 - [/variable] - [then] - {VARIABLE type $main_spawns[$group_id].spawn_type[$random].type} - {SPAWN_UNIT {SIDE} $type $random 1 $max_units} - [/then] - [else] - # fallback for invalid/cleared spawn groups - {VARIABLE gold 0} - [/else] - [/if] - [/do] - [/while] - {ADJUST_UNIT_LEVEL {SIDE} 1} - {ADJUST_UNIT_LEVEL {SIDE} 2} - {ADJUST_UNIT_LEVEL {SIDE} 3} - # spend remainder - {VARIABLE extra_units 3} - [while] - [variable] - name=gold - greater_than_equal_to=$min_cost - [/variable] - [variable] - name=extra_units - greater_than=0 - [/variable] - [do] - {RANDOMIZE $size} - [if] - [variable] - name=random - greater_than=0 - [/variable] - [then] - {VARIABLE type $main_spawns[$group_id].spawn_type[$random].type} - {SPAWN_UNIT {SIDE} $type $random 5 $max_units} - {VARIABLE_OP extra_units sub 1} - [/then] - [else] - # fallback for invalid/cleared spawn groups - {VARIABLE gold 0} - [/else] - [/if] - [/do] - [/while] - {PLACE_SPAWN_GROUP $main_spawns[$group_id].x $main_spawns[$group_id].y} - {CLEAR_SPAWN_GROUP $group_id} - [music] - name=frantic.ogg - ms_before=300 - play_once=yes - immediate=yes - [/music] - [/event] - - # the event extending the turn limit - # (This is so the player does not know exactly when the final spawn will occur?) - [event] - name=turn_44 - id=Dark_Forecast_Turn_Limit_Extension_Starter - - [event] - name=new_turn - id=Dark_Forecast_Turn_Limit_Extension - first_time_only=no - - # Add a turn. - [modify_turns] - add=1 - [/modify_turns] - [/event] - [/event] - - # the event firing final spawns - [event] - name=turn_$final_turns - - [music] - name=battle.ogg - ms_before=200 - immediate=yes - append=yes - [/music] - {FINAL_SPAWN} - [modify_turns] - value="$($turn_number + 12)" - [/modify_turns] - [message] - side=3,4 - canrecruit=yes - message= _ "The last and most powerful of these creatures are almost upon us. I feel that if we can finish them off in time, we shall be victorious." - [/message] - - # Define the victory condition. - {VICTORY_CHECK} - - # Stop the turn limit extension. - [event] - id=Dark_Forecast_Turn_Limit_Extension_Starter - remove=yes - [/event] - [event] - id=Dark_Forecast_Turn_Limit_Extension - remove=yes - [/event] - - # More final spawns in later turns: - {VARIABLE_OP next_final_spawn rand 2..3} - {VARIABLE_OP next_final_spawn add $turn_number} - [event] - name=turn_$next_final_spawn - first_time_only=no - - {FINAL_SPAWN} - {RANDOMIZE 2} - {VARIABLE_OP next_final_spawn add $random} - [/event] - [/event] -#enddef - - # X_VALUE is either an X coordinate (for fixed spawn position) - # or "random" for a random location - # chosen from the spawn_place array - # set in DEFINE_SPAWN_LOCATION - # (in the latter case Y_VALUE is ignored) -#define DEFINE_MAIN_GROUP X_VALUE Y_VALUE - {VARIABLE spawn_id 0} - {VARIABLE_OP main_group add 1} - {VARIABLE main_spawns[$main_group].x {X_VALUE}} - {VARIABLE main_spawns[$main_group].y {Y_VALUE}} -#enddef - -#define ADD_MAIN_SPAWN TYPE UP1_VALUE UP2_VALUE UP3_VALUE - {VARIABLE_OP spawn_id add 1} - {VARIABLE main_spawns[$main_group].spawn_type[$spawn_id].type {TYPE}} - {VARIABLE main_spawns[$main_group].spawn_type[$spawn_id].up1 {UP1_VALUE}} - {VARIABLE main_spawns[$main_group].spawn_type[$spawn_id].up2 {UP2_VALUE}} - {VARIABLE main_spawns[$main_group].spawn_type[$spawn_id].up3 {UP3_VALUE}} - {VARIABLE main_spawns[$main_group].spawn_number $spawn_id} -#enddef - -#define DEFINE_SPAWN_LOCATION X_SPAN Y_SPAN - {VARIABLE_OP location add 1} - {VARIABLE spawn_place[$location].x {X_SPAN}} - {VARIABLE spawn_place[$location].y {Y_SPAN}} -#enddef - -#define DEFINE_FIXED_GROUP X Y - {VARIABLE spawn_id 0} - {VARIABLE_OP fixed_group add 1} - {VARIABLE fixed_spawns[$fixed_group].x {X}} - {VARIABLE fixed_spawns[$fixed_group].y {Y}} -#enddef - -#define ADD_FIXED_SPAWN TYPE - {VARIABLE_OP spawn_id add 1} - {VARIABLE fixed_spawns[$fixed_group].spawn_type[$spawn_id].type {TYPE}} - {VARIABLE fixed_spawns[$fixed_group].spawn_number $spawn_id} -#enddef - -#define SET_TIMID_AI_AND_BOLD_AI TIMID_SIDE BOLD_SIDE - {VARIABLE timid_ai_side {TIMID_SIDE}} - {VARIABLE bold_ai_side {BOLD_SIDE}} - [event] - name=side turn - first_time_only=no - [if] - [variable] - name=side_number - greater_than=$timid_ai_side - [/variable] - [then] - {ADJUST_AGGRESSION $timid_ai_side $bold_ai_side} - [/then] - [/if] - [/event] -#enddef - -#define WEATHER_EVENT_AT TURN WEATHER_VALUE - {VARIABLE_OP weather_events add 1} - {VARIABLE weather_event[$weather_events].turn {TURN}} - {VARIABLE weather_event[$weather_events].weather {WEATHER_VALUE}} - {RANDOMIZE 2} - {VARIABLE_OP turn add $random} - {VARIABLE_OP weather[{WEATHER_VALUE}].turns sub $random} - {VARIABLE max_turns 2} - {VARIABLE w_id {WEATHER_VALUE}} - [if] - [variable] - name=w_id - numerical_equals=0 - [/variable] - [then] - {VARIABLE max_turns 1} - [/then] - [/if] - [while] - [variable] - name=max_turns - greater_than=0 - [/variable] - [variable] - name=weather[{WEATHER_VALUE}].turns - greater_than=1 - [/variable] - [do] - {RANDOMIZE 2} - [if] - [variable] - name=random - less_than=2 - [/variable] - [then] - {VARIABLE_OP turn add $random} - {VARIABLE_OP max_turns sub $random} - {VARIABLE_OP weather[{WEATHER_VALUE}].turns sub $random} - [/then] - [else] - # stop incrementing - {VARIABLE max_turns 0} - [/else] - [/if] - [/do] - [/while] - {CLEAR_VARIABLE w_id} -#enddef - -#define WEATHER_MAP NAME - [terrain_mask] - mask={NAME} - x=1 - y=1 - border=yes - [/terrain_mask] -#enddef - -#define WEATHER_ALERT TEXT RED GREEN BLUE - [print] - text= {TEXT} - duration=120 - size=26 - red={RED} - green={GREEN} - blue={BLUE} - [/print] -#enddef - -#define ADJUST_WEATHER VAR - [switch] - variable={VAR} - - [case] - value=4 - # second snow - {WEATHER_MAP "{multiplayer/maps/Dark_Forecast_secondsnow.map}"} - [sound] - name=bat-flapping.wav - [/sound] - {WEATHER_ALERT _"Heavy Snowfall" 224 255 251} - [/case] - - [case] - value=3 - # first snow - {WEATHER_MAP "{multiplayer/maps/Dark_Forecast_firstsnow.map}"} - [sound] - name=wail.wav - [/sound] - {WEATHER_ALERT _"Snowfall" 229 243 241} - [/case] - - [case] - value=2 - # heavy rains - {WEATHER_MAP "{multiplayer/maps/Dark_Forecast_rain.map}"} - [sound] - name=magic-faeriefire-miss.ogg - [/sound] - [delay] - time=250 - [/delay] - [sound] - name=ambient/ship.ogg - [/sound] - {WEATHER_ALERT _"Heavy Rains" 174 220 255} - [/case] - - [case] - value=1 - # drought - {WEATHER_MAP "{multiplayer/maps/Dark_Forecast_drought.map}"} - [sound] - name=gryphon-shriek-1.ogg - [/sound] - {WEATHER_ALERT _"Drought" 251 231 171} - [/case] - - [else] - # clear weather - {WEATHER_MAP "{multiplayer/maps/Dark_Forecast_basic.map}"} - [sound] - name=magic-holy-miss-2.ogg - [/sound] - {WEATHER_ALERT _"Clear Weather" 221 253 171} - [/else] - [/switch] -#enddef - -#define INIT_WEATHER - {VARIABLE weather[0].turns 22} - {VARIABLE weather[0].name "Clear"} - {VARIABLE weather[1].turns 10} - {VARIABLE weather[1].name "Drought"} - {VARIABLE weather[2].turns 12} - {VARIABLE weather[2].name "Heavy Rain"} - {VARIABLE weather[3].turns 9} - {VARIABLE weather[3].name "Snowfall"} - {VARIABLE weather[4].turns 6} - {VARIABLE weather[4].name "Heavy Snowfall"} - {VARIABLE next_weather 1} - {VARIABLE weather_events 0} - - # Enforce limits on turns spent in each weather pattern. - {VARIABLE_OP turn rand 4..6} - [while] - [variable] - name=turn - less_than=55 - [/variable] - [do] - {VARIABLE_OP id rand 1..3} - {VARIABLE check 3} - [while] - [variable] - name=weather[$id].turns - less_than=1 - [/variable] - [variable] - name=check - greater_than=0 - [/variable] - [do] - # Cycle to the next weather, excluding clear and heavy snow. - {VARIABLE id "$($id % 3 + 1)"} - # Prevent infinite recursion. - {VARIABLE_OP check sub 1} - [/do] - [/while] - {WEATHER_EVENT_AT $turn $id} - # check for second snow - [if] - [variable] - name=id - numerical_equals=3 - [/variable] - [variable] - name=weather[4].turns - greater_than=0 - [/variable] - [then] - # Second snow happens half the time. - {RANDOMIZE 2} - [if] - [variable] - name=random - equals=1 - [/variable] - [then] - {WEATHER_EVENT_AT $turn 4} - [/then] - [/if] - [/then] - [/if] - # Go back to clear weather. - {WEATHER_EVENT_AT $turn 0} - [/do] - [/while] - [event] - name=side 3 turn - first_time_only=no - [filter_condition] - [variable] - name=turn_number - greater_than_equal_to=$weather_event[$next_weather].turn - [/variable] - [/filter_condition] - - {ADJUST_WEATHER weather_event[$next_weather].weather} - {VARIABLE_OP next_weather add 1} - [/event] -#enddef {DEFAULT_SCHEDULE_DAWN} -#endif [side] side=1 team_name="revolt" @@ -1064,136 +77,13 @@ Note: You need to use the default map settings for the scenario to work right." fog="yes" share_view="yes" [/side] - -#ifdef MULTIPLAYER_2P_DARK_FORECAST_LOAD + [lua] + code = << + wesnoth.dofile("multiplayer/scenarios/2p_Dark_Forecast.lua") + >> + [/lua] [event] name=prestart - {SET_TIMID_AI_AND_BOLD_AI 2 1} - {VARIABLE location 0} - {VARIABLE turn_limit 40} - {DEFINE_SPAWN_LOCATION "3-14" "15"} #south - {DEFINE_SPAWN_LOCATION "1" "4-13"} #west - {DEFINE_SPAWN_LOCATION "2-13" "1"} #north - {DEFINE_SPAWN_LOCATION "1" "2-15"} #west - - {VARIABLE main_group 0} - - # this is used as spacer for the final spawns - {VARIABLE next_final_spawn 99} - - {DEFINE_MAIN_GROUP random 1} - {ADD_MAIN_SPAWN "Heavy Infantryman" "Shock Trooper" "Iron Mauler" "none"} - {ADD_MAIN_SPAWN "Elvish Fighter" "Elvish Hero" "more" "Elvish Champion"} - {ADD_MAIN_SPAWN "Goblin Spearman" "more" "more" "more"} - {ADD_MAIN_SPAWN "Goblin Spearman" "Goblin Rouser" "none" "none"} - {ADD_MAIN_SPAWN "Elvish Fighter" "Elvish Captain" "Elvish Marshal" "none"} - - {DEFINE_MAIN_GROUP random 2} - {ADD_MAIN_SPAWN "Mage" "Red Mage" "Silver Mage" "none"} - {ADD_MAIN_SPAWN "Footpad" "Outlaw" "more" "none"} - {ADD_MAIN_SPAWN "Drake Fighter" "Drake Warrior" "Drake Blademaster" "none"} - {ADD_MAIN_SPAWN "Walking Corpse" "more" "more" "more"} - - {DEFINE_MAIN_GROUP random 3} - {ADD_MAIN_SPAWN "Merman Hunter" "Merman Spearman" "Merman Entangler" "none"} - {ADD_MAIN_SPAWN "Naga Fighter" "Naga Warrior" "Naga Myrmidon" "none"} - {ADD_MAIN_SPAWN "Spearman" "Pikeman" "none" "Halberdier"} - - {DEFINE_MAIN_GROUP random 4} - {ADD_MAIN_SPAWN "Elvish Shaman" "Elvish Druid" "Elvish Shyde" "Elvish Sylph"} - {ADD_MAIN_SPAWN "Drake Burner" "Fire Drake" "Inferno Drake" "Armageddon Drake"} - {ADD_MAIN_SPAWN "Skeleton" "Revenant" "more" "Draug"} - - {DEFINE_MAIN_GROUP random 5} - {ADD_MAIN_SPAWN "Giant Mudcrawler" "Sea Serpent" "none" "none"} - {ADD_MAIN_SPAWN "Mudcrawler" "more" "Giant Mudcrawler" "more"} - - {DEFINE_MAIN_GROUP random 6} - {ADD_MAIN_SPAWN "Ghoul" "Necrophage" "more" "none"} - {ADD_MAIN_SPAWN "Elvish Archer" "Elvish Marksman" "none" "Elvish Sharpshooter"} - {ADD_MAIN_SPAWN "Elvish Archer" "Elvish Ranger" "Elvish Avenger" "none"} - {ADD_MAIN_SPAWN "Drake Clasher" "Drake Thrasher" "more" "Drake Enforcer"} - - {DEFINE_MAIN_GROUP random 7} - {ADD_MAIN_SPAWN "Skeleton Archer" "Bone Shooter" "more" "Banebow"} - {ADD_MAIN_SPAWN "Fencer" "Duelist" "none" "Master at Arms"} - {ADD_MAIN_SPAWN "Drake Glider" "Sky Drake" "Hurricane Drake" "none"} - - {DEFINE_MAIN_GROUP random 8} - {ADD_MAIN_SPAWN "Merman Fighter" "Merman Warrior" "more" "Merman Triton"} - {ADD_MAIN_SPAWN "Dark Adept" "Dark Sorcerer" "Necromancer" "none"} - {ADD_MAIN_SPAWN "Elvish Scout" "Elvish Rider" "more" "none"} - - {DEFINE_MAIN_GROUP random 9} - {ADD_MAIN_SPAWN "Wose" "Elder Wose" "Ancient Wose" "none"} - {ADD_MAIN_SPAWN "Orcish Archer" "Orcish Crossbowman" "Orcish Slurbow" "none"} - {ADD_MAIN_SPAWN "Saurian Skirmisher" "more" "Saurian Ambusher" "more"} - - {DEFINE_MAIN_GROUP random 10} - {ADD_MAIN_SPAWN "Orcish Grunt" "Orcish Warrior" "more" "none"} - {ADD_MAIN_SPAWN "Vampire Bat" "Blood Bat" "more" "none"} - {ADD_MAIN_SPAWN "Dwarvish Thunderer" "Dwarvish Thunderguard" "none" "none"} - {ADD_MAIN_SPAWN "Peasant" "more" "more" "more"} - {ADD_MAIN_SPAWN "Woodsman" "more" "Sergeant" "Orcish Ruler"} - - {DEFINE_MAIN_GROUP random 11} - {ADD_MAIN_SPAWN "Dwarvish Guardsman" "Dwarvish Stalwart" "none" "none"} - {ADD_MAIN_SPAWN "Bowman" "Longbowman" "more" "Master Bowman"} - {ADD_MAIN_SPAWN "Troll Whelp" "Troll" "Troll Warrior" "none"} - - {DEFINE_MAIN_GROUP random 12} - {ADD_MAIN_SPAWN "Orcish Assassin" "Orcish Slayer" "more" "none"} - {ADD_MAIN_SPAWN "Cavalryman" "Dragoon" "more" "Cavalier"} - {ADD_MAIN_SPAWN "Saurian Augur" "Saurian Soothsayer" "none" "none"} - - {DEFINE_MAIN_GROUP random 13} - {ADD_MAIN_SPAWN "Wolf Rider" "Goblin Pillager" "more" "none"} - {ADD_MAIN_SPAWN "Ghost" "Shadow" "more" "more"} - {ADD_MAIN_SPAWN "Sergeant" "Lieutenant" "General" "Grand Marshal"} - - {DEFINE_MAIN_GROUP random 14} - {ADD_MAIN_SPAWN "Gryphon Rider" "none" "more" "none"} - {ADD_MAIN_SPAWN "Thief" "Rogue" "more" "Assassin"} - - {DEFINE_MAIN_GROUP random 15} - {ADD_MAIN_SPAWN "Dwarvish Fighter" "Dwarvish Steelclad" "more" "Dwarvish Lord"} - {ADD_MAIN_SPAWN "Poacher" "Trapper" "more" "none"} - {ADD_MAIN_SPAWN "Cuttle Fish" "more" "more" "none"} - - {DEFINE_MAIN_GROUP random 16} - {ADD_MAIN_SPAWN "Walking Corpse" "more" "more" "more"} - {ADD_MAIN_SPAWN "Mage" "White Mage" "Mage of Light" "none"} - {ADD_MAIN_SPAWN "Thug" "Bandit" "more" "none"} - - {VARIABLE fixed_group 0} - - {DEFINE_FIXED_GROUP 1 15} - {ADD_FIXED_SPAWN "Fire Dragon"} - {ADD_FIXED_SPAWN "Gryphon Master"} - {ADD_FIXED_SPAWN "Hurricane Drake"} - - {DEFINE_FIXED_GROUP 5 1} - {ADD_FIXED_SPAWN "Yeti"} - {ADD_FIXED_SPAWN "Elvish Druid"} - {ADD_FIXED_SPAWN "Elvish Druid"} - - {DEFINE_FIXED_GROUP 1 7} - {ADD_FIXED_SPAWN "Lich"} - {ADD_FIXED_SPAWN "Walking Corpse"} - {ADD_FIXED_SPAWN "Walking Corpse"} - {ADD_FIXED_SPAWN "Walking Corpse"} - {ADD_FIXED_SPAWN "Ghoul"} - {ADD_FIXED_SPAWN "Soulless"} - {ADD_FIXED_SPAWN "Walking Corpse"} - {ADD_FIXED_SPAWN "Walking Corpse"} - {ADD_FIXED_SPAWN "Walking Corpse"} - - {DEFINE_FIXED_GROUP 11 15} - {ADD_FIXED_SPAWN "Elvish Champion"} - {ADD_FIXED_SPAWN "Dwarvish Stalwart"} - {ADD_FIXED_SPAWN "Dwarvish Stalwart"} - {ADD_FIXED_SPAWN "Orcish Slayer"} - [store_unit] variable=leader [filter] @@ -1215,7 +105,7 @@ Note: You need to use the default map settings for the scenario to work right." {VARIABLE notes ( _ "Since your team has two leaders, the enemy waves will be at full strength.")} [/else] [/if] - + {CLEAR_VARIABLE leader} [music] name=wanderer.ogg ms_before=2000 @@ -1290,24 +180,6 @@ The weather will also change randomly, affecting the layout of the map. [/message] [/event] - [event] - name=turn 2 - {INIT_WEATHER} - [if] - [variable] - name=leader.length - less_than=2 - [/variable] - [then] - {REGULAR_RANDOM_SPAWNS 2 5 11 50 5 4 21} - [/then] - [else] - {REGULAR_RANDOM_SPAWNS 2 4 11 90 4 5 23} - [/else] - [/if] - {CLEAR_VARIABLE leader} - [/event] - [event] name=last breath first_time_only=no @@ -1362,27 +234,4 @@ The weather will also change randomly, affecting the layout of the map. message= _ "The enemy cheers as a dark mist rises from the land, engulfing you. As ghostly wisps drain away your will, you realize that your time in this land is over." [/message] [/event] - -#undef RANDOMIZE -#undef RANDOMIZE_INDEX -#undef PLACE_SPAWN_GROUP -#undef ADJUST_AGGRESSION -#undef SPAWN_UNIT -#undef ADJUST_UNIT_LEVEL -#undef CLEAR_SPAWN_GROUP -#undef VICTORY_CHECK -#undef FINAL_SPAWN -#undef REGULAR_RANDOM_SPAWNS -#undef DEFINE_MAIN_GROUP -#undef ADD_MAIN_SPAWN -#undef DEFINE_SPAWN_LOCATION -#undef DEFINE_FIXED_GROUP -#undef ADD_FIXED_SPAWN -#undef SET_TIMID_AI_AND_BOLD_AI -#undef WEATHER_EVENT_AT -#undef WEATHER_MAP -#undef WEATHER_ALERT -#undef ADJUST_WEATHER -#undef INIT_WEATHER -#endif [/multiplayer] diff --git a/data/multiplayer/scenarios/2p_Dark_Forecast.lua b/data/multiplayer/scenarios/2p_Dark_Forecast.lua new file mode 100644 index 000000000000..47e3abb1b788 --- /dev/null +++ b/data/multiplayer/scenarios/2p_Dark_Forecast.lua @@ -0,0 +1,531 @@ + +local helper = wesnoth.require("lua/helper.lua") +local _ = wesnoth.textdomain 'wesnoth-multiplayer' +local T = helper.set_wml_tag_metatable {} + +local event_handlers = {} +local old_on_event = wesnoth.game_events.on_event or function(eventname) end +wesnoth.game_events.on_event = function(eventname) + for k,v in pairs(event_handlers[eventname] or {}) do + v() + end + old_on_event(eventname) +end + +local function on_event(eventname, handler) + eventname = string.gsub(eventname, " ", "_") + event_handlers[eventname] = event_handlers[eventname] or {} + table.insert(event_handlers[eventname], handler) +end + + +local function get_spawn_types(num_units, max_gold, unit_pool) + local gold_left = max_gold + local units_left = num_units + local current_types = {} + while gold_left > 0 and units_left > 0 do + local unit_group = wesnoth.random(#unit_pool) + local unit_rank = 1 + local unit_type = wesnoth.unit_types[unit_pool[unit_group][unit_rank]] + table.insert(current_types, { group = unit_group, type = unit_type}) + gold_left = gold_left - unit_type.cost + units_left = units_left - 1 + end + -- Upgrade units, eigher by replacing them with better units or by duplicating them. + for next_rank = 2,4 do + local next_types = {} + for i,v in ipairs(current_types) do + local advanceto = unit_pool[v.group][next_rank] or "" + local unit_type = wesnoth.unit_types[advanceto] + if unit_type then + local upgrade_cost = math.ceil((unit_type.cost - v.type.cost) * 1.25) + if gold_left >= upgrade_cost then + gold_left = gold_left - upgrade_cost + table.insert(next_types, { group = v.group, type = unit_type}) + else + table.insert(next_types, { group = v.group, type = v.type}) + end + elseif advanceto == "more" then + local upgrade_cost = v.type.cost + 2 + if gold_left >= upgrade_cost then + gold_left = gold_left - upgrade_cost + table.insert(next_types, { group = v.group, type = v.type}) + end + table.insert(next_types, { group = v.group, type = v.type}) + else + table.insert(next_types, { group = v.group, type = v.type}) + end + end + current_types = next_types + end + --spend remaining gold + local min_cost = 100 + for i,v in ipairs(unit_pool) do + min_cost = math.min(min_cost, wesnoth.unit_types[v[1]].cost) + end + while gold_left >= min_cost do + local possible_groups = {} + for i,v in ipairs(unit_pool) do + local unit_type = wesnoth.unit_types[v[1]] + if unit_type.cost <= gold_left then + table.insert(possible_groups, { group = i, type = unit_type}) + end + end + local index = wesnoth.random(#possible_groups) + table.insert(current_types, possible_groups[index]) + gold_left = gold_left - possible_groups[index].type.cost + end + local res = {} + for i,v in ipairs(current_types) do + table.insert(res, v.type.id) + end + return res +end + +-- convert a ugly wml lua table to a normal lua table from the 'main_spawn' wml array from that get_spawn_types can use. +local function parse_unit_pool(pool) + local res = {} + for type_group in helper.child_range(pool, "group") do + table.insert(res, {}) + for rank in helper.child_range(type_group, "rank") do + table.insert(res[#res], rank.type) + end + end + return res +end + +-- creates the 'timed_spawn' wml array. +-- @a num_spawns: the total number of times units get spawned +-- @a interval: the number of turns between 2 spawns +-- @a base_gold_amount, gold_increment: used to cauculate the amount of gold available for each timed spawn +-- @a units_amount, gold_per_unit_amount: used to cauculate the number of units spawned in each timed spawn +local function create_timed_spaws(interval, num_spawns, base_gold_amount, gold_increment, units_amount, gold_per_unit_amount) + local final_turn = math.ceil(((num_spawns - 1) * interval + 40 + wesnoth.random(2,4))/2) + local end_spawns = 0 + for spawn_number = 1, num_spawns do + local turn = 3 + (spawn_number - 1) * interval + local gold = base_gold_amount + (turn - 3) * gold_increment + if spawn_number > 1 then + -- foruma taken from original Dark forecast, TODO: find easier formula. + local unit_gold = (turn - 3) * gold_increment + math.min(wesnoth.random(base_gold_amount), wesnoth.random(base_gold_amount)) + local gold_per_unit = gold_per_unit_amount + turn / 1.5 + local units = unit_gold / gold_per_unit + units_amount + wesnoth.random(-1, 2) + if wesnoth.random(5) == 5 then + units = units - 1 + end + -- end complicated formula + turn = turn + wesnoth.random(-1, 1) + -- reduce gold and units for spawns after the final spawn + if turn >= final_turn then + units = units / (end_spawns + 3) + gold = gold / (end_spawns + 4) + end_spawns = end_spawns + 1 + -- we only want two spawns after the final turn. + if end_spawns > 2 then + break + end + end + wesnoth.set_variable("timed_spawn[" .. (spawn_number - 1) .. "]", { + units = math.ceil(units), + turn = turn, + gold = gold, + }) + else + wesnoth.set_variable("timed_spawn[" .. (spawn_number - 1) .. "]", { + units = units_amount + 1, + turn = turn, + gold = gold, + }) + end + end + wesnoth.set_variable("final_turn", final_turn) +end + +-- @a unittypes: a array of strings +-- @a x,y: the location where to spawn the units on the map. +local function place_units(unittypes, x, y) + for i,v in ipairs(unittypes) do + local u = wesnoth.create_unit { type = v, generate_name = true, side = 2 } + u:add_modification("object", { + T.effect { + apply_to = "movement_costs", + replace = true, + T.movement_costs { + flat = 1, + sand = 2, + forest = 2, + impassable = 3, + unwalkable = 3, + deep_water = 3, + } + } + }) + -- give the unit less moves on its first turn. + u.status.slowed = true + u:add_modification("object", { + duration = "turn end", + T.effect { + apply_to = "movement", + increase = "-50%", + } + }) + local dst_x, dst_y = wesnoth.find_vacant_tile(x, y, u) + u:to_map(dst_x, dst_y) + end +end + +local function final_spawn() + local spawns_left = wesnoth.get_variable("fixed_spawn.length") + if spawns_left == 0 then + return + end + local spawn_index = wesnoth.random(spawns_left) - 1 + local spawn = wesnoth.get_variable("fixed_spawn[" .. spawn_index .. "]") + wesnoth.set_variable("fixed_spawn[" .. spawn_index .. "]") + local types = {} + for tag in wesnoth.child_range(spawn, "type") do + table.insert(types, tag.type) + end + place_units(types, spawn.x, spawn.y) +end + +-- convert all 'veteran' units from side 2 to the more agressive side 1 +-- this must happen before the new units are created from spawns. +on_event("new turn", function() + for i, unit in ipairs(wesnoth.get_units { side = 2 }) do + unit.side = 1 + end +end) + +on_event("prestart", function() + local leaders = wesnoth.get_units { side = "3,4", canrecruit= true} + if #leaders < 2 then + create_timed_spaws(5, 11, 50, 5, 4, 21) + else + create_timed_spaws(4, 11, 90, 4, 5, 23) + end +end) + +-- the regular spawns: +-- when they appear is defined in the 'timed_spawn' wml array. which is created at prestart +-- which unit types get spawned is defined in the 'main_spawn' wml array which is also spawned at prestart +on_event("new turn", function() + local next_spawn = wesnoth.get_variable("timed_spawn[0]") + if wesnoth.current.turn ~= next_spawn.turn then + return + end + wesnoth.set_variable("timed_spawn[0]") + local num_spawns = wesnoth.get_variable("main_spawn.length") + if num_spawns == 0 then + return + end + local pool_id = wesnoth.random(num_spawns) - 1 + local unit_pool = wesnoth.get_variable("main_spawn[" .. pool_id .. "]") + wesnoth.set_variable("main_spawn[" .. pool_id .. "]") + local unit_types = get_spawn_types(next_spawn.units, next_spawn.gold, parse_unit_pool(unit_pool)) + local spawn_areas = {{"3-14", "15"}, {"1", "4-13"}, {"2-13", "1"}, {"1", "2-15"}} + local spawn_area = spawn_areas[wesnoth.random(#spawn_areas)] + local locations_in_area = wesnoth.get_locations { x = spawn_area[1], y = spawn_area[2], radius=1, include_borders=false } + local chosen_location = locations_in_area[wesnoth.random(#locations_in_area)] + place_units(unit_types, chosen_location[1], chosen_location[2]) +end) + +-- on turn 'final_turn' the first 'final spawn' appears +on_event("new turn", function() + if wesnoth.current.turn ~= wesnoth.get_variable("final_turn") then + return + end + wesnoth.wml_actions.music { + name = "battle.ogg", + ms_before = 200, + immediate = true, + append = true, + } + final_spawn() + wesnoth.game_config.last_turn = wesnoth.current.turn + 12 + wesnoth.wml_actions.message { + side="3,4", + canrecruit=true, + message= _ "The last and most powerful of these creatures are almost upon us. I feel that if we can finish them off in time, we shall be victorious.", + } +end) + +-- after the first final spawn, spawn a new final spawn every 1 or 2 turns. +on_event("new turn", function() + if wesnoth.current.turn ~= wesnoth.get_variable("next_final_spawn") then + return + end + final_spawn() + wesnoth.set_variable("next_final_spawn", wesnoth.current.turn + wesnoth.random(1,2)) +end) + +-- The victory condition: win when there are no enemy unit after the first final spawn appeared. +on_event("die", function() + if wesnoth.current.turn < wesnoth.get_variable("final_turn") then + return + end + if wesnoth.have_unit { side = "1,2"} then + return + end + wesnoth.wml_actions.music { + name = "victory.ogg", + play_once = true, + immediate = true, + } + wesnoth.wml_actions.message { + speaker = "narrator", + message = _"The screams and pleas for mercy are finally silenced, as you remove your blood soaked blade from the last of the rebels. There will be no more resistance from the local scum. Your reign has finally earned stability.", + image ="wesnoth-icon.png", + } + wesnoth.wml_actions.endlevel { + result = "victory", + } +end) + +-- initilize the 'fixed_spawn' and 'main_spawn' +on_event("prestart", function() + local fixed_spawn = function(x, y, ...) + local res = { x = x, y = y } + for i,v in ipairs {...} do + table.insert(res, T.type { type = v }) + end + return res + end + local main_spawn = function(...) + local res = {} + for i, v in ipairs {...} do + local group = {} + table.insert(res, T.group(group)) + for i2, utype in ipairs(v) do + table.insert(group, T.rank { type = utype}) + end + end + return res + end + helper.set_variable_array("fixed_spawn", { + fixed_spawn(1, 15, "Fire Dragon", "Gryphon Master", "Hurricane Drake"), + fixed_spawn(5, 1, "Yeti", "Elvish Druid", "Elvish Druid"), + fixed_spawn(1, 7, "Lich", "Walking Corpse", "Walking Corpse", "Walking Corpse", "Ghoul", "Soulless", "Walking Corpse", "Walking Corpse", "Walking Corpse"), + fixed_spawn(11, 15, "Elvish Champion", "Dwarvish Stalwart", "Dwarvish Stalwart", "Orcish Slayer"), + }) + helper.set_variable_array("main_spawn", { + main_spawn( + {"Heavy Infantryman", "Shock Trooper", "Iron Mauler", "none"}, + {"Elvish Fighter", "Elvish Hero", "more", "Elvish Champion"}, + {"Goblin Spearman", "more", "more", "more"}, + {"Goblin Spearman", "Goblin Rouser", "none", "none"}, + {"Elvish Fighter", "Elvish Captain", "Elvish Marshal", "none"} + ), + main_spawn( + {"Mage", "Red Mage", "Silver Mage", "none"}, + {"Footpad", "Outlaw", "more", "none"}, + {"Drake Fighter", "Drake Warrior", "Drake Blademaster", "none"}, + {"Walking Corpse", "more", "more", "more"} + ), + main_spawn( + {"Merman Hunter", "Merman Spearman", "Merman Entangler", "none"}, + {"Naga Fighter", "Naga Warrior", "Naga Myrmidon", "none"}, + {"Spearman", "Pikeman", "none", "Halberdier"} + ), + main_spawn( + {"Elvish Shaman", "Elvish Druid", "Elvish Shyde", "Elvish Sylph"}, + {"Drake Burner", "Fire Drake", "Inferno Drake", "Armageddon Drake"}, + {"Skeleton", "Revenant", "more", "Draug"} + ), + main_spawn( + {"Giant Mudcrawler", "Sea Serpent", "none", "none"}, + {"Mudcrawler", "more", "Giant Mudcrawler", "more"} + ), + main_spawn( + {"Ghoul", "Necrophage", "more", "none"}, + {"Elvish Archer", "Elvish Marksman", "none", "Elvish Sharpshooter"}, + {"Elvish Archer", "Elvish Ranger", "Elvish Avenger", "none"}, + {"Drake Clasher", "Drake Thrasher", "more", "Drake Enforcer"} + ), + main_spawn( + {"Skeleton Archer", "Bone Shooter", "more", "Banebow"}, + {"Fencer", "Duelist", "none", "Master at Arms"}, + {"Drake Glider", "Sky Drake", "Hurricane Drake", "none"} + ), + main_spawn( + {"Merman Fighter", "Merman Warrior", "more", "Merman Triton"}, + {"Dark Adept", "Dark Sorcerer", "Necromancer", "none"}, + {"Elvish Scout", "Elvish Rider", "more", "none"} + ), + main_spawn( + {"Wose", "Elder Wose", "Ancient Wose", "none"}, + {"Orcish Archer", "Orcish Crossbowman", "Orcish Slurbow", "none"}, + {"Saurian Skirmisher", "more", "Saurian Ambusher", "more"} + ), + main_spawn( + {"Orcish Grunt", "Orcish Warrior", "more", "none"}, + {"Vampire Bat", "Blood Bat", "more", "none"}, + {"Dwarvish Thunderer", "Dwarvish Thunderguard", "none", "none"}, + {"Peasant", "more", "more", "more"}, + {"Woodsman", "more", "Sergeant", "Orcish Ruler"} + ), + main_spawn( + {"Dwarvish Guardsman", "Dwarvish Stalwart", "none", "none"}, + {"Bowman", "Longbowman", "more", "Master Bowman"}, + {"Troll Whelp", "Troll", "Troll Warrior", "none"} + ), + main_spawn( + {"Orcish Assassin", "Orcish Slayer", "more", "none"}, + {"Cavalryman", "Dragoon", "more", "Cavalier"}, + {"Saurian Augur", "Saurian Soothsayer", "none", "none"} + ), + main_spawn( + {"Wolf Rider", "Goblin Pillager", "more", "none"}, + {"Ghost", "Shadow", "more", "more"}, + {"Sergeant", "Lieutenant", "General", "Grand Marshal"} + ), + main_spawn( + {"Gryphon Rider", "none", "more", "none"}, + {"Thief", "Rogue", "more", "Assassin"} + ), + main_spawn( + {"Dwarvish Fighter", "Dwarvish Steelclad", "more", "Dwarvish Lord"}, + {"Poacher", "Trapper", "more", "none"}, + {"Cuttle Fish", "more", "more", "none"} + ), + main_spawn( + {"Walking Corpse", "more", "more", "more"}, + {"Mage", "White Mage", "Mage of Light", "none"}, + {"Thug", "Bandit", "more", "none"} + ), + }) +end) + +------------------------------------------------------------------------------- +-------------------------- Weather events ------------------------------------- +------------------------------------------------------------------------------- +-- The weather evens are complateleey unrelated to the spawn events. + +local function get_weather_duration(max_duration) + local res = wesnoth.random(2) + while res < max_duration and wesnoth.random(2) == 2 do + res = res + 1 + end + return res +end +-- initilize the weather_event wml array which defines at which turns the weather changes. +on_event("prestart", function() + local turn = wesnoth.random(4,6) + local event_num = 0 + local weather_to_dispense = { + { turns_left = 10, id = "drought"}, + { turns_left = 12, id = "heavy rain"}, + { turns_left = 9, id = "snowfall"}, + } + local clear_turns_left = 22 + local heavy_snowfall_turns_left = 6 + while turn < 55 and #weather_to_dispense > 0 do + -- pick a random weather except 'clear' and 'heavy snow' + local index = wesnoth.random(#weather_to_dispense) + local num_turns = get_weather_duration(weather_to_dispense[index].turns_left) + local weather_id = weather_to_dispense[index].id + weather_to_dispense[index].turns_left = weather_to_dispense[index].turns_left - num_turns + if weather_to_dispense[index].turns_left <= 0 then + table.remove(weather_to_dispense, index) + end + wesnoth.set_variable("weather_event[" .. event_num .. "]", { + turn = turn, + weather_id = weather_id, + }) + event_num = event_num + 1 + turn = turn + num_turns + -- Second snow happens half the time. + if weather_id == "snowfall" and heavy_snowfall_turns_left >= 0 and wesnoth.random(2) == 2 then + num_turns = get_weather_duration(heavy_snowfall_turns_left) + wesnoth.set_variable("weather_event[" .. event_num .. "]", { + turn = turn, + weather_id = "heavy snowfall", + }) + event_num = event_num + 1 + turn = turn + num_turns + heavy_snowfall_turns_left = heavy_snowfall_turns_left - num_turns + end + -- Go back to clear weather. + num_turns = get_weather_duration(clear_turns_left) + wesnoth.set_variable("weather_event[" .. event_num .. "]", { + turn = turn, + weather_id = "clear", + }) + event_num = event_num + 1 + turn = turn + num_turns + clear_turns_left = clear_turns_left - num_turns + end +end) + +local function weather_alert(text, red, green, blue) + wesnoth.wml_actions.print { + text = text, + duration = 120, + size = 26, + red = red, + green = green, + blue = blue, + } +end + +local function weather_map(name) + wesnoth.wml_actions.terrain_mask { + mask = wesnoth.read_file(name), + x = 1, + y = 1, + border = true, + } + wesnoth.redraw {} +end + +-- change weather at side 3 turns, TODO: consider the case that side 3 is empty. +on_event("side 3 turn", function() + -- get next weather event + local weather_event = wesnoth.get_variable("weather_event[0]") + if wesnoth.current.turn ~= weather_event.turn then + return + end + -- remove the to-be-consumed weather event from the todo list. + wesnoth.set_variable("weather_event[0]") + if weather_event.weather_id == "clear" then + weather_map("multiplayer/maps/Dark_Forecast_basic.map") + wesnoth.wml_actions.sound { + name = "magic-holy-miss-2.ogg", + } + weather_alert(_"Clear Weather", 221, 253, 171) + elseif weather_event.weather_id == "drought" then + weather_map ("multiplayer/maps/Dark_Forecast_drought.map") + wesnoth.wml_actions.sound { + name = "gryphon-shriek-1.ogg", + } + weather_alert(_"Drought", 251, 231, 171) + elseif weather_event.weather_id == "heavy rain" then + weather_map("multiplayer/maps/Dark_Forecast_rain.map") + wesnoth.wml_actions.sound { + name = "magic-faeriefire-miss.ogg", + } + wesnoth.wml_actions.delay { + time = 250, + } + wesnoth.wml_actions.sound { + name = "ambient/ship.ogg", + } + weather_alert(_"Heavy Rains", 174, 220, 255) + elseif weather_event.weather_id == "snowfall" then + weather_map("multiplayer/maps/Dark_Forecast_firstsnow.map") + wesnoth.wml_actions.sound { + name = "wail.wav", + } + weather_alert(_"Snowfall", 229, 243, 241) + elseif weather_event.weather_id == "heavy snowfall" then + weather_map("multiplayer/maps/Dark_Forecast_secondsnow.map") + wesnoth.wml_actions.sound { + name = "bat-flapping.wav", + } + weather_alert(_"Heavy Snowfall", 224, 255, 251) + else + error("unknown weather '" .. tostring(weather_event.weather_id) .. "'") + end +end) + +