Jump to content
Sign in to follow this  
Spahbod

Discussing Triggers

Recommended Posts

I know that implementation of triggers is postponed to Empires Besieged, but it shouldn't stop us from discussing the technical parts here.

It is obvious that triggers should be able to change the simulation state. So either they should be part of it, or somehow linked to the simulation code. I think it would be better if we don't complicate the code by using the second approach.

My suggestion is this:

"Triggers" are JavaScript codes that are run in the simulation. The map maker will also create a "something.js" in the map folder and specify it in the .xml file. In the .js code, there are some overloaded functions like "OnUnitKilled" or "OnTechnologyResearched". The map maker should write the code for these functions to get the intended result (eg. if the unit killed was a hero, the player loses).

These functions are actually undefined variables as default. They are called when the event occurs in the simulation code (eg. when an entity takes damage in the simulation code, the function "OnEntityTakesDamage" is called if it is not undefined.

A schema:

In "promotion.js"

...Promotion.prototype.Promote = function(promotedTemplateName){   ...   // after everything is done   if (OnUnitPromoted !== undefined)   {       OnUnitPromoted({"entity" : this.entity, "newentity" : promotedUnitEntity});   }}...

In "mymaptriggers.js"

OnUnitPromoted = function(data) {   // do actions}

Another approach would be parsing a new language we have defined for the triggers. They both have advantages and disadvantages:

My approach:

Pros:

Very flexible and powerful: We can change anything in the simulation which means we can almost access anything worth of note in the game.

Easier implementation and expansion: It is much easier to implement.

Better performance: Unless we want to move the triggers into the C++ side, this approach is one of the fastest we could take.

Cons:

Too much access to simulation: This means that a badly written trigger might cause the game to crash.

Harder for mapmakers without programming knowledge: It won't be easy to create the effects if you are not familiar with the simulation.

Parsing approach:

Pros:

Easy for map makers: We can keep the syntax very simple.

Restricted access to simulation: We can prevent the game from crashing/giving oos errors.

Cons:

Hard to make a good performance parser: It wouldn't be easy to parse the new syntax. Especially if done in js.

Limited flexibility/power: Every new event/condition/effect should be added manually.

Takes much more time to implement: It is obvious.

I think we'd better go for the first one. This way, we might be able to implement the triggers in 0 A.D. Part 1. Also the power and the flexibility it brings is something few games offer (and those that do are usually very successful).

To make it easier for map makers, we can create a GUI interface in atlas similar to that of Warcraft III. In Warcraft III, Triggers were defined in a scripting syntax, but it also had a GUI based trigger editor similar to that of Age of Mythology. Those triggers were then translated into the scripting syntax to run. Needless to say that this was one of the reasons it became so successful.

A good point is that we can postpone the GUI interface for the next part, but still have triggers in Empires Ascendant.

Share this post


Link to post
Share on other sites

I don't think it was postponed to Empires Besieged, but I might be mistaken.

EDIT: link, they are likely not going to be in part 1, so EB it is then

I do think this is one of the most important features for scenarios! I really hope this is going to get into part 1 ... If not ... in four years my Computer Science course will be over so ... xD

Share this post


Link to post
Share on other sites

we don't need a lot of infrastructure changes. It is already possible to run simulation code from the map file (just open the units demo, or the huge combat demo).

But those maps don't work with Atlas for two reasons. They influence the map before the first turn. This can be solved easily by working with timers that would only run on the first turn. But I think Atlas also overwrites the JS code, which is a bigger issue, as you can't edit the map after putting a script in it.

This way, triggers can use everything in simulation (also setting up timers for later execution), but as a framework to make triggers easier, I suggest a trigger component, where you could execute cmpTrigger.RegisterTrigger({trigger: "timer", triggerData: {time: 300}, action: defeatPlayer, actionData: [2]}). Then the triggers component would make a timer for you, and when the time had come, execute the right function.

Next to that, there should also be some helper functions for common triggers and actions. This would make the syntax easy enough for the common cases, and it would make it easily interpretable for an Atlas GUI in the future.

Share this post


Link to post
Share on other sites

Many fans are asking about campaigns (or scenarios with triggers). I myself am also a big single player fan,I don't enjoy multiplayer games that much. But if I can 'relive' history, instead of random deathmatches I'm excited.

I wish that triggers make it into part 1. I think people expect it. If we don't add campaigns, at least allow the community to start working on them.

  • Like 2

Share this post


Link to post
Share on other sites

we don't need a lot of infrastructure changes. It is already possible to run simulation code from the map file (just open the units demo, or the huge combat demo).

But those maps don't work with Atlas for two reasons. They influence the map before the first turn. This can be solved easily by working with timers that would only run on the first turn. But I think Atlas also overwrites the JS code, which is a bigger issue, as you can't edit the map after putting a script in it.

This way, triggers can use everything in simulation (also setting up timers for later execution), but as a framework to make triggers easier, I suggest a trigger component, where you could execute cmpTrigger.RegisterTrigger({trigger: "timer", triggerData: {time: 300}, action: defeatPlayer, actionData: [2]}). Then the triggers component would make a timer for you, and when the time had come, execute the right function.

Next to that, there should also be some helper functions for common triggers and actions. This would make the syntax easy enough for the common cases, and it would make it easily interpretable for an Atlas GUI in the future.

One of the most important features of the triggers is that they are "event" based. Adding a trigger component (which is already there) and sending them there won't solve the problem. We still need to make a hook for every event in the main simulation code. So we still need some infrastructure changes.

My approach also solves the problem with atlas. It works the same with map previews, where the map maker only determines the name of the script file.

Helper functions will certainly be useful. I agree with that. It could simplify the "action" part of the triggers.

Share this post


Link to post
Share on other sites

Campaigns and scenarios are something communities just love doing :-) So it's most definitely an important thing to have!

(it also allows people to make new game modes like 'Castle Wars' where units are spawned automatically at a castle/fortress, and 'Defend' games where invasion forces are sent every so often)

  • Like 2

Share this post


Link to post
Share on other sites

Campaigns and scenarios are something communities just love doing :-) So it's most definitely an important thing to have!

(it also allows people to make new game modes like 'Castle Wars' where units are spawned automatically at a castle/fortress, and 'Defend' games where invasion forces are sent every so often)

If part 1 of 0 A.D. will just be a skirmish/multiplayer game where you can also make new units/maps in the editor, not many people will start modding.

Triggers will attract many scenario designers... So many historical scenarios to recreate....

In my opinion, triggers should be part of part 1. I for one want to start making scenarios with triggers.

  • Like 2

Share this post


Link to post
Share on other sites

Oh I was wrong, there's no problem with Atlas, the scrips are saved just fine.

Also, the triggers component would be able to listen to many existing messages (player defeated, ownership changed, entity created/removed) without touching other parts of the simulation code. For some triggers that can't be caught by existing messages, you could still have other components (like the promotion component) call a function in the triggers component to execute all registered triggers that should be handled.

So in the map, you'd have some simple functions as

OnCivCenterCreated(SendResouces, {wood: 100});

Then, the global helper functions look like this:

var OnCivCenterCreated = function(action, actionData){    var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);    var ccAction = function(actionData, msg)    {        // check if the entity in the msg is a CC        // check the owner in the cc        // execute the action for that owner    }    cmpTrigger.RegisterTrigger ({trigger:"OnOwnershipChanged", action: ccAction, actionData: actionData})};var SendResources = function(actionData, msg){    // get player defined in the message    // send player the resources defined in the actionData};

And the Trigger component just Listens to the OnOwnershipChanged message, and executes the ccAction function with the msg and the action data passed on.

  • Like 1

Share this post


Link to post
Share on other sites

For some triggers that can't be caught by existing messages, you could still have other components (like the promotion component) call a function in the triggers component to execute all registered triggers that should be handled.

Which is what I'm trying to say. Still we are creating hooks inside the simulation code.

I never said that we shouldn't have a trigger component. I just said that we need the hooks.

Also, OnOwnershipChanged is called in a variety of occasions, ranging from entity creation to death. Are these situations distinguishable from each other?

So in the map, you'd have some simple functions as...

One of the most important parts of the triggers is the "condition" part. For example, we shouldn't have an event named "OnCivCenterCreated". Rather, we should have something like "OnEntityCreated", and a condition block for any condition checks (Is it a civic center? is it owned by player 2? etc.). If not, we are going to create hundreds of helper functions and still lack the flexibility. Also, we should make sure the map maker is able to use his own functions if he wants to do something not present in the helpers.

I have ay idea about how to implement the conditions in the approach you are suggesting. If they can define the function that is called by the trigger themselves, they'd be able to merge the "condition" and "action" parts (The first code snippet). But in general we could make it like the second code snippet:

//In the map's trigger part:var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);cmpTrigger.OnEntityCreated(MyOwnFunction);MyOwnFunction = function(data){   if (something) //do the checks yourself   {      //actions, including the ones that can be accessed using the helpers   }}...//In trigger.js:cmpTrigger.OnEntityCreated(action){   //it listens to messages as you suggest or is directly called by the simulation code (for eg. in builder.js)   //in any way, we get two entities: the one that was created and the creator (building and builder, trained unit and the barracks, etc.)   //and we call the action   action({"createdEntity": entity, "creatorEntity": creator});}
//In the map's trigger part:var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);cmpTrigger.OnEntityCreated(AHelperFunction, AConditionFunction, otherData);

Again, it would limit the flexibility, but still it is easy to understand.

  • Like 1

Share this post


Link to post
Share on other sites

According to the design documents, yes. But these things are not set in stone, we're not a big company cutting features to save money/time.

I guess if someone would insist on working on triggers, it would be hard to stop him/her ;p (some wishful thinking on my part there).

  • Like 1

Share this post


Link to post
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.

Sign in to follow this  

×
×
  • Create New...