Jump to content

Triggers (split from A couple of suggestions)


Recommended Posts

Why not do this with normal simulation scripting?

The maps/RMS would need access to simulation. But as it is now RMS are run before simulation is started. For "normal" maps, as I said, I'm not sure. But how would I write one with an editor (so I could add trigger scripts)?

Adding a dependency on yet another scripting library when we already have SpiderMonkey == madness and/or SPARTA!

Not another, the only one. Python is supported by any OS officially supported by 0 A.D. (Added native Windows support in the next version). And Python would not need something like SpiderMonkey at all AFAIK (Just a file to wrap the needed C++ functions to Python and import them wherever you like - Well maybe ctypes/boost is something like SpiderMonkey x) ).

You will always have to punch a hole in the engine to allow scripting whatever language you choose. SpiderMonkey for Javascript. If you don't like it it's another reason to think about changing the used scripting language. But since the development has made it that far it's perhaps a matter to live with.

Generating random maps before simulation starts, however, is a concept flaw. That way simulations and RMS can never work with each other without some hacky stuff.

Could you give me an example how I would add a new unit type to be able to build in a building of a given type on a specific map (Just so I understand better how that would work)?

Edited by FeXoR
Link to comment
Share on other sites

For those that don't know exactly what we're talking about, a trigger is essentially a script event that controls actions in a scenario.

They're based on "Conditions" and "Effects" (i.e. if/then) that are defined in the scenario editor (Atlas, in our case). When a condition or set of conditions is met, an effect is fired. A condition can be anything

It sounds like a primitive AI, only with the UI included as part of the state it can affect/respond to. So it's a matter of determing which state the triggers need and building that state. We already do something very similar in the GuiInterface component.

I would recommend not inventing our own scripting language, nor adding some other, instead we can use JSON for ease of integration with existing scripts. A single JSON file could define a "condition" with its description, unique name and expected parameters (what the scenario designer will see), and a condition function to evaluate. An "effect" JSON file would be similar only with an effect function to evaluate. We could have a library of functions (API) to save trigger devs from writing a bunch of state accessors and tests.

Example condition file:


{
"Name": "IsEntityInRangeOfPosition",
"Description": "Checks if an entity is within range of a position",
"Parameters": [ "entityID", "position", "range" ],
"TestCondition": function(state, options) {
var pos = GetEntityPosition(state, options.entityID);
return (pos && DistanceBetweenPoints(pos, options.position) <= options.range);
}
}

Example effect file:


{
"Name": "SendChatToPlayer",
"Description": "Sends a chat message to specified player",
"Parameters": [ "player", "message" ],
"DoEffect": function(state, options) { Engine.PostCommand({"type": "chat", "player": options.player, "message": options.message}); }
}

The advantage would be every condition and effect fits that template, and the only complicated part is for the trigger devs to write the logic. There should be enough state provided to evaluate any useful condition and effect; if something is missing, we add it.

A trigger would consist of one or more conditions (or in the simple case, only one), one or more effects, and the parameters selected by the scenario designer. Each trigger would have a unique ID, so they could reference eachother, you'd end up with a hierarchy that allowed fairly complex behavior. I suppose that would also be JSON, embedded in the scenario's XML, as we do for map settings currently. Example:


...
<TriggerData><![CDATA[
{
"Triggers": [
{
"ID": 1,
"Name": "Trigger001",
"Parent": 0,
"Conditions": [ { "Condition": "IsEntityInRangeOfPosition", "Options": { "entityID": 300, "position": { "x": 623, "z": 891}, "range": 12 } } ],
"Effects": [ { "Effect": "SendChatToPlayer", "Options": { "player": 1, "message": "Good job, you moved the female citizen to the farmland!" } } ],
},
...
]
}
]]></TriggerData>
...

Mostly you'd never look at the "raw" trigger data, because you'd have a UI...

