Author Topic: Sea Battles  (Read 13658 times)

Jubal

  • Megadux
    Executive Officer
  • Posts: 31091
  • Karma: 124
  • Awards Awarded for oustanding services to Exilian!
    • View Profile
    • Awards
Sea Battles
« on: December 14, 2008, 03:31:09 PM »
[size=14]TO SEA![/size]
Implementing Sea Battles in Mount&Blade

THis is a full tutorial, spanning many posts and vast amounts of code, of how to implement Mirathei's sea battle scripts into the game using the modle system. It is accompanied by downloads of BRF files and scenes necessary for it to work. It may be expanded in future to include more information, more ship types and clever stuff, and so on.

Finally, can I say that this is not my work. I've tweaked, I've edited, I've added, but the master craftsman is Mirathei here, and this is to Mirathei's credit not mine.

I haven't had the time to work through the whole tutorial from a vanialla game yet, it may not work 100% or I may have missed some code (can you blame me?) If so, please post explaining your problem fully and I will do my best to work out the problem and edit the tutorial.

BACK UP YOUR FILES BEFORE YOU BEGIN.

Screenies before you start;




The duke, the wanderer, the philosopher, the mariner, the warrior, the strategist, the storyteller, the wizard, the wayfarer...

Jubal

  • Megadux
    Executive Officer
  • Posts: 31091
  • Karma: 124
  • Awards Awarded for oustanding services to Exilian!
    • View Profile
    • Awards
Sea Battles
« Reply #1 on: December 14, 2008, 04:43:51 PM »
1. Getting you sailing

Module_Game_Menus;
Add this anywhere in the file, allows you to get on a pre-existing boat and get off it again.
 
Code: [Select]
(
    "disembark",0,
    "Do you wish to disembark?",
    "none",
    [],
    [
      ("disembark_yes", [], "Yes.",
       [(assign, "$g_player_icon_state", pis_normal),
        (party_set_flags, "p_main_party", pf_is_ship, 0),
        (party_get_position, pos1, "p_main_party"),
        (party_set_position, "p_main_party", pos0),
        (try_begin),
          (le, "$g_main_ship_party", 0),
          (set_spawn_radius, 0),
          (spawn_around_party, "p_main_party", "pt_none"),
          (assign, "$g_main_ship_party", reg0),
          (party_set_flags, "$g_main_ship_party", pf_is_static|pf_always_visible|pf_hide_defenders|pf_is_ship, 1),
          (str_store_troop_name, s1, "trp_player"),
          (party_set_name, "$g_main_ship_party", "@{s1}'s Ship"),
          (party_set_icon, "$g_main_ship_party", "icon_ship"),
          (party_set_slot, "$g_main_ship_party", slot_party_type, spt_ship),
        (try_end),
        (enable_party, "$g_main_ship_party"),
        (party_set_position, "$g_main_ship_party", pos0),
        (party_set_icon, "$g_main_ship_party", "icon_ship_on_land"),
        (assign, "$g_main_ship_party", -1),
        (change_screen_return),
        ]),
      ("disembark_no", [], "No.",
       [(change_screen_return),
        ]),
    ]
  ),

  (
    "ship_reembark",0,
    "Do you wish to embark?",
    "none",
    [],
    [
      ("reembark_yes", [], "Yes.",
       [(assign, "$g_player_icon_state", pis_ship),
        (party_set_flags, "p_main_party", pf_is_ship, 1),
        (party_get_position, pos1, "p_main_party"),
        (map_get_water_position_around_position, pos2, pos1, 6),
        (party_set_position, "p_main_party", pos2),
        (assign, "$g_main_ship_party", "$g_encountered_party"),
        (disable_party, "$g_encountered_party"),
        (change_screen_return),
        ]),
      ("reembark_no", [], "No.",
       [(change_screen_return),
        ]),
    ]
  ),
And add this somewhere within the town menus, allowing you to get a ship;
Code: [Select]
     ("sail_from_port",[(party_slot_eq,"$current_town",slot_party_type, spt_town),
#                         (party_slot_eq,"$current_town",slot_town_near_shore, 1),
                         ], "Buy a ship (2000 denars)",
       [(assign, "$g_player_icon_state", pis_ship),
        (party_set_flags, "p_main_party", pf_is_ship, 1),
        (troop_remove_gold, "trp_player", 2000),
        (party_get_position, pos1, "p_main_party"),
        (map_get_water_position_around_position, pos2, pos1, 6),
        (party_set_position, "p_main_party", pos2),
        (assign, "$g_main_ship_party", -1),
        (change_screen_return),
        ]),


