+- +-


Welcome, Guest.
Please login or register.

Login with your social network

Forgot your password?

+-Stats ezBlock

Total Members: 31
Latest: vicky007
New This Month: 0
New This Week: 0
New Today: 0
Total Posts: 2404
Total Topics: 59
Most Online Today: 2
Most Online Ever: 101
(October 22, 2023, 02:07:38 pm)
Users Online
Members: 0
Guests: 2
Total: 2

Author Topic: Making A Quest (By Lumos)  (Read 587 times)

0 Members and 0 Guests are viewing this topic.

Offline Michadr

  • Perisno Lead Developer
  • Administrator
  • Squire
  • *
  • Posts: 668
  • Karma: +11/-0
  • Gender: Male
  • Location: USA
    • View Profile
Making A Quest (By Lumos)
« on: August 30, 2013, 07:35:31 pm »
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: [Select]
(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: (check_interval, [ operations_block ]),
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: [Select]
(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
Spoiler (hover to show)

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: [Select]
["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, [
(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: [Select]
("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 ti_on_weapon_attack and ti_on_init_scene_prop. 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...

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:
(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: [Select]
(24, 0, 0, [], [
(lt, "$player_honor", 0),
(troop_add_gold, "trp_player", 100),

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:

Much Better:
Code: [Select]
(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 - ti_before_mission_start, 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 (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 (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:
(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.
(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 mtef_team_0 and so on;
- The alter_flags are flags that say what equipment should the agents NOT spawn with - for an example, af_override_horse or af_override_all
- The ai_flags are flags that will give the AI agents spawned from this record a specific behavour. Usually used with 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 disguise 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: [Select]
("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, [
(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 mtef_visitor_source will allow for agents to spawn through the usage of (modify_visitors_at_site, "scn_current_scene"), (set_visitor, entry_point_number, "trp_whatever"), while 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.
« Last Edit: October 07, 2013, 01:44:05 am by Michadr »

Share on Facebook Share on Twitter


+-Recent Topics

Erotic Escorts and Get in touch with Lady in Udaipur by vicky007
October 28, 2020, 01:06:33 am

Talesworld Board by Michadr
September 30, 2013, 06:30:21 pm

Rate the song above you by habeo
September 10, 2013, 12:02:55 pm

Stuff in development [items] by Michadr
September 05, 2013, 07:38:59 pm

Suggestions Thread by habeo
September 01, 2013, 11:51:47 am

Making A Quest (By Lumos) by Michadr
August 30, 2013, 07:35:31 pm

Bug Report Thread by Michadr
August 29, 2013, 03:09:59 am

Modding Tools/ Links by Michadr
August 28, 2013, 11:03:29 pm

Factions by habeo
August 27, 2013, 09:02:01 pm

Other Games You Play by Zephilinox
August 27, 2013, 02:31:10 pm