Jump to content

Technical Triggers discussion


Recommended Posts

Here, I'd like to discuss triggers (http://trac.wildfiregames.com/ticket/52). The work started by Spahbod, but I've taken over, and redesigned big parts of it.

First of all, triggers need to have a big freedom. So in its basic form, triggers are just a script (or multiple scripts) the map loads when all entities and components are initialised. From that point on. Triggers can modify existing components, subscribe for messages, schedule functions for later execution and all stuff you like to imagine.

Of course, such freedom is hard to handle. For example. If the triggers need a state to save (and most do), they need to serialize that state to support rejoining in network games and saved games. We'd also like to keep our maps more or less compatible with next versions. So triggers shouldn't modify too much in the simulation either.

So there is a special component (the Trigger component) made to be extended by triggers.

Functionality in the Trigger component

The Trigger component also offers some basic functionality to triggers. It has 3 important functions: RegisterTrigger, EnableTrigger and DisableTrigger. Triggers are a combination of an event on which they're fired, an action to execute, and possibly extra data.

There already are a number of predefined events, But they're handled differently in the background. Some events are handled by the Trigger component listening to messages, other events require other parts of the simulation code to warn the Trigger component. The events are made extendible. So we can always add new ones when needed.

The action is the functionname defined under the extension of the Trigger component.

As part of a "keep it simple" exercise, the combination of event and action has to be unique. So all sorts of triggers can be enabled and disabled without extra keys. This does limit the triggers a bit, as f.e. the repeat time of an interval trigger is part of the data. So there can only be one trigger with "OnInterval" as event and a certain function as action. But it should make it easier if we ever try to make a trigger editor when we have a basic interface.

Of course, these limitations are only limitations in the interface of the Triggers component. As the code is completely part of the simulation. You can just call the timer component directly, and register your timers there. But this will require you to keep a key for that timer, in order to disable it again. So there goes simplicity.