Now load the system and load the game, You should be able to buy a ship and sail around.
The duke, the wanderer, the philosopher, the mariner, the warrior, the strategist, the storyteller, the wizard, the wayfarer...

Jubal

  • Megadux
    Executive Officer
  • Posts: 31091
  • Karma: 124
  • Awards Awarded for oustanding services to Exilian!
    • View Profile
    • Awards
Sea Battles
« Reply #2 on: December 14, 2008, 04:44:51 PM »
Part 2.To war!

Firstly, you'll want the actual ship models;
http://www.exilian.110mb.com/files/ships.zip
The brf file needs to go in your mod's resource folder, and the texture in your mod textures folder.

In module_ini.txt, make sure that scan_module_textures=1, and add the following line;

Code: [Select]
load_mod_resource = sail
Add this to just before the end of module_scene props to get those all-important ship models ingame;
Code: [Select]
 ("ship",sokf_moveable,"longship","bo_longship", [   (ti_on_scene_prop_init,
    [
     (set_position_delta,0,0,0),
     (particle_system_add_new, "psys_wake"),
     (store_trigger_param_1, ":instance_no"),
     (party_set_slot,"p_ship_colisions",":instance_no",0),
    ]),]),
  ("ships_end",0,0,0,[]),
  ("enemy_ship",sokf_moveable,"longship","bo_longship", [   (ti_on_scene_prop_init,
    [
     (set_position_delta,0,0,0),
     (particle_system_add_new, "psys_wake"),
     (store_trigger_param_1, ":instance_no"),
     (party_set_slot,"p_ship_colisions",":instance_no",0),
    ]),]),
  ("enemy_ships_end",0,0,0,[]),
  ("universal_end",0,0,0,[]),

  ("ship_protect",0,0,"bo_gourd_spike",[]),
  ("enemy_ship_protect",0,0,"bo_gourd_spike",[]),

We're going to want some sea to fight on, of course...

add these files to your mod sceneobj folder;
http://www.exilian.110mb.com/files/seascenes.zip
And this to module_scenes;
Code: [Select]
 ("sea",sf_generate,"none", "none", (0,0),(240,240),-0.5,"0x0000000030000000c00d2348000000008000000000000000",
    [],[]),
  ("sea_2",sf_generate,"none", "none", (0,0),(240,240),-0.5,"0x0000000030000000c00d2348000000008000000000000000",
    [],[]),