The Atlas UI for creating triggers might be the hardest part, it would need to clearly show the relation between triggers, the logic of conditions for each trigger, and offer controls for the parameters of both conditions and effects. C++ parsing of JSON is yucky, but it would be minimal in this case, really only name (string), description (string) and parameters (list - but we might have to worry about types and data validation?)

Link to comment
Share on other sites

Sounds good.

I would like to add "triggeringEntity" to the returned values:The ID of the entity that activated the trigger. If needed that way another check could be done e.g. for the units type, it's state or other properties like it's actual health.

Another thing is that the code for triggers would have to be part of a map but is not to be executed when the map is loaded but - when a trigger fires - "something" has to check if the map has code to be called matching that trigger event.

Edited by FeXoR
Link to comment
Share on other sites

Generating random maps before simulation starts, however, is a concept flaw. That way simulations and RMS can never work with each other without some hacky stuff.

I see no flaw in that. The simulation is supposed to take place inside the map, so it is only natural that the map would have to exist before the simulation begins.

Could you give me an example how I would add a new unit type to be able to build in a building of a given type on a specific map (Just so I understand better how that would work)?

If doing something like Kimball and historic_bruno describes, there might be a "AddNewUnitType" effect which you could run in response to some event (e.g. "MapLoaded").

Here is a mockup I dug up on the forum which illustrates it quite well:

trigger-menu-concept-Diagra.gif

Link to comment
Share on other sites

And someone could add code in there instead of using the GUI?

It's good to have a GUI to keep the barrier of entry low. But I like scripting.

BTW: I meant more like a working code example and where to add it to the map and where to add the trigger implementation needed for that (the thing that is manipulated is not the matter, I only want to understand how you want to manipulate simulations at a specific point in the game by something written in the map file).

I see no flaw in that. The simulation is supposed to take place inside the map, so it is only natural that the map would have to exist before the simulation begins.

Than triggers are given to the map generated by rmgen "exportMap()" as well and then manipulating the game in simulations?

Edited by FeXoR
Link to comment
Share on other sites

And someone could add code in there instead of using the GUI?

It's good to have a GUI to keep the barrier of entry low. But I like scripting.

Yeah, that would be what the "Script" button is for. I would prioritize the simple, GUI-defined triggers, though, since the most people will benefit from those.

Than triggers are given to the map generated by rmgen "exportMap()" as well and then manipulating the game in simulations?

Yes, something along those lines.

Link to comment
Share on other sites

I don't think triggers should have anything to do with random maps, unless you are creating a random interactive scenario... Otherwise, if the random map generator needs to know something about entities before it places them, we just add entity template parsing into the random map generator. It's really no big deal, we only have to get to it eventually.

Link to comment
Share on other sites

I don't think triggers should have anything to do with random maps, unless you are creating a random interactive scenario... Otherwise, if the random map generator needs to know something about entities before it places them, we just add entity template parsing into the random map generator. It's really no big deal, we only have to get to it eventually.

That would be very helpful (adding template information to rmgen).

But that's not what I meant. If it is possible to change the games behavior with triggers it should be possible with RMS as well. The code would not even have to be called during the rmgen interpretation but a "trigger code string" would need to be stored with the map (though common editors highlighting will not be amused about a "string of code", well, but there has to be better ways about as simple ^^).

Edited by FeXoR
Link to comment
Share on other sites

If possible, it would be cool to have a way for campaign missions to interact between themselves. A way to store info, i.e. I made a mission in which you had to make 10 soldiers through a mountain passage, no buildings, no training. The mission after, i'd want to keep the exact same number of soldiers and their health.

Link to comment
Share on other sites

It sounds like a primitive AI, only with the UI included as part of the state it can affect/respond to. So it's a matter of determing which state the triggers need and building that state. We already do something very similar in the GuiInterface component.