If we ever want to have a visual trigger editor (maybe something based on Scratch - http://wiki.scratch.mit.edu), we should have an interface that's as simple as possible.

Trigger points

Another thing added are trigger points. Those will be markers, only visible in Atlas, that can be used in triggers to define positions on the map (without having to calculate coordinates). A trigger point has a reference (A, B, C, ...), and all trigger points with a certain reference can be queried from the Trigger component.

Trigger points can be used to spawn units. To give as a target position, ... Currently, they're also the only way to support range triggers. When you register a range trigger in the Trigger component, the Trigger component passes it on to the matching TriggerPoint components. So that component will listen to the OnRange messages (which is a lot cheaper than listening to all range change messages), and will execute the action for it.

It could also be extended to territory events (i.e. the TriggerPoint executing an action when the territory under it changed).

Trigger points also have an owner. So you won't run out of trigger points very quickly, as you can make a difference between trigger point A for player 1 and for player 2.

(De)Serialization (saved games)

By extending the Trigger component. There are no problems at all with serialisation. All functions should be defined under the Trigger prototype. Like

Trigger.prototype.MyFirstAction = function() {/* Do something here */};

Those will not be serialised, but rather be reloaded when loading the game. So they should not have a state (i.e. not change throughout the game).

For saving states, that can just be done as with all other components. By using the "this" keyword in functions registered under the Trigger component. F.e.

Trigger.prototype.MyAction = function(){    this.myState = "start";};

When serialising the Trigger component, they get serialised with it.

Helper functions

Something I'm still unsure about is the filesystem organisation. Map triggers can be placed anywhere in mod/maps/. As I'm now imagining it, a map with triggers should have one map-specific script (probably having the same base name as the xml and pmp files, and being in the same directory). That specific script could do actions on specific entities of a map. And then, there could be multiple helper scripts in maps/scripts. Those scripts could be added when needed, and provide small to big utility functions, s.a. getting the owner of an entity to spawning units from a certain trigger point, to really complicated, but still general stuff. Those helper scripts won't be loaded by default, but should probably be organised per topic. So if a map-specific trigger wants to use a method from those helpers, it can just include those helpers.

I hope, with the current design, we keep the simple cases simple (so many people can make triggers), but we also allow for great customisability of maps.

  • Like 3
Link to comment
Share on other sites

The first thing I thought about was how triggers are assigned to maps and how tightly/loosely they should be tied to maps. Victory conditions could be implemented with triggers for example. There are well known victory conditions such as wonder, king of the hill, regicide, protecting the wonder etc.

When I thought more about it, I figured maps should be more loosely tied to mission scripts (scripts containing triggers). I've made up some terms to describe what I mean...

Term: Generic missions

Victory conditions are basically just specific cases of small missions. For example, your first task is to collect enough resources, the second is to build a wonder and the third is to protect it long enough. So instead of calling them victory conditions, we could also call it "generic missions" and include special scripted behaviour that does not lead to victory (like a mode that gives you resources for each temple you build). Generic is referring to the map in this case and would mean that triggers only refer to things that can be done on any map or nearly any map. Again, the wonder victory condition would work for almost any game and could be implemented as generic mission (it won't work if you only have one hero on a map for example).

Generic missions could be an easy way to provide customized gameplay for a large quantity of maps. Of course we could still separate the missions in the GUI into "generic missions" and "victory conditions" even if they are handled the same way in the background.

Term: Flexible missions

There are many other possibilities of generic missions, but they are very limited at the same time. They would be much more powerful if it was possible to define some requirements for the map without tying them to a specific map. I'll call this concept "flexible missions".

Flexible missions contain a requirement definition that can be validated on the gamesetup screen to show available maps for the mission script or available mission scripts for a map. Such requirements could be:

  • Each player has at least one building of type X at the beginning
  • There's a trigger point with the name "InvadingArmy1Spawn" on the map (extend trigger points with a name?)
  • There are at least 5 entities of the type "relic" on the map
  • There's a trigger point with the name "KingOfTheHillLocation"

Instead of listing requirements it would probably be better to pass map data and provide a function that checks that for requirements, but that's an implementation detail.

Also generic missions most likely aren't needed as a separate implementations if flexible missions are implemented.

Term Scenario missions

Scenario missions would be the type of mission that only makes sense with a specific map and isn't worth to be implemented as flexible mission.

I'd like to avoid getting stuck because of too many ideas and things that are "nice to have". At the same time I think it's especially important to clearly define the scope of triggers.

If we want features later that could have been implemented with triggers but need a completely new approach to avoid breaking existing missions, that's bad.

Such generic or flexible missions would be cool in my opinion because they offer a lot of gameplay variety with little effort (little effort for adding new missions once the system is in place).

Link to comment
Share on other sites

Forgive me for not being technical enough, but allow me to share my thoughts on Triggers:

I agree on what Yves suggested, in that triggers could be localized/ categorized depending on the map necessities. What I like about the Age of Empire 1 editor is the simplicity of the Conditions > Effects that is actually pre-loaded in the editor, which, for beginners, could be selected to provide simple changes in game play mechanics. I would love to see that simplicity.

The most powerful and at the same time flexible editor I used, however, is Empire Earth's. While having the same simple Conditions > Effects choices, it can also mix in different variables for different purposes and effects, so that, you can almost recreate any effect or trigger any game play mechanics you can think of, limited only by the core game engine. I hope that 0 AD could replicate that.

Again, sorry for not being of help technically (I don't know much in scripting). But I sure can help with testing/ suggesting what sort of pre-existing conditions/ effects should be there for beginners to use in creating their own maps.

Link to comment
Share on other sites

I agree on what Yves suggested, in that triggers could be localized/ categorized depending on the map necessities. What I like about the Age of Empire 1 editor is the simplicity of the Conditions > Effects that is actually pre-loaded in the editor, which, for beginners, could be selected to provide simple changes in game play mechanics. I would love to see that simplicity.

A trigger editor isn't for now. But we should try to keep the interface simple (at least the most used cases), so it could be done visually at some point in the future.

The most powerful and at the same time flexible editor I used, however, is Empire Earth's. While having the same simple Conditions > Effects choices, it can also mix in different variables for different purposes and effects, so that, you can almost recreate any effect or trigger any game play mechanics you can think of, limited only by the core game engine. I hope that 0 AD could replicate that.

That's the plan
Link to comment
Share on other sites

I hope, with the current design, we keep the simple cases simple (so many people can make triggers), but we also allow for great customisability of maps.

I thought you did no code design. ;) It's yet another message I can't say how much this brings us forward. Now all our dreams can come true, we can define whole storylines. I never thought something like this could ever be a community project. I'm looking forward to script triggers for shieldwolf (as his assistant :D) and also create storylines for historical and fantasy settings.

A miracle, 0AD is a miracle.

Instead of listing requirements it would probably be better to pass map data and provide a function that checks that for requirements, but that's an implementation detail.

That makes sense + fits nicely with Sander's planned filestructure. The only addition would be the trigger-name but I wonder if a trigger not has type we somehow can figure out. It must be possible to determine what a trigger is for and thus we would not need the extra attribute name.

In addition to that Flexible Missions look like they would extraordinarily well fit to Random Map Scripts. Instead of checking requirements, we could also add the requirements ourselves on the fly. (if scripts can place triggers and as it's being stored in map.XML I think they can.)

The Missions would itself be built up of Sander's proposed helper building block scripts organized per category in the maps/scripts/ . Therefore we would also have a maps/missions/ folder. (not sure if we should separate the different types of mission templates Yves proposed, i.e. Generic+Flexible+Specific each in its own sub-folder, but probably yes.)

Link to comment
Share on other sites

I'm going to take a different stance form Yves here. Triggers imo should be powerful, but utterly limited to the map. Of course you could code victory conditions in them, but we don't have to, so I really don't see the point. If people want different game modes, they can ship a mod, it'll work better.

I don't really have any comment otherwise, except that the most powerful scenario editor is RoN since the triggers were actual scripts :P

Link to comment
Share on other sites

Except that we can't offer methods to read the mouse or camera position (as that's non-synchronised by design), we're about just as powerful. I think you could write an entire AI in triggers. And apart from setting the height map or textures, placing entities as in RMS'es is also possible.

The only think I want to keep simple is the default interface. But behind the scenes, Triggers have complete access to all scripted simulation.

Link to comment
Share on other sites

A note about the current interface and the possible future gui expansion:

The current trigger system is based on that of Warcraft III. That game had an utterly powerful but easy to use trigger editor. Each trigger was made up of three main parts: The events, the conditions and the actions. The actions part could also have "if-else" blocks for further conditioning if needed.

post-12825-0-35513800-1402076961_thumb.p

There was a GUI editor that helped someone with zero coding experience create sophisticated triggers using the structure mentioned above. When saving the map, the editor translated those "gui triggers" into a script that was then run by the game. Those "gui triggers" were also preserved so that the map maker could continue working on it after saving the map.

The best part was that it was not limited to this. One could use an option that converted all of the current "gui triggers" into the game-readable scripting syntax, and continue working on the triggers by coding in the mentioned script directly. This way, you had access to some of the game's functions that were not accessible in the gui state. This process was not reversible and you would ultimately lose your gui based codes.

post-12825-0-37004500-1402076977_thumb.p

It is possible to change each of the events/conditions/actions by double clicking on them. Parts in that are written in blue text can ve changed by clicking on them. This makes it possible for a non-coder to create complex triggers solely useing this GUI interface.

My guess is that even in the future, we won't have the time and resources to write a GUI interface that can directly read the game's trigger scripts. The codes are simply too unpredictable to do this. So, we could plan for an entirely warcraft-like trigger system and do not go for an utterly simple interface that actually sacrifices the "coder"'s flexibility for the ease of the "gui trigger maker". We could go for a convenient scripting interface, and then create a gui editor on top of it to use as much of the power of the scripting interface as it can.

post-12825-0-37603600-1402076987_thumb.p

Still, it can all be converted to the native scripting syntax for further flexibility and access to more features.

Link to comment
Share on other sites

Sounds very promising!

I guess triggers will be available for all map types (Scenarios, Skirmish, Random)?

If we get something like the Warcraft III trigger editor that would be most astonishing (at least for me).

It might be good to change map previews to be in the same location than the maps/trigger scripts as well (same path, same base name, no need to add it to the .json file).

Link to comment
Share on other sites

I'm going to take a different stance form Yves here. Triggers imo should be powerful, but utterly limited to the map. Of course you could code victory conditions in them, but we don't have to, so I really don't see the point. If people want different game modes, they can ship a mod, it'll work better.

The terms are a bit blurry here. What is a mod and what are triggers?

A mod is just a directory or a zip file in binaries/data/mods that can contain anything. A mod is a very general solution for implementing custom functionality, which is good in many cases but also a problem in other situations. I'll elaborate more on that below.

Triggers are basically like any other simulation component and could therefore also be part of a mod with a similar or completely different implementation.

What makes them special and what we are talking about in this case is:

  1. Triggers suggest how the component system can be used to implement scripted missions by providing a suitable pattern.
  2. Triggers provide often used functionality for scripted missions like range events, timer events, predefined actions etc.
  3. Triggers simplify mission scripting for map designers
  4. In contrast to the very general concept of a mod, triggers provide additional ways of integrating custom content. In the proposed solution that's the "TriggerScripts" definition in the map JSON that defines which trigger scripts are loaded as part of the map.

Our task (and my task when reviewing the patch) is to analyse if the proposed solution meets these requirements well enough and if it can be extended in the future to meet additional requirements.

  1. The most important criteria is if the suggested pattern is flexible enough. A suggested pattern is successful if it gets used in most cases and doesn't have to be replaced by another pattern. IMO this solution is very flexible and meets the requirements in this case.
  2. As far as I can tell, this patch already offers some often used functionality and the attached tutorial proof-of-concept mission shows that quite a lot can be done already. We should keep an eye on commonly used functionality that could be added to the default trigger component, but I'm quite sure that extending this implementation works well for the future. IMO the requirement is met.
  3. I think the solution can be extended in different way to simplify mission scripting for map designers (like Spahbod described for example). It already simplifies it a lot by fulfilling requirement nbr 1. However, I think we need to agree on how triggers will be presented in atlas and make sure this patch can be extended accordingly in the future before it can be committed. IMO we're on the right way but this requirement is not completely met yet.
  4. As wraitii says, we could always implement functionality with mods, which is a very general approach. General approaches have some limitations for specific cases. Flexible missions (check definition above) are hard to implement with mods for example. You could add trigger scripts to all maps, but then it quickly gets difficult if you have more than one mod and if you want to use maps from other mods with the triggers of your flexible mission. Another approach would be figuring out on your own how you can add all the functionality to the game in a general way and use it with all maps. This would probably work somehow but it would at least make it a lot more difficult for mission designers and it wouldn't be done often. I've discussed flexible missions with Sander on IRC. The requirements checking is a problem. If we want the full flexibility we'd have to load the whole map on the gamesetup screen to check for requirements. Sander suggested listing flexible missions and the associated trigger scripts in the map JSON data. This would mean the flexible mission needs to be known at map creation time, which kind of defeats the purpose. Maybe a reasonable tradeoff would be predefining some "mission script definitions" in the map JSON data. Like specifying that the map has a "InvadingArmySpawn" trigger point (or maybe "FarAwayFromPlayerSpawnPoint") or that each player starts with a CC. Then we could have trigger scripts requiring certain mission script definitions. This is just one aspect and there are some other open questions about how trigger content is provided. Random maps are another example. IMO this requirement is not yet met.

I'll think about triggers a bit more this afternoon and probably add some more comments.

Generally I like the approach very much and it seems to be a solid solution once the open questions are resolved. :)

Link to comment
Share on other sites

For point 3:

I see Atlas offering you a fixed set of events (as they come from other code, it would be hard to create new ones), and a premade list of actions, that can be extended by creating extra actions (either by combining existing actions, or by writing JS code for it).

Atlas itself would write the code to a trigger script, and to some custom data format (closer representing the UI). That custom data format could be read by Atlas when a map is opened (to allow editing of triggers). But Atlas shouldn't be able to interprete the JS code (that would be too hard, even if we keep it simple).

I see it working a bit like Scratch, where you also have a predefined list of actions and events, and can combine them. Scratch can write JS, but it can't read it. In Scratch you can make new methods (actions), but no new events. For the same reasons I think.

So pretty much what Spahbod said.

About point 4:

We can have a directory with JSON files containing info about possible missions. The JSON files would say what requirements they have for the map, and the map should list the fulfilled requirements. This is one level deeper than offering the list of possible missions in the map JSON, and because of the splitting per file, it would allow mods to add their own (as long as they use standard criteria). When certain missions are selected in the game setup, the scripts associated with that JSON could be loaded.

Link to comment
Share on other sites

Ok, worked out the details of victory conditions and triggers. Not fully implemented, but enough code to see it will work nicely (see the attached patch).

Basically, if someone wants to make a victory script, he places a requirements-checking script inside gui/gamesetup/victory_scripts. When #2622 is in, all those scripts can be loaded automatically.

Those scripts give basic GUI info (name to display, description for a tooltip, ...), a function to check the requirements using the game settings (i.e. everything set in the map JSON data part + specific settings for that game, s.a. starting resources, number of players, ...). As the variables in that JSON part are free, a victory condition may require a certain specific variable to be set before enabling the victory condition. And as last thing, the script also gives a list of trigger scripts that must be loaded in order to enable this victory.

The list has a different name than the default trigger scripts, but they can be loaded the same way as the current trigger scripts are loaded.

This way, general victory conditions can work (by just always answering "true" to the requirements check), dynamic victory conditions can work (by checking existing data, or requiring a non-specific key to be set in the JSON), and specific victory conditions can work (by requiring a specific key in the JSON).

We also need to make the map settings available to the trigger scripts (either making it global, or through the triggers component), so the victory scripts can ask some data for it.

For example, a "king of the hill" victory condition might require a "hillToCapture" variable be set to a trigger point reference. Something like

{    ...    Preview: "anatolian_plateau.png",     CircularMap: true,     HillToCapture: "A",    XXXXXX: "Optionally define other things here."}

So the requirementsCheck would check for the existance of "HillToCapture" in the map data. And the trigger script would query the value of "HillToCapture" to see on which trigger point its trigger should listen.

With that figured out, I think we should go over to comiting it pretty soon.

victory.diff

  • Like 1
Link to comment
Share on other sites

Looks dynamic + really flexible. Great the ticket is already committed.

Currently in victory.diff we return true in the requirements check, so that is a general victory condition? I.e. if that hero reaches that hilltop/coordinates, then the game is won?

Other than the GUI list for choosing the victory condition, Is there a difference to triggering/starting a conversation with a unit if e.g. a certain hero reaches a certain hilltop/coordinates?

Can we reuse such closely related triggers for both a victory condition and sparking a common action/event (like the conversation above).

Best I study your trigger examples.

Link to comment
Share on other sites

Currently in victory.diff we return true in the requirements check, so that is a general victory condition? I.e. if that hero reaches that hilltop/coordinates, then the game is won?

That's just an example. I could log the map settings JSON from there, so I can use it for decisions too.

Other than the GUI list for choosing the victory condition, Is there a difference to triggering/starting a conversation with a unit if e.g. a certain hero reaches a certain hilltop/coordinates?

Can we reuse such closely related triggers for both a victory condition and sparking a common action/event (like the conversation above).

Best I study your trigger examples.

That's already closely related. There's a simple onRange trigger, where you just fill in a few details, and you get feedback when a unit entered the range you asked.

The difference between the two is indeed only in the loading stage. In the game itself, there's no difference between regular triggers and victory conditions.

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...