Module_Game_menus
Find the menu marked 'encounter_attack' and replace it with the folllowing changed version, this means that when on the sea you will be given the option to enter a sea battle instead of a land fight.
Code: [Select]
     ("encounter_attack",[
          (eq, "$encountered_party_friendly", 0),
          (store_troop_health,reg(5)),(party_get_current_terrain,":terrain","p_main_party"),
          (neq,":terrain",0),
          ],
                            "Charge the enemy.",[
                                (assign, "$g_battle_result", 0),
                                (assign, "$g_engaged_enemy", 1),
                                (call_script, "script_calculate_renown_value"),
                                (call_script, "script_calculate_battle_advantage"),
                                (set_battle_advantage, reg0),
                                (set_party_battle_mode),
                                (try_begin),
                                  (eq, "$g_encounter_type", enctype_fighting_against_village_raid),
                                  (set_jump_mission,"mt_village_raid"),
                                  (party_get_slot, ":scene_to_use", "$g_encounter_is_in_village", slot_castle_exterior),
                                  (jump_to_scene, ":scene_to_use"),
                                (else_try),
                                  (eq, "$g_encounter_type", enctype_catched_during_village_raid),
                                  (set_jump_mission,"mt_village_raid"),
                                  (party_get_slot, ":scene_to_use", "$g_encounter_is_in_village", slot_castle_exterior),
                                  (jump_to_scene, ":scene_to_use"),
                                (else_try),
                                  (set_jump_mission,"mt_lead_charge"),
                                  (call_script, "script_setup_random_scene"),
                                (try_end),
                                (assign, "$g_next_menu", "mnu_simple_encounter"),
                                (jump_to_menu, "mnu_battle_debrief"),
                                (change_screen_mission),
                                ]),
      ("encounter_attack",[
          (eq, "$encountered_party_friendly", 0),
          (store_troop_health,reg(5)),(party_get_current_terrain,":terrain","p_main_party"),
          (eq,":terrain",0),
          ],
                            "Engage the enemy.",[
                                (assign, "$g_battle_result", 0),
                                (assign, "$g_engaged_enemy", 1),
                                (call_script, "script_calculate_renown_value"),
                                (call_script, "script_calculate_battle_advantage"),
                                (set_battle_advantage, reg0),
                                (set_party_battle_mode),
                                (try_begin),
                                  (eq, "$g_encounter_type", enctype_fighting_against_village_raid),
                                  (set_jump_mission,"mt_village_raid"),
                                  (party_get_slot, ":scene_to_use", "$g_encounter_is_in_village", slot_castle_exterior),
                                  (jump_to_scene, ":scene_to_use"),
                                (else_try),
                                  (eq, "$g_encounter_type", enctype_catched_during_village_raid),
                                  (set_jump_mission,"mt_village_raid"),
                                  (party_get_slot, ":scene_to_use", "$g_encounter_is_in_village", slot_castle_exterior),
                                  (jump_to_scene, ":scene_to_use"),
                                (else_try),
                                  (set_jump_mission,"mt_ship_battle"),
                                  (try_begin),
                                    (val_add,reg10,reg11),
                                    (gt,reg10,30),
                                    (jump_to_scene, "scn_sea_2"),
                                  (else_try),
                                    (jump_to_scene, "scn_sea"),
                                  (end_try),
                                (try_end),
                                (assign, "$g_next_menu", "mnu_simple_encounter"),
                                (jump_to_menu, "mnu_battle_debrief"),
                                (change_screen_mission),
                                ]),

And similarly with the join_attack menu;
Code: [Select]
       ("join_attack",[
#          (neq, "$encountered_party_hostile", 0),
          (neg|troop_is_wounded, "trp_player"),
##          (store_troop_health,reg(5),"trp_player"),
##          (ge,reg(5),20),
(party_get_current_terrain,":terrain","p_main_party"),
          (neq,":terrain",0),
          ],
                            "Charge the enemy.",[
                                (assign, "$g_battle_result", 0),
                                (call_script, "script_calculate_renown_value"),
                                (call_script, "script_calculate_battle_advantage"),
                                (set_battle_advantage, reg0),
                                (set_party_battle_mode),
                                (set_jump_mission,"mt_lead_charge"),
                                (call_script, "script_setup_random_scene"),
                                (assign, "$g_next_menu", "mnu_join_battle"),
                                (jump_to_menu, "mnu_battle_debrief"),
                                (change_screen_mission),
                                ]),

      ("join_attack",[
#          (neq, "$encountered_party_hostile", 0),
          (neg|troop_is_wounded, "trp_player"),
##          (store_troop_health,reg(5),"trp_player"),
##          (ge,reg(5),20),
(party_get_current_terrain,":terrain","p_main_party"),
          (eq,":terrain",0),
          ],
                            "Engage the enemy.",[
                                (assign, "$g_battle_result", 0),
                                (call_script, "script_calculate_renown_value"),
                                (call_script, "script_calculate_battle_advantage"),
                                (set_battle_advantage, reg0),
                                (set_party_battle_mode),
                                (set_jump_mission,"mt_ship_battle"),
                                (call_script, "script_setup_random_scene"),
                                (assign, "$g_next_menu", "mnu_join_battle"),
                                (jump_to_menu, "mnu_battle_debrief"),
                                  (try_begin),
                                    (val_add,reg10,reg11),
                                    (gt,reg10,30),
                                    (jump_to_scene, "scn_sea_2"),
                                  (else_try),
                                    (jump_to_scene, "scn_sea"),
                                  (end_try),
                                (change_screen_mission),
                                ]),