Do the triggers need to be "compartmentalized" or "sandboxed" somehow, the same way GUI and simulation are compartmentalized from each other (where you can't immediately call simulation stuff from the GUI and vice versa). If they don't need to be compartmentalized - i.e. if we can run them in the simulation as is - I guess they could use the standard API for interacting with entities and components?

Or perhaps your point is that the standard API may not currently offer all the state the triggers might need?

Edited by zoot
Link to comment
Share on other sites

what do you try to achieve?

'trigger' should be a conversion function??

where’s the definition for 'trigger(…)' ?


CTrigger trigger(eventName);
m_Triggers.push_back(trigger);

you basically do: define a function prototype and than push_back() a zero-pointer to that non-existing function

you can define function without implementing it when you don‘t call it, but you try to push it into the list

____

so implement

CTrigger trigger(eventName);

in the h/cpp file and then use

m_Triggers.push_back(trigger(eventName));

Edited by luziferius
Link to comment
Share on other sites

trigger is supposed to be an object of the CTrigger class, initialized with eventName as an argument into its constructor.

See this example:

Date cToday(9, 5, 2007); // cToday is initialized to Sept 5th, 2007

Edit: MapReader.cpp looks a bit off though, made a fixup: https://github.com/z...20b2c...b5245af The segfault on TriggerManager.cpp:25 persists, however.

Edit2: Fixed this, it was just some dumb variable initialization issue.

Edited by zoot
Link to comment
Share on other sites

How do you plan to implement the action? It should be possible to write a javascript function and give it to the trigger as an effect without running the given function at initialization. When the trigger event happens and the trigger conditions are true the function could then be run. I don't know how this should work but I think that would be best.

I'd like to help but until I have an example for a working trigger I'm staying out of the C++ part since I don't have much experience there. If I have an example trigger (and maybe a list of wanted trigger events/conditions/actions) I'd like to help.

If it's helpful, I found a really old thread that contains some of CheeZy's wisdom on triggers and a list of proposed effects/conditions: http://www.wildfireg...?showtopic=7274

Good to see that you're making progress on this! (Even if I don't have any idea what you're saying :))

I cannot access the link. Would it be possible to allow me the access (or make it public)?

BTW: Are triggers officially wanted (now) or will this be a community project that, if working well, might then be added to the main game?

Edited by FeXoR
Link to comment
Share on other sites

How do you plan to implement the action? It should be possible to write a javascript function and give it to the trigger as an effect without running the given function at initialization. When the trigger event happens and the trigger conditions are true the function could then be run. I don't know how this should work but I think that would be best.

I don't know yet - something similar to what historic_bruno suggested. Maybe I will have to make a new 'scripting host' or maybe I can find a way to use one of the existing ones. The slightly tricky thing is that we want triggers to be able to respond to both simulation and UI events, though they are run in different contexts.

Link to comment
Share on other sites

That's why I think in the end having triggers implemented and used for the map editor, player interaction, random maps and AIs would be the cleaner design. That way you'd only need the trigger layer to access the engine and have the other parts use those functions.

But I don't really get what simulation includes so I'm not entirely sure.

But for now I should set my sights lower and be content with working triggers ;)

Edited by FeXoR
Link to comment
Share on other sites

Yes, but the functions used to edit e.g. the GUI so that if a button is clicked something happens could use triggers as well. If you have a scenario with several options to chose in-game you need the same functionality. But as is now everything (that can be scripted) has its own scripting environment (simulation, AI, Atlas, RMS, Civilization/Unit/Mod/Game-rules definition). And every function needed in more than one of them is duplicated.

Maybe I'm missing something. If you see what this is please let me know.

Edited by FeXoR
Link to comment
Share on other sites

Yes, but the functions used to edit e.g. the GUI so that if a button is clicked something happens could use triggers as well. If you have a scenario with several options to chose in-game you need the same functionality. But as is now everything (that can be scripted) has its own scripting environment (simulation, AI, Atlas, RMS). And every function needed in more than one of them is duplicated.

Maybe I'm missing something. If you see what this is please let me know.

As far as I know, Atlas does not rely on scripting at all - it's written in C++. As for simulation, AI and RMS, those need to be separate - if I download an RMS someone made, I don't want to have to worry that it might be hacking the simulation to give my opponent an unfair advantage, for instance.

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...