Modding Q&A [For Quick Questions and Answers]

Users who are viewing this thread

Status
Not open for further replies.
Lumos said:
That's a bit more complicated and there are a number of variants. I am unfortunately busy right now, but I'll answer your question later today if nobody does it before me. (It's 09:20 where I am, I should be back online at about 13:00-14:00. Please be patient.)

I can try, the begining...  :grin:

cwr said:
YES!!! I can make everything in quests, except mission templates, so that would be great. :smile:

I hope i understand the question this time  :mrgreen:

A complete quest :

a new npc

module troop
["traitor", "traitor", "traitors", tf_hero, scn_dihrim_forest|entry(2), reserved, fac_commoners, [itm_leather_boots,itm_tabard], def_attrib|level(2), wp(20), knows_inventory_management_10,  merchant_face_1, merchant_face_2 ],

make a dialogue for a npc or creat it at module_troop

after its last dialogue if it's the mayor, or a lord...You'll realize why after you come back...


  [anyone,"start", [(eq, "$g_talk_troop", "trp_your_npc_id"),
                    ],
  "I have a job for you", "next_dialogue_id", []],
 
  [anyone|plyr ,"next_dialogue_id", [], "I'm interested", "next_dialogue_id_2",[]], 
  [anyone|plyr ,"next_dialogue_id", [], "No thank you.", "close_window",[]],


  [anyone ,"next_dialogue_id_2", [],"Go to dhirim's forest and kill the traitor.", "close_window",
[
    (play_sound,"snd_start_quest"),
    (str_store_string, s2, "@I 'm going to the forest around dihirm for kill the traitor."),     
    (call_script, "script_start_quest", "qst_dhirim_quest_1", "$g_talk_troop"),     
  (party_set_flags, "p_dihrim_f", pf_disabled, 0),#enable partie and icon map (initialy disabled)
    (party_set_flags, "p_dihrim_f", pf_always_visible, 1),#enable partie and icon map (initialy disabled)
    (party_set_flags, "p_dihrim_f", pf_quest_party, 1),#change the party color by blue (quest, like in native...)
]],

yellow= npc talk
green=player talk
blue=next topic

module quest

("dhirim_quest_1", "Kill the traitor.", 0,
  "{!}None"
  ),


make a forest scene/add entry point 1 and 2


and her codes at module scene
  ("dihrim_forest",sf_generate,"none", "none", (0,0),(100,100),-100,"0x300bc5430001e0780000448a0000049f00007932",
    [],[],"outer_terrain_castle_9"),

name his sco "scn_dihrim_forest" (see a tutorial for this...)

module partie at the end

  ("dihrim_f","Forest of dhirim", icon_village_a| pf_disabled|pf_is_static|pf_always_visible|pf_hide_defenders, no_menu, pt_none, fac_neutral,0,ai_bhvr_hold,0,(80.76,38.58),[],100),

red= The location on the world map x/y
blue = initialy disabled


Module script

  # script_game_event_party_encounter:
  # This script is called from the game engine whenever player party encounters another party or a battle on the world map
  # INPUT:
  # param1: encountered_party
  # param2: second encountered_party (if this was a battle
  ("game_event_party_encounter",
  [
      (store_script_param_1, "$g_encountered_party"),
      (store_script_param_2, "$g_encountered_party_2"),# encountered_party2 is set when we come across a battle or siege, otherwise it's a negative value
#      (store_encountered_party, "$g_encountered_party"),
#      (store_encountered_party2,"$g_encountered_party_2"), # encountered_party2 is set when we come across a battle or siege, otherwise it's a minus value
      (store_faction_of_party, "$g_encountered_party_faction","$g_encountered_party"),
      (store_relation, "$g_encountered_party_relation", "$g_encountered_party_faction", "fac_player_faction"),
             
      (party_get_slot, "$g_encountered_party_type", "$g_encountered_party", slot_party_type),
      (party_get_template_id,"$g_encountered_party_template","$g_encountered_party"),
#      (try_begin),
#        (gt, "$g_encountered_party_2", 0),
#        (store_faction_of_party, "$g_encountered_party_2_faction","$g_encountered_party_2"),
#        (store_relation, "$g_encountered_party_2_relation", "$g_encountered_party_2_faction", "fac_player_faction"),
#        (party_get_template_id,"$g_encountered_party_2_template","$g_encountered_party_2"),
#      (else_try),
#        (assign, "$g_encountered_party_2_faction",-1),
#        (assign, "$g_encountered_party_2_relation", 0),
#        (assign,"$g_encountered_party_2_template", -1),
#      (try_end),

#NPC companion changes begin
      (call_script, "script_party_count_fit_regulars", "p_main_party"),
      (assign, "$playerparty_prebattle_regulars", reg0),

#        (try_begin),
#            (assign, "$player_party__regulars", 0),
#            (call_script, "script_party_count_fit_regulars", "p_main_party"),
#            (gt, reg0, 0),
#            (assign, "$player_party_contains_regulars", 1),
#        (try_end),
#NPC companion changes end


      (assign, "$g_last_rest_center", -1),
      (assign, "$talk_context", 0),
      (assign,"$g_player_surrenders",0),
      (assign,"$g_enemy_surrenders",0),
      (assign, "$g_leave_encounter",0),
      (assign, "$g_engaged_enemy", 0),
#      (assign,"$waiting_for_arena_fight_result", 0),
#      (assign,"$arena_bet_amount",0),
#      (assign,"$g_player_raiding_village",0),
      (try_begin),
        (neg|is_between, "$g_encountered_party", centers_begin, centers_end),
        (rest_for_hours, 0), #stop waiting
        (assign, "$g_infinite_camping", 0),
      (try_end),
#      (assign, "$g_permitted_to_center",0),
      (assign, "$new_encounter", 1), #check this in the menu.
      (try_begin),
        (lt, "$g_encountered_party_2",0), #Normal encounter. Not battle or siege.
        (try_begin),
          (party_slot_eq, "$g_encountered_party", slot_party_type, spt_town),
          (jump_to_menu, "mnu_castle_outside"),
        (else_try),
          (party_slot_eq, "$g_encountered_party", slot_party_type, spt_castle),
          (jump_to_menu, "mnu_castle_outside"),
        (else_try),
          (party_slot_eq, "$g_encountered_party", slot_party_type, spt_ship),
          (jump_to_menu, "mnu_ship_reembark"),
        (else_try),
          (party_slot_eq, "$g_encountered_party", slot_party_type, spt_village),
          (jump_to_menu, "mnu_village"),
        (else_try),
          (party_slot_eq, "$g_encountered_party", slot_party_type, spt_cattle_herd),
          (jump_to_menu, "mnu_cattle_herd"),
        (else_try),
          (is_between, "$g_encountered_party", training_grounds_begin, training_grounds_end),
          (jump_to_menu, "mnu_training_ground"),


      #
        (else_try),
          (eq, "$g_encountered_party", "p_dihrim_f"),
          (jump_to_menu, "mnu_dhirim_forest_m"),


module game menu

  (
    "dhirim_forest_m",0,
    "You are in the dirim forest, what you want to do ?",
    "none",
    [

        ],
    [
      ("enter.",[
          ], "enter...",
      [     
        (modify_visitors_at_site,"scn_dihrim_forest"),
          (reset_visitors),
            (set_jump_entry, 1),#player entry
            (set_visitor, 2, "trp_ traitor"),  #npc entry
      (set_jump_mission,"mt_dhirim_quest"),   
        (mission_tpl_entry_set_override_flags, "mt_dhirim_quest", 1, af_override_horse),  #if you dont want horse for thios scene...     
          (jump_to_scene, "scn_dihrim_forest"),
        (change_screen_mission),
        (music_set_situation, 0),    #if you want stop the music for start a new......ect   
        ]),

      ("leavx",[],"return...",
      [(change_screen_return),
        ]),
    ]
  ),


module mission template  :eek:

  (
    "dhirim_quest",0,-1,
    "dhirim forest",
    [
    (0,mtef_scene_source|mtef_team_0,af_override_horse,0,1,pilgrim_disguise),
    (1,mtef_scene_source|mtef_team_0,0,0,1,[]),#player entry
    (2,mtef_scene_source|mtef_team_1,af_override_horse,0,1,pilgrim_disguise),#npc entry
#add more, if you have more npc...
    ],

      [

      (ti_before_mission_start, 0, 0, [],
      [
        (call_script, "script_change_banners_and_chest"),
          (team_set_relation, 0, 1, 0),#neutral at the begining (for team 1/ team 2)
          (team_set_relation, 1, 0, 0),#

        ]),
      (ti_inventory_key_pressed, 0, 0,
      [
          (set_trigger_result,1),
        ], []),
           

      (ti_tab_pressed, 0, 0,
      [
        (try_begin),
          (eq, "$ traitor_dead", 1),
        (mission_enable_talk),#you can talk now
        (change_screen_return),
        (finish_mission),
        (else_try),
          (eq, "$traitor_dead", 0),
          (display_message, "str_cannot_leave_now"),
        (try_end),
        ],
      []),





      (1, 3, ti_once, [(main_hero_fallen,0)],#if you are dead  :sad:
      [
        (mission_enable_talk),     
        (call_script, "script_fail_quest", "qst_dhirim_quest_1"),   
        (change_screen_return),
        (try_end),
        (finish_mission),
        ]),

      (1, 3, ti_once,#if you win  :twisted: (just a team and no knocked down = it's you (the last team) = you win
      [
        (store_mission_timer_a, reg1),     
        (ge, reg1, 1),
        (num_active_teams_le, 1),
        (neg|main_hero_fallen),
        ],
      [
        (mission_enable_talk),
        (call_script, "script_succeed_quest", "qst_dhirim_quest_1"),
      (call_script, "script_end_quest", "qst_dhirim_quest_1"), 
        (assign,"$traitor_dead",1),# you can leave by "press tab"
        (display_message,"str_msg_battle_won"),     
        ]), 
               
  ],     
), 

     

blue = enry point entry...the number of your entry point  :roll: easy...

A dialogue for the  traitor on the forest scene

      [anyone,"start", [(eq, "$g_talk_troop", "trp_ traitor"),
                    ],
  "what do you want ?", "w_d_y_w", []],
 
  [anyone|plyr ,"w_d_y_w", [], "I want to kill you.", "close_window",
  [
        (team_set_relation, 0, 1, -1),  #set team 0/1 agressiveness, take a look at module mission template (team 0 =player/ 1=npc)     
        (team_set_relation, 1, 0, -1),
    (mission_disable_talk),#dont talk during a combat
    ]], 




Now, the last dialogue (for my tutorail, but 3 of 40.000 for your mod if you want a lot of quests  :lol:)

above his latest dialogue ! with a new condition...


  [anyone,"start", [
                    (eq, "$g_talk_troop", "trp_town_1_mayor"),
                    (check_quest_succeeded, "qst_dhirim_quest_1"),#the simple version for this tutorial...
                    ],
  "what new ?", "kill_responsse", []],
 
  [anyone|plyr,"kill_responsse", [], "he's dead", "kill_responsse_end",[]],

  [anyone,"kill_responsse_end", [],"Great! take this money....", "close_window",
[
(call_script, "script_troop_add_gold", "trp_player", 30000000),# :lol:
]],


######################### first dilogue ################

[anyone,"start", [(eq, "$g_talk_troop", "trp_trp_town_1_mayor"),
                    ],
  "I have a job for you", "next_dialogue_id", []],
 
  [anyone|plyr ,"next_dialogue_id", [], "I'm interested", "next_dialogue_id_2",[]], 
  [anyone|plyr ,"next_dialogue_id", [], "No thank you.", "close_window",[]],


  [anyone ,"next_dialogue_id_2", [],"Go to dhirim's forest and kill the traitor.", "close_window",
[
    (play_sound,"snd_start_quest"),
    (str_store_string, s2, "@I 'm going to the forest around dihirm for kill the traitor."),     
    (call_script, "script_start_quest", "qst_dhirim_quest_1", "$g_talk_troop"),     
  (party_set_flags, "p_dihrim_f", pf_disabled, 0),#enable partie and icon map (initialy disabled)
    (party_set_flags, "p_dihrim_f", pf_always_visible, 1),#enable partie and icon map (initialy disabled)
    (party_set_flags, "p_dihrim_f", pf_quest_party, 1),#change the party color by blue (quest, like in native...)
]],



 


edit:

Lumos said:
FantasyWarrior, please don't get offended

No,no worry, you're right  :wink:
But i hope he can help, it's a complet quest with the .py files and the method (just need to make the scenes).
But it's realy not helpfull for start modding  :???:
 
FantasyWarrior posted that while I was writing, I will not be taking his post into any consideration. FantasyWarrior, please don't get offended, but your posts that are similar to that one above are almost painful to read. I understand what you've done with your code, but damn, the way you post such "guides" is mind-numbing.
WARNING MASSIVE WALL OF TEXT INBOUND

Walking home about (EDIT: two hours and a) half an hour ago, I was thinking about writing a full-fledged tutorial about implementing a quest along with additions to nearly every file, but then I realised two things. First, this is a massive overhead and requires more time than I can spare at the moment. Secondly, I'm too short on beer for such an endeavour.
So, I decided to simply explain how triggers and mission templates work, and I'll do it in detail and with examples. So let's get started, shall we?
- (Simple) Triggers:
There are two types of triggers in M&B: Regular triggers and simple triggers. We'll begin with the simple triggers, because they're generally smaller and easier to understand.
Before that though, what is a trigger? A trigger is a block of code that executes multiple times as the game progresses. It's called a trigger, because it fires - that's how it's called when the time comes for the trigger to do its job.

Simple triggers:
Simple triggers are generally found in module_simple_triggers.py and despite being... well, simpler, they're not to be underestimated. Let's have a look at a simple trigger and then explain what does what:
Code:
(24, [
	(troop_add_gold, "trp_player", 100),
  ]),
This is rather simple, isn't it? Every 24 hours, this trigger will give 100 gold to the player. Yes, it makes no sense, but it works. And that's basically how every simple trigger operates. Here's the structure:
Code:
[color=navy](check_interval, [ operations_block ]),[/color]
This is shared by each and every simple trigger, including the gold-giving one we've got above. Now let's look at the components: check_interval is how frequently this trigger will be checked, measured in in-game hours. Using 24 will make the trigger fire once every day, using 1 will make it fire 24 times per day.
NB: Using 0 as a check interval will make the trigger fire once every frame, i.e. a lot of times per second, dependent on the user's frame rate. Such triggers are potential performance hogs, so be cautious when using them.
The operations block is what happens when the trigger fires, and can contain whatever codes you want to place in it. Yes, checks are allowed. For an example, we can enhance our aforementioned code by doing this:
Code:
(24, [
	# (try_begin), # We don't need try blocks right now
	(lt, "$player_honor", 0),
	(troop_add_gold, "trp_player", 100),
	# (try_end),
  ]),
Now it will give a hundred gold per day to the player, if he/she is dishonourable. It makes even less sense now, but whatever. As you can see, a trigger can fail with no problems whatsoever, however be careful when not wrapping statements in try_ blocks. Of course, it's always safer to use the try blocks, just in case.
Code:
(24, [
	(try_begin), # Better safe than sorry
		(lt, "$player_honor", 0), # Make sure your indentation is always correct!
		(troop_add_gold, "trp_player", 100), # Tabs don't look so huge in the text editors, only here on the forum.
	(try_end),
  ]),
Right, so we've got the basics covered now. There are more things you need to know though. Simple triggers are also used in other places, such as on items and scene props, but with special conditions, for an example:
Code:
["flintlock_pistol", "Flintlock Pistol", [("flintlock_pistol",0)], itp_type_pistol|itp_merchandise|itp_primary, itcf_shoot_pistol|itcf_reload_pistol, 230, weight(1.5)|difficulty(0)|spd_rtng(38)|shoot_speed(160)|thrust_damage(10, pierce)|max_ammo(1)|accuracy(65), imodbits_none, [ # A comma is always followed by a spacebar, as your friendly schoolbooks teach you
  (ti_on_weapon_attack, [
	(play_sound,"snd_pistol_shot"),
	(position_move_x, pos1,27),
	(position_move_y, pos1,36),
	(particle_system_burst, "psys_pistol_smoke", pos1, 15) # The last line in a field can remain without a comma, but be careful when adding more lines later
  ])]],
Code:
  ("catapult_destructible", sokf_moveable|sokf_show_hit_point_bar|sokf_destructible, "Catapult", "bo_Catapult", [
   (ti_on_init_scene_prop, [
	(store_trigger_param_1, ":instance_no"),
	(scene_prop_set_hit_points, ":instance_no", 1600),
    ]),
   # Other triggers omitted for clarity
    ]),
As you can see, these two examples use respectively
Code:
[color=navy]ti_on_weapon_attack[/color]
and
Code:
[color=navy]ti_on_init_scene_prop[/color]
. which are hard-coded conditions passed by the engine at the right times. A list of all such "special" check intervals can be found in header_triggers.py.

This about sums up everything related to simple triggers, now let's move on to...

Triggers:
The regular triggers, called only "triggers" are a bit more complex and versatile than their simpler counterparts, but are largely the same. These triggers are more important, however, because they are used in the mission templates, which we'll talk about afterwards.
Let's examine the structure of a trigger:
Code:
(check_interval, delay_interval, re-arm_inverval, [ conditions_block], [ operations_block ]),
As you can see, there're more fields present here than there were above. Now let's examine them one by one.
- The check_interval is absolutely the same as before - how often the trigger fires;
- The delay_interval is how much the consequences should be delayed once the conditions are true;
- The re-arm_interval is how long should the trigger remain inactive once the consequences are applied;
- The conditions_block contains the code that needs to be checked in order to allow for the consequences to fire;
- The consequences_block is where the majority of your ocde is usually located, it will be executed once the conditions are evaluated to true and the delay_interval wears off.
Now, how would our senseless trigger from above look like?
Code:
(24, 0, 0, [], [
	(try_begin),
		(lt, "$player_honor", 0),
		(troop_add_gold, "trp_player", 100),
	(try_end),
  ]),
This is perfectly valid, but it's frankly kind of stupid if we're going to use a regular trigger. Let's buff up the rewards and rework the code a bit in order to make use of the systems that this trigger allows us:
Code:
(24, 6, 48, [
	(lt, "$player_honor", 0),
  ], [
	(troop_add_gold, "trp_player", 400),
  ]),
Now, every 24 hours this trigger will evaluate the player's honour. If it's below zero, six hours will pass, keeping the player on edge (okay, not really), and then he or she will be awarded four hundred gold. However, the trigger will not fire for the next 48 hours, which kind of compensates for the greater reward.
Yes, the trigger is still dumb, but serves as a nice example.
Regular triggers also have their special conditions, most of which related to missions -
Code:
ti_before_mission_start
,
Code:
ti_on_agent_spawn
and so on, once again listed in header_triggers.py.

NB: Local variables are not transferred between conditions and consequences. In other words, you'll need to store a variable again to modify it in the consequences if you've already stored it to check it.

NB: When dealing with triggers with special conditions, you are likely to need to check their parameters using the
Code:
(store_trigger_param)
operation. Consult header_triggers.py for a list of parameters for each trigger.


I hope you've learned something. If you haven't, I'm sorry.

Now, we'll take a look at...
- Mission templates
First of all, you need to understand one simple concept - that a mission template is largely a template to be used for similar missions. A mission is any occasion that you're controlling your character in. Mission templates provide different functions through trigger usage and are pretty important, being the second required component of a mission (the other one is a scene for them ission to play in). They are usually accessed through a menu with the
Code:
(set_jump_mission, "mt_mission_template"), (jump_to_scene, "scn_selected_scene"), (change_screen_mission),
set of commands.
A mission template's structure is a lot more complex than a trigger, and contains lists of objects such as triggers. Let us examine a mission template:
Code:
(mission_template_id, flags, type, useless_text, [ spawn_records ], [ triggers ]),
- The mission_template_id is what you're going to be referencing this mission template with;
- The flags are just that - flags. Look in header_mission_templates.py for a list of flags,  leave it a zero when you've not got any special conditions;
- The type is a special value that is usually -1, you're unlikely to need to change it;
- The useless_text is a mission template's description, which serves absolutely no purpose. I guess you could use it to describe stuff for yourself, but I believe it only takes up space;
- The spawn_records is a list of spawn points and conditions for them;
- The triggers is a list of triggers, much like the ones we discussed above.

First of all, we have to look through the structure of each spawn record and see what they're made of.
Code:
(entry_id, spawn_flags, alter_flags, ai_flags, num_troops, [ equipment_list ]),
- The entry_id is the spawn point number which the troops from this record will use;
- The spawn_flags are flags that dictate something about the spawning - like
Code:
[color=navy]mtef_team_0[/color]
and so on;
- The alter_flags are flags that say what equipment should the agents NOT spawn with - for an example,
Code:
af_override_horse
or
Code:
af_override_all
- The ai_flags are flags that will give the AI agents spawned from this record a specific behavour. Usually used with
Code:
aif_start_alarmed
;
- The num_troops is how many agents should spawn from this record;
- The equipment_list is a maximum of items that will be added to the agent's inventory, eight at max. Overriding all and adding the pilgrim disgiuse in the equipment_list results in the player being disguised while "fooling the town guards".

Let's make a dummy mission template, so we can talk about stuff. Consider this:
Code:
   ("useless_template",0,-1, "Nothing to see here", [
	(0, mtef_visitor_source|mtef_team_0, af_override_fullhelm, aif_start_alarmed, 1, []),
	(1, mtef_visitor_source|mtef_team_1, af_override_fullhelm, aif_start_alarmed, 1, []),
     ], [
	(ti_on_agent_spawn, 0, 0, [], [
		(display_message, "@Agent spawned"),
	]),

	(ti_on_agent_killed_or_wounded, 0, 0, [], [
		(store_trigger_param, ":dead_agent_id", 1),
		(agent_get_troop_id, ":troop", ":dead_agent_id"),
		(str_store_troop_name, s1, ":troop"),
		(display_message, "@{s1} died a gruesome death. Or was knocked unconsious, we're not checking that."),
	]),

	# Health regen for the player
	(1, 0, 0, [
		(neg|main_hero_fallen),
		(get_player_agent_no, ":agent"),
		(agent_is_alive, ":agent"),
	      ], [
		(get_player_agent_no, ":agent"), # Local variables are not transferred between conditions and consequences
		(store_agent_hit_points, ":health", ":agent", 1),
		(val_add, ":health", 1),
		(agent_set_hit_points, ":agent", ":health", 1),
	]),

    ]),
In this mission template, two agents on two different teams are going to spawn, and they'll spawn without helmets. Upon their spawning, two "Agent spawned" messages will roll out, and when one dies you will be notified by another message. On top of all that, you will regenerate health wat a rate of 1 HP/second (which is quite overpowered).
As you can see, this mission template contains two spawn records and three triggers. The
Code:
mtef_visitor_source
will allow for agents to spawn through the usage of
Code:
(modify_visitors_at_site, "scn_current_scene"), (set_visitor, entry_point_number, "trp_whatever"),
while
Code:
mtef_scene_source
... I've got no idea what it does. Feel free to experiment.
The triggers here are pretty self-explanatory, I reckon.

And given that I've wasted too much time already on this, I'll have to wrap it up here. The best advice I could give you is to LOOK at the files and see how things are already done. Then you'll understand how to do them yourself.
Hope this helps. If it doesn't, I won't write another one.
 
Somebody said:
xPearse said:
I have been setting up units for multiplayer and for some reason I can't select troops for faction 3 and 4. Any reason why this would happen.
Did you give the troops the proper factions and differentiate them from the bot versions?

Yea just looked over the troops after I posted and noticed that they weren't set to the right faction,  Oops.
 
i ran into a problem...i have this code
Code:
(set_show_messages,0),
(display_log_message,"@{s1} with id {reg1} connected!"),
(set_show_messages,1),
(display_message,"@{s1} just connected!",0xFFFF00),

in my code, the first 3 lines writes that string into rgl_log.txt, and it is not shown in game(wich is good). the 4 line should show me that player_x just connected!, wich is also stored in rgl_log.txt, and here the strange things comes in and the s1 content is modified. i tested this with my friend, his name is Aratar1 , in rgl_log.txt this line is wrote " Aratar1 with id 2 connected!" , wich is good, but in game i get this message "March 23, 1257 just connected!". how can i resolve this? is this warbands engine fault?

here are the lines in rgl_log.txt
Code:
Aratar1 with id 2 connected!
 March 23, 1257 just connected!
first one is only written in the txt file, and the second one is shown in game.
 
Lumos said:
FantasyWarrior posted that while I was writing, I will not be taking his post into any consideration. FantasyWarrior, please don't get offended, but your posts that are similar to that one above are almost painful to read. I understand what you've done with your code, but damn, the way you post such "guides" is mind-numbing.
WARNING MASSIVE WALL OF TEXT INBOUND

Walking home about (EDIT: two hours and a) half an hour ago, I was thinking about writing a full-fledged tutorial about implementing a quest along with additions to nearly every file, but then I realised two things. First, this is a massive overhead and requires more time than I can spare at the moment. Secondly, I'm too short on beer for such an endeavour.
So, I decided to simply explain how triggers and mission templates work, and I'll do it in detail and with examples. So let's get started, shall we?
- (Simple) Triggers:
There are two types of triggers in M&B: Regular triggers and simple triggers. We'll begin with the simple triggers, because they're generally smaller and easier to understand.
Before that though, what is a trigger? A trigger is a block of code that executes multiple times as the game progresses. It's called a trigger, because it fires - that's how it's called when the time comes for the trigger to do its job.

Simple triggers:
Simple triggers are generally found in module_simple_triggers.py and despite being... well, simpler, they're not to be underestimated. Let's have a look at a simple trigger and then explain what does what:
Code:
(24, [
	(troop_add_gold, "trp_player", 100),
  ]),
This is rather simple, isn't it? Every 24 hours, this trigger will give 100 gold to the player. Yes, it makes no sense, but it works. And that's basically how every simple trigger operates. Here's the structure:
Code:
[color=navy](check_interval, [ operations_block ]),[/color]
This is shared by each and every simple trigger, including the gold-giving one we've got above. Now let's look at the components: check_interval is how frequently this trigger will be checked, measured in in-game hours. Using 24 will make the trigger fire once every day, using 1 will make it fire 24 times per day.
NB: Using 0 as a check interval will make the trigger fire once every frame, i.e. a lot of times per second, dependent on the user's frame rate. Such triggers are potential performance hogs, so be cautious when using them.
The operations block is what happens when the trigger fires, and can contain whatever codes you want to place in it. Yes, checks are allowed. For an example, we can enhance our aforementioned code by doing this:
Code:
(24, [
	# (try_begin), # We don't need try blocks right now
	(lt, "$player_honor", 0),
	(troop_add_gold, "trp_player", 100),
	# (try_end),
  ]),
Now it will give a hundred gold per day to the player, if he/she is dishonourable. It makes even less sense now, but whatever. As you can see, a trigger can fail with no problems whatsoever, however be careful when not wrapping statements in try_ blocks. Of course, it's always safer to use the try blocks, just in case.
Same but fixed:
Code:
(24, [
	(try_begin), # Better safe than sorry
		(lt, "$player_honor", 0), # Make sure your indentation is always correct!
		(troop_add_gold, "trp_player", 100), # Tabs don't look so huge in the text editors, only here on the forum.
	(try_end),
  ]),
Right, so we've got the basics covered now. There are more things you need to know though. Simple triggers are also used in other places, such as on items and scene props, but with special conditions, for an example:
Code:
["flintlock_pistol", "Flintlock Pistol", [("flintlock_pistol",0)], itp_type_pistol|itp_merchandise|itp_primary, itcf_shoot_pistol|itcf_reload_pistol, 230, weight(1.5)|difficulty(0)|spd_rtng(38)|shoot_speed(160)|thrust_damage(10, pierce)|max_ammo(1)|accuracy(65), imodbits_none, [ # A comma is always followed by a spacebar, as your friendly schoolbooks teach you
  (ti_on_weapon_attack, [
	(play_sound,"snd_pistol_shot"),
	(position_move_x, pos1,27),
	(position_move_y, pos1,36),
	(particle_system_burst, "psys_pistol_smoke", pos1, 15) # The last line in a field can remain without a comma, but be careful when adding more lines later
  ])]],
Code:
  ("catapult_destructible", sokf_moveable|sokf_show_hit_point_bar|sokf_destructible, "Catapult", "bo_Catapult", [
   (ti_on_init_scene_prop, [
	(store_trigger_param_1, ":instance_no"),
	(scene_prop_set_hit_points, ":instance_no", 1600),
    ]),
   # Other triggers omitted for clarity
    ]),
As you can see, these two examples use respectively
Code:
[color=navy]ti_on_weapon_attack[/color]
and
Code:
[color=navy]ti_on_init_scene_prop[/color]
. which are hard-coded conditions passed by the engine at the right times. A list of all such "special" check intervals can be found in header_triggers.py.

This about sums up everything related to simple triggers, now let's move on to...

Triggers:
The regular triggers, called only "triggers" are a bit more complex and versatile than their simpler counterparts, but are largely the same. These triggers are more important, however, because they are used in the mission templates, which we'll talk about afterwards.
Let's examine the structure of a trigger:
Code:
(check_interval, delay_interval, re-arm_inverval, [ conditions_block], [ operations_block ]),
As you can see, there're more fields present here than there were above. Now let's examine them one by one.
- The check_interval is absolutely the same as before - how often the trigger fires;
- The delay_interval is how much the consequences should be delayed once the conditions are true;
- The re-arm_interval is how long should the trigger remain inactive once the consequences are applied;
- The conditions_block contains the code that needs to be checked in order to allow for the consequences to fire;
- The consequences_block is where the majority of your ocde is usually located, it will be executed once the conditions are evaluated to true and the delay_interval wears off.
Now, how would our senseless trigger from above look like?
Code:
(24, 0, 0, [], [
	(try_begin),
		(lt, "$player_honor", 0),
		(troop_add_gold, "trp_player", 100),
	(try_end),
  ]),
This is perfectly valid, but it's frankly kind of stupid if we're going to use a regular trigger. Let's buff up the rewards and rework the code a bit in order to make use of the systems that this trigger allows us:
Code:
(24, 6, 48, [
	(lt, "$player_honor", 0),
  ], [
	(troop_add_gold, "trp_player", 400),
  ]),
Now, every 24 hours this trigger will evaluate the player's honour. If it's below zero, six hours will pass, keeping the player on edge (okay, not really), and then he or she will be awarded four hundred gold. However, the trigger will not fire for the next 48 hours, which kind of compensates for the greater reward.
Yes, the trigger is still dumb, but serves as a nice example.
Regular triggers also have their special conditions, most of which related to missions -
Code:
ti_before_mission_start
,
Code:
ti_on_agent_spawn
and so on, once again listed in header_triggers.py.

NB: Local variables are not transferred between conditions and consequences. In other words, you'll need to store a variable again to modify it in the consequences if you've already stored it to check it.

NB: When dealing with triggers with special conditions, you are likely to need to check their parameters using the
Code:
(store_trigger_param)
operation. Consult header_triggers.py for a list of parameters for each trigger.


I hope you've learned something. If you haven't, I'm sorry.

Now, we'll take a look at...
- Mission templates
First of all, you need to understand one simple concept - that a mission template is largely a template to be used for similar missions. A mission is any occasion that you're controlling your character in. Mission templates provide different functions through trigger usage and are pretty important, being the second required component of a mission (the other one is a scene for them ission to play in). They are usually accessed through a menu with the
Code:
(set_jump_mission, "mt_mission_template"), (jump_to_scene, "scn_selected_scene"), (change_screen_mission),
set of commands.
A mission template's structure is a lot more complex than a trigger, and contains lists of objects such as triggers. Let us examine a mission template:
Code:
(mission_template_id, flags, type, useless_text, [ spawn_records ], [ triggers ]),
- The mission_template_id is what you're going to be referencing this mission template with;
- The flags are just that - flags. Look in header_mission_templates.py for a list of flags,  leave it a zero when you've not got any special conditions;
- The type is a special value that is usually -1, you're unlikely to need to change it;
- The useless_text is a mission template's description, which serves absolutely no purpose. I guess you could use it to describe stuff for yourself, but I believe it only takes up space;
- The spawn_records is a list of spawn points and conditions for them;
- The triggers is a list of triggers, much like the ones we discussed above.

First of all, we have to look through the structure of each spawn record and see what they're made of.
Code:
(entry_id, spawn_flags, alter_flags, ai_flags, num_troops, [ equipment_list ]),
- The entry_id is the spawn point number which the troops from this record will use;
- The spawn_flags are flags that dictate something about the spawning - like
Code:
[color=navy]mtef_team_0[/color]
and so on;
- The alter_flags are flags that say what equipment should the agents NOT spawn with - for an example,
Code:
af_override_horse
or
Code:
af_override_all
- The ai_flags are flags that will give the AI agents spawned from this record a specific behavour. Usually used with
Code:
aif_start_alarmed
;
- The num_troops is how many agents should spawn from this record;
- The equipment_list is a maximum of items that will be added to the agent's inventory, eight at max. Overriding all and adding the pilgrim disgiuse in the equipment_list results in the player being disguised while "fooling the town guards".

Let's make a dummy mission template, so we can talk about stuff. Consider this:
Code:
   ("useless_template",0,-1, "Nothing to see here", [
	(0, mtef_visitor_source|mtef_team_0, af_override_fullhelm, aif_start_alarmed, 1, []),
	(1, mtef_visitor_source|mtef_team_1, af_override_fullhelm, aif_start_alarmed, 1, []),
     ], [
	(ti_on_agent_spawn, 0, 0, [], [
		(display_message, "@Agent spawned"),
	]),

	(ti_on_agent_killed_or_wounded, 0, 0, [], [
		(store_trigger_param, ":dead_agent_id", 1),
		(agent_get_troop_id, ":troop", ":dead_agent_id"),
		(str_store_troop_name, s1, ":troop"),
		(display_message, "@{s1} died a gruesome death. Or was knocked unconsious, we're not checking that."),
	]),

	# Health regen for the player
	(1, 0, 0, [
		(neg|main_hero_fallen),
		(get_player_agent_no, ":agent"),
		(agent_is_alive, ":agent"),
	      ], [
		(get_player_agent_no, ":agent"), # Local variables are not transferred between conditions and consequences
		(store_agent_hit_points, ":health", ":agent", 1),
		(val_add, ":health", 1),
		(agent_set_hit_points, ":agent", ":health", 1),
	]),

    ]),
In this mission template, two agents on two different teams are going to spawn, and they'll spawn without helmets. Upon their spawning, two "Agent spawned" messages will roll out, and when one dies you will be notified by another message. On top of all that, you will regenerate health wat a rate of 1 HP/second (which is quite overpowered).
As you can see, this mission template contains two spawn records and three triggers. The
Code:
mtef_visitor_source
will allow for agents to spawn through the usage of
Code:
(modify_visitors_at_site, "scn_current_scene"), (set_visitor, entry_point_number, "trp_whatever"),
while
Code:
mtef_scene_source
... I've got no idea what it does. Feel free to experiment.
The triggers here are pretty self-explanatory, I reckon.

And given that I've wasted too much time already on this, I'll have to wrap it up here. The best advice I could give you is to LOOK at the files and see how things are already done. Then you'll understand how to do them yourself.
Hope this helps. If it doesn't, I won't write another one.


THANK YOU!!! :grin:


That was exactly what I needed. :smile: You should post that in unofficial tutorials, seriously. That was really helpful. :smile:
 
Hi fellas, I have a one quick question for all the map makers out there. How do I enable AI mesh face displaying? AI mesh looks like this to me:

LLctBVx.jpg

Which is very, very annoying, because edges and vertexes can't tell me where the faces are. I've checked the editor options - none of them solve this. I will be thankful for any advices.
 
Code:
    ("beacon_fire_big", psf_billboard_3d|psf_global_emit_dir|psf_always_emit|psf_randomize_size|psf_randomize_rotation, "prt_mesh_fire_1",
     30, 1.0, 0, -1.2, 10.0, 5.0,     #num_particles, life, damping, gravity_strength, turbulance_size, turbulance_strength
     (0.2, 0.7), (1, 0),        #alpha keys
     (0.2, 1.0), (1, 0.9),      #red keys
     (0.2, 0.7),(1, 0.3),       #green keys
     (0.2, 0.2), (1, 0.0),      #blue keys
     (0, 1),   (1, 1),          #scale keys
     (1, 1, 0.5),        #emit box size
     (0, 0, 0.0),               #emit velocity
     0.0,                       #emit dir randomness
     250,                       #rotation speed
     0.3                        #rotation damping
Which of these values controls the height of a particle?

Hi fellas, I have a one quick question for all the map makers out there. How do I enable AI mesh face displaying? AI mesh looks like this to me:

(click to show/hide)

Which is very, very annoying, because edges and vertexes can't tell me where the faces are. I've checked the editor options - none of them solve this. I will be thankful for any advices.
Does "Create new face" show the same problem?
 
Hey all. I'm wondering if it is possible to add a poison type effect to weapons. For example, the first hit inflicts 25 damage, and then it deals an additional 25 damage over 10 seconds. Is it possible? If so, where do I need to go to add it?

Thanks.
 
Is it possible to add vertex animations to scene props? I've made a Ballista over the framework of the cannons in the Napoleonic Wars DLC, but unfortunately although it is working great in every other way, I can't figure out a way to make the limbs and string move back as you cock it.

 
Hartzekar said:
Hey all. I'm wondering if it is possible to add a poison type effect to weapons. For example, the first hit inflicts 25 damage, and then it deals an additional 25 damage over 10 seconds. Is it possible? If so, where do I need to go to add it?

Thanks.

It's possible. You'll need to edit mission_templates and add a ti_on_agent_hit trigger, detect if the weapon is poison and (after defining it in module_constants) set (or add, if you want it to stack) slot_agent_poisoned to 10, then make another trigger that runs every 1 second, loops through all the agents and if the agent is poisoned deal some damage and reduce slot_agent_poisoned by 1. You'll have to do slightly more if you have multiple weapons with different poison effects.

Take a look at Lumos's's earlier post (:wink:) regarding triggers if you don't know about them.

Quintillius said:
Code:
    ("beacon_fire_big", psf_billboard_3d|psf_global_emit_dir|psf_always_emit|psf_randomize_size|psf_randomize_rotation, "prt_mesh_fire_1",
     30, 1.0, 0, -1.2, 10.0, 5.0,     #num_particles, life, damping, gravity_strength, turbulance_size, turbulance_strength
     (0.2, 0.7), (1, 0),        #alpha keys
     (0.2, 1.0), (1, 0.9),      #red keys
     (0.2, 0.7),(1, 0.3),       #green keys
     (0.2, 0.2), (1, 0.0),      #blue keys
     (0, 1),   (1, 1),          #scale keys
     (1, 1, 0.5),        #emit box size
     (0, 0, 0.0),               #emit velocity
     0.0,                       #emit dir randomness
     250,                       #rotation speed
     0.3                        #rotation damping
Which of these values controls the height of a particle?

I don't believe its possible to stretch particles, its size must remain relative to its original one. You'll need to edit the particle and change the height manually.
 
Willhelm said:
Is it possible to add vertex animations to scene props? I've made a Ballista over the framework of the cannons in the Napoleonic Wars DLC, but unfortunately although it is working great in every other way, I can't figure out a way to make the limbs and string move back as you cock it.
It may works with the WSE operation
Code:
(prop_instance_set_vertex_keys_time_point, <prop_instance_no>, <time_point>), #Sets <prop_instance_no>'s mesh vertex keys time point to <time_point>
but I havent tried it out yet.

Another way is to do it with vertex shaders somehow.
 
cwr said:
rt_bridge.

Bridges are just map icons placed over that, so it looks realistic. :smile:

Ugh, when I saw a gap between rt_desert and rt_bridge I assumed that was where rt_ford used to be. Thanks, texture is map_bridge.dds in materials.brf
 
I searched for a while, so, apologies if I missed this. Feel free to tell me where it is.

I was doing literally the simplest thing to one of my mods (adding a single troop) and it was working totally fine until I did so. Now I get this:

Code:
Traceback (most recent call last):
  File "process_init.py", line 2, in <module>
    from process_operations import *
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Traceback (most recent call last):
  File "process_global_variables.py", line 12, in <module>
    from process_operations import *
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Exporting strings...
Exporting skills...
Exporting tracks...
Exporting animations...
Exporting meshes...
Exporting sounds...
Exporting skins...
Traceback (most recent call last):
  File "process_map_icons.py", line 6, in <module>
    from process_operations import *
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Exporting faction data...
Exporting item data...
Traceback (most recent call last):
  File "process_items.py", line 66, in <module>
    from process_operations import *
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Exporting scene data...
Traceback (most recent call last):
  File "process_scenes.py", line 15, in <module>
    from process_operations import *
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Traceback (most recent call last):
  File "process_troops.py", line 4, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Exporting particle data...
Traceback (most recent call last):
  File "process_scene_props.py", line 7, in <module>
    from process_operations import *
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Traceback (most recent call last):
  File "process_tableau_materials.py", line 8, in <module>
    from process_operations import *
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Traceback (most recent call last):
  File "process_presentations.py", line 8, in <module>
    from process_operations import *
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Exporting party_template data...
Traceback (most recent call last):
  File "process_parties.py", line 6, in <module>
    from process_operations import *
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Exporting quest data...
Exporting info_page data...
Traceback (most recent call last):
  File "process_scripts.py", line 7, in <module>
    from process_operations import *
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Traceback (most recent call last):
  File "process_mission_tmps.py", line 8, in <module>
    from process_operations import *
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Traceback (most recent call last):
  File "process_game_menus.py", line 8, in <module>
    from process_operations import *
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Traceback (most recent call last):
  File "process_simple_triggers.py", line 5, in <module>
    from process_operations import *
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Traceback (most recent call last):
  File "process_dialogs.py", line 9, in <module>
    from process_operations import *
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Traceback (most recent call last):
  File "process_global_variables_unused.py", line 3, in <module>
    from process_operations import*
  File "C:\Program Files (x86)\Module_system 1.158\process_operations.py", line
14, in <module>
    from module_troops import *
  File "C:\Program Files (x86)\Module_system 1.158\module_troops.py", line 2139
    upgrade2(troops,"watchman","caravan_guard","mercenary_crossbowman")
           ^
SyntaxError: invalid syntax
Exporting postfx_params...
 
Status
Not open for further replies.
Back
Top Bottom