Mission Templates
Now we can actually get these ships moving!
Code: [Select]
(
    "ship_battle",mtf_battle_mode,-1,
    "You enter battle on your longships.",
    [
     (0,mtef_attackers|mtef_team_1,af_override_horse,aif_start_alarmed,4,[]),
     (1,mtef_attackers|mtef_team_1,af_override_horse,aif_start_alarmed,4,[]),
     (2,mtef_attackers|mtef_team_1,af_override_horse,aif_start_alarmed,4,[]),
     (10,mtef_defenders|mtef_team_0,af_override_horse,aif_start_alarmed,4,[]),
     (11,mtef_defenders|mtef_team_0,af_override_horse,aif_start_alarmed,4,[]),
     (12,mtef_defenders|mtef_team_0,af_override_horse,aif_start_alarmed,4,[]),
     ],
    [
      (1, 0, 0, [], [(scene_prop_get_instance,"$ship", "spr_ship", 0),(scene_prop_get_instance,"$eship", "spr_enemy_ship", 0),]),
      
      (10, 0, ti_once, [], [(try_for_agents,":agent"),(agent_set_speed_limit,":agent",0),(end_try),]),
      (ti_tab_pressed, 0, 0, [],
       [
           (try_begin),
             (eq, "$battle_won", 1),
             (finish_mission,0),
           (else_try),
             (call_script, "script_cf_check_enemies_nearby"),
             (question_box,"str_do_you_want_to_retreat"),
           (else_try),
             (display_message,"str_can_not_retreat"),
           (try_end),
        ]),
      
      (0, 0, ti_once, [], [(assign,"$pbehavior",1),(assign,"$ebehavior",2),(assign,"$battle_won",0),]),
      (1, 60, ti_once, [(store_mission_timer_a,reg(1)),(ge,reg(1),10),(all_enemies_defeated,2),(neg|main_hero_fallen,0),(set_mission_result,1),(display_message,"str_msg_battle_won"),(assign,"$battle_won",1),(assign, "$g_battle_result", 1)],
           [(finish_mission,1)]),
      (10, 0, 0, [], [(eq,"$battle_won",1),(display_message,"str_msg_battle_won")]),
      (1, 4, ti_once, [(main_hero_fallen,0)],
          [(set_mission_result,-1),(finish_mission,1)]),


#friendly ship ai
      (0.1, 0, 0, [],
      [(call_script,"script_check_for_collisions"),]),

      (0.1, 0, 0, [],
      [(call_script,"script_kill_overboard"),]),


      (0.05, 0, 0, [],
      [(call_script,"script_cf_keep_troops_on_ships"),]),

 #     (0.1, 0, 0, [],
#[(try_for_agents,":agent"),
 #     (agent_is_human,":agent"),
  #    (agnet_is_alive,":agent"),


      (1.0, 0, 0, [(eq,"$pbehavior",1)],                  
       [(scene_prop_get_num_instances,reg12, "spr_ship"),
        (val_add,reg12,1),
        (try_for_range,reg13,0,reg12),
           (scene_prop_get_instance,"$ship", "spr_ship", reg13),
           (call_script,"script_select_enemy_ship"),
           (call_script,"script_cf_close_and_board"),
        (end_try),(call_script,"script_check_for_collisions"),]),
          
      
      (1.0, 0, 0, [(eq,"$pbehavior",2),],                  
       [(scene_prop_get_num_instances,reg12, "spr_ship"),
        (val_add,reg12,1),
        (try_for_range,reg13,0,reg12),
           (scene_prop_get_instance,"$ship", "spr_ship", reg13),
           (call_script,"script_select_enemy_ship"),
           (call_script,"script_skirmish"),
        (end_try),(call_script,"script_check_for_collisions"),]),
        


#enemy ship ai


 
      (10.0, 0, 0, [],
       [(assign,":friends",0),
        (assign,":enemies",0),
        (try_for_agents,":agent"),
           (agent_is_alive,":agent"),
           (try_begin),
              (agent_is_ally,":agent"),
              (val_add,":friends",1),
           (else_try),
              (val_add,":enemies",1),
           (end_try),
        (end_try),
        (try_begin),
           (val_mul,":friends",10),
           (val_div,":friends",":enemies"),
           (gt,":friends",8),
           (assign,"$ebehavior",2),
        (else_try),
           (assign,"$ebehavior",1),
        (end_try)]),      


      (1.0, 0, 0, [(eq,"$ebehavior",1)],
       [(scene_prop_get_num_instances,reg12, "spr_enemy_ship"),
        (val_add,reg12,1),
        (try_for_range,reg13,0,reg12),
           (scene_prop_get_instance,"$ship", "spr_enemy_ship", reg13),
           (call_script,"script_select_friendly_ship"),
           (call_script,"script_cf_close_and_board"),
        (end_try),(call_script,"script_check_for_collisions"),]),
        
      (1.0, 0, 0, [(eq,"$ebehavior",2)],
       [(scene_prop_get_num_instances,reg12, "spr_enemy_ship"),
        (val_add,reg12,1),
        (try_for_range,reg13,0,reg12),
           (scene_prop_get_instance,"$ship", "spr_enemy_ship", reg13),
           (call_script,"script_select_friendly_ship"),
           (call_script,"script_skirmish"),
        (end_try),(call_script,"script_check_for_collisions"),]),


    

  
       (ti_inventory_key_pressed, 0, 0, [(try_begin),
                                            (eq,"$pbehavior",2),
                                            (assign,"$pbehavior",0),
                                            (display_message,"str_hold"),
                                            (scene_prop_get_instance,"$ship", "spr_ship", 0),
                                            (prop_instance_get_position,1,"$ship"),
                                            (prop_instance_animate_to_position,"$ship",1,1),
                                         (else_try),
                                            (val_add,"$pbehavior",1),
                                            (try_begin),
                                               (eq,"$pbehavior",1),
                                               (display_message,"str_board"),
                                            (else_try),
                                               (display_message,"str_skirmish"),
                                            (end_try),
                                         (end_try)], []),

      (ti_question_answered, 0, 0, [],
       [(store_trigger_param_1,":answer"),(eq,":answer",0),(finish_mission,0),]),
  


    ],
  ),
The duke, the wanderer, the philosopher, the mariner, the warrior, the strategist, the storyteller, the wizard, the wayfarer...

Jubal

  • Megadux
    Executive Officer
  • Posts: 31091
  • Karma: 124
  • Awards Awarded for oustanding services to Exilian!
    • View Profile
    • Awards
Sea Battles
« Reply #3 on: December 14, 2008, 04:46:55 PM »
(part 2 continued)

Scripts

These scripts move and manouevre the ship.
[code]################################################################

#
The duke, the wanderer, the philosopher, the mariner, the warrior, the strategist, the storyteller, the wizard, the wayfarer...

Jubal

  • Megadux
    Executive Officer
  • Posts: 31091
  • Karma: 124
  • Awards Awarded for oustanding services to Exilian!
    • View Profile
    • Awards
Sea Battles
« Reply #4 on: December 14, 2008, 04:48:15 PM »
3. Someone to fight!
Time we put someone to fight for you on the high seas...

Find this section of mdule contants, adding the bold red line;
Code: [Select]
num_forest_bandit_spawn_points = 1
num_mountain_bandit_spawn_points = 1
num_steppe_bandit_spawn_points = 1
num_black_khergit_spawn_points = 1
num_sea_raider_spawn_points = 2
[COLOR=red][B]num_sea_pirate_spawn_points = 3[/B][/COLOR]

Add this to module_party_templates;
[code]
The duke, the wanderer, the philosopher, the mariner, the warrior, the strategist, the storyteller, the wizard, the wayfarer...

Jubal

  • Megadux
    Executive Officer
  • Posts: 31091
  • Karma: 124
  • Awards Awarded for oustanding services to Exilian!
    • View Profile
    • Awards
Sea Battles
« Reply #5 on: December 14, 2008, 04:48:28 PM »
Placeholder
The duke, the wanderer, the philosopher, the mariner, the warrior, the strategist, the storyteller, the wizard, the wayfarer...

Jubal

  • Megadux
    Executive Officer
  • Posts: 31091
  • Karma: 124
  • Awards Awarded for oustanding services to Exilian!
    • View Profile
    • Awards
Sea Battles
« Reply #6 on: December 14, 2008, 04:48:42 PM »
Placeholder
The duke, the wanderer, the philosopher, the mariner, the warrior, the strategist, the storyteller, the wizard, the wayfarer...

Jubal

  • Megadux
    Executive Officer
  • Posts: 31091
  • Karma: 124
  • Awards Awarded for oustanding services to Exilian!
    • View Profile
    • Awards
Sea Battles
« Reply #7 on: December 14, 2008, 06:49:28 PM »
Updated already, thanks Ruthven.
The duke, the wanderer, the philosopher, the mariner, the warrior, the strategist, the storyteller, the wizard, the wayfarer...

Jubal

  • Megadux
    Executive Officer
  • Posts: 31091
  • Karma: 124
  • Awards Awarded for oustanding services to Exilian!
    • View Profile
    • Awards
Sea Battles
« Reply #8 on: December 14, 2008, 09:02:24 PM »
Update #2, thanks again to Ruthven (forgot River Pirates weren't in Native).
The duke, the wanderer, the philosopher, the mariner, the warrior, the strategist, the storyteller, the wizard, the wayfarer...

Guest

  • Guest
Sea Battles
« Reply #9 on: February 03, 2009, 08:51:34 PM »
I just get this error :/

Initializing...
Compiling all global variables...
Exporting strings...
Exporting skills...
Exporting tracks...
Exporting animations...
Exporting meshes...
Exporting sounds...
Exporting skins...
Exporting map icons...
Exporting faction data...
Exporting item data...
Exporting scene data...
Exporting troops data
Exporting particle data...
Exporting scene props...
Error: Unable to find object:psys_wake
ERROR: Illegal Identifier:psys_wake
Error: Unable to find object:p_ship_colisions
ERROR: Illegal Identifier:p_ship_colisions
Error: Unable to find object:psys_wake
ERROR: Illegal Identifier:psys_wake
Error: Unable to find object:p_ship_colisions
ERROR: Illegal Identifier:p_ship_colisions
Exporting tableau materials data...
Exporting presentations...
Exporting party_template data...
Exporting parties
Exporting quest data...
Exporting scripts...
Exporting mission_template data...
Error: Unable to find object:spr_gourd_spike
ERROR: Illegal Identifier:spr_gourd_spike
Error: Unable to find object:spr_gourd_spike
ERROR: Illegal Identifier:spr_gourd_spike
Error: Unable to find object:spr_gourd_spike
ERROR: Illegal Identifier:spr_gourd_spike
Exporting game menus data...
exporting simple triggers...
exporting triggers...
exporting dialogs...
Checking global variable usages...

______________________________

Script processing has ended.
Press any key to exit. . .

Jubal

  • Megadux
    Executive Officer
  • Posts: 31091
  • Karma: 124
  • Awards Awarded for oustanding services to Exilian!
    • View Profile
    • Awards
Sea Battles
« Reply #10 on: February 03, 2009, 09:34:26 PM »
You're missing the bit in particle systems an the bit in parties, the last 2 bits of code in section 2.
The duke, the wanderer, the philosopher, the mariner, the warrior, the strategist, the storyteller, the wizard, the wayfarer...

Guest

  • Guest
Sea Battles
« Reply #11 on: May 22, 2009, 11:06:32 PM »
Okay i try to  build module yet i get  python is a unreadable source so i cant implement sea battles. it cant find .pyc or my mod.

Jubal

  • Megadux
    Executive Officer
  • Posts: 31091
  • Karma: 124
  • Awards Awarded for oustanding services to Exilian!
    • View Profile
    • Awards
Sea Battles
« Reply #12 on: May 23, 2009, 07:08:29 AM »
THat would indicate a problem with your installation of Python methinks.
The duke, the wanderer, the philosopher, the mariner, the warrior, the strategist, the storyteller, the wizard, the wayfarer...

Silver Wolf

  • Megas Domestikos
    Voting Member
  • Posts: 4725
  • Karma: 42
    • View Profile
    • Awards
Sea Battles
« Reply #13 on: May 31, 2009, 12:41:50 AM »
Is it possible to add this into the game as a sea battle ? (9000 triangles)
(The original ship model is not mine... I have just reduced the polycount, modified the ship a bit and made this battle scene with two ships)

"Less of a young professional - more of an ancient amateur. But frankly, I'm an absolute dream."

Darwin

  • M&B Modders and Tutorialists
    Voting Member
  • Posts: 415
  • Karma: 0
  • Scio ne nihil scire, ergo disco.
    • View Profile
    • Awards
Sea Battles
« Reply #14 on: July 14, 2009, 01:10:09 PM »
nice model :)
« Last Edit: July 14, 2009, 01:10:26 PM by Darwin »