Jump to content
The Dark Mod Forums

Recommended Posts

Well the big moment has arrived, it is time for our first Darkmod-specific feature. I will start with the Objectives Editor GUI, because this is something that all mappers will need (as opposed to the Stim/Response editor, which many, but not all, mappers will make use of).

 

For this I will need to know how the Objectives system works. There is some documentation on the Wiki (http://www.thirdfilms.com/darkwiki/index.p...itle=Objectives) but this only gives an overview of what objectives mean. @Mod devs -- is there any further documentation besides this anywhere? I will need to have a clear understanding, from the very beginning, of exactly what keyvals need to be set on what, in order to come up with a reasonable interface.

Link to post
Share on other sites
  • Replies 98
  • Created
  • Last Reply

Top Posters In This Topic

Stim responses are equally important. How do you setup a candle that you can extinguish with the water arrow? But at this moment I think it doesn't matter so much and you have to start somewhere anyway, so objectives is probably a good place to start with, and afterwards the stim/response system.

Gerhard

Link to post
Share on other sites

I agree with Orb that Stim/Response is a more advanced feature that many authors won't use to make maps. Plenty of T1/2 FMs have been made (most of them in fact) without the author knowing a thing about stim stuff. I think they're important, just not equally important as objectives

shadowdark50.gif keep50.gif
Link to post
Share on other sites

The difference in Dromed is though, that things like torches, and a lot of gameplay elements are already properly pre configured. This will take quite some time, so I think that mappers will have to aquaint themselve with the concepts. At least in the beginning, until we can polish it more.

Gerhard

Link to post
Share on other sites

Ishtvan is the one you need to talk to about Objectives functionality.

Link to post
Share on other sites

That documentation is still pretty accurate.

 

The thing you probably need to know for the GUI is that some objective types take two specifiers and two arguments, and some only take one. Also, some specifiers do not work for certain objectives. For example, if you tried to set up a "KO" objective with an "inventory group" specifier, it wouldn't work, because you can't KO inventory items. Same goes for setting up an "item" objective with an "AI team" specifier.

 

I was planning to make a spreadsheet showing what specifiers make sense for each component, and which ones have two arguments. I haven't done this yet.

 

There's also a tutorial map, objective_test on CVS, which includes several objectives.

Link to post
Share on other sites
That documentation is still pretty accurate.

 

The problem is that the documentation doesn't make clear (to me at least) precisely what keyvals you need to set. For example, if "Objective 1 text" is "Kidnap Benny", as in the example, how is this specified by a keyval: "objective1text", "objectivetext1", "objective_text1" etc ?

 

There's also a tutorial map, objective_test on CVS, which includes several objectives.

 

Thanks, I'll have a look at this.

Link to post
Share on other sites

I'll write up something today after the SuperBowl. Rather than wait until I have a nice spreadsheet done, it's probably better to just convey the info sooner in the form of a posting. The keyvals are all general for every type of objective component, but some of them do slightly different things or are not applicable to certain components. I'll write it up.

Link to post
Share on other sites

List of general objective spawnargs:

The entity to place for setting up objectives is: target_tdm_addobjectives. This adds certain objectives when triggered, and the spawnargs on here control the objectives.

 

Henceforth, the phrase "If true" denotes "If set to '1'". To clarify how the enums work, they are all input in to the spawnarg as int values, so OBJ_COMPLETE would be entered as "0". The GUI can of course create a dropdown list of their names or whatever is convenient.

 

 

Objective Spawnargs (apply to the whole objective)

All the spawnargs for a given objective will have the prefix "obj<i>_*", where i is the index of the objective. They get added in numerical order via the index (I think). So the "1" below gets incremented. In this case the counter starts at "1" and not "0", for user friendliness when FM authors are trying to keep track.

 

Key: obj1_desc

Value: text description of the objective that appears in the objectives GUI. If necessary, we can store two of these for a long version and a short version.

Default: ""

 

Key: obj1_mandatory

Value: If true, objective is mandatory, otherwise it is optional. Failing a mandatory objective fails the mission, the mission cannot be completed until all mandatory objectives are completed.

Default: "1" // mandatory

 

Key: obj1_irreversible

Value: If true, this objective may only change state once. After that it latches and remains in the changed state. E.g., "Pass through the foyer of the mansion". Once you do that once, the objective is complete.

Default: "0"

 

Key: obj1_state

Value: One of the following from the enum below

List of possible objective states:

OBJ_COMPLETE (0)
OBJ_INCOMPLETE (1)
OBJ_FAILED (2)
OBJ_INVALID (3)

Complete and incomplete are self-explanatory. Invalid means this objective is not currently being checked. Objectives may start out incomplete and later be set invalid, or vice-versa.

Default: OBJ_INCOMPLETE

NOTE: Some objectives start out complete, e.g., "Don't kill anyone." At the start of the mission, you haven't killed any AI. These types of objectives are also usually marked "ongoing" (see below)

 

Key: obj1_ongoing

Value: If set to "1", this means this objective is ongoing throughout the mission. Internally, it remains true unless the player does something that fails it, but it doesn't get completed from the player's perspective (checked off in the GUI) until the end of the mission. Failing a mandatory ongoing objective fails the mission. An example of an ongoing objective would be "Don't kill anyone."

Default: "0" // not ongoing

 

Key: obj1_visible

Value: If true, objective is visible in the objectives GUI (NYI), otherwise it is hidden.

Default: "1" // visible

NOTE: One way for a mapper to have an objective kick in later is to start it out in state OBJ_INVALID, and with the obj<i>_visible spawnarg set to 0. Via scripts, the author can set it visible and set its state to OBJ_INCOMPLETE to add it at a later time. (The other way to add objectives at a later time is set up a second target_tdm_addobjectives and trigger it, but if there are multiple ones that can get triggered in different order, it may confuse the objective handles later).

 

Key: obj1_script_complete

Value: String name of the script to call when this objective is completed. This may be in global scope or a namespace may be specified, e.g. "<mapname>::<script in map namespace>".

Default: ""

 

Key: obj1_script_failed

Value: String name of script to call when objective is failed.

Default: ""

 

Key: obj1_enabling_objs

Value: Space-delimited list of integer id's of objectives that must be completed before this objective may be completed. E.g. "1 2 3"

Default: ""

NOTE: This is used when multiple objectives must be completed in a certain order. The FM author could script this themselves without using enabling objectives, but this option exists to save them some work.

 

Not Yet Implemented :

Key: obj1_logic_success

Value: A boolean logic string with int objective component handles as identifiers. When any objective component is updated, all of the objective components are checked with this logic, and if the result is true, this objective state becomes completed. E.g. "(1 AND (2 OR NOT(4)) ) OR (3 AND 5)"

Default: "" // If no logic string is present, default logic of 1 AND 2 AND 3 ... AND N for all N components will be applied.

 

Key: obj1_logic_failure

Value: A boolean logic string with int objective component handles as identifiers. When any objective component is updated, all of the objective components are checked with this logic, and if the result is true, this objective state becomes failed. E.g. "(1 AND (2 OR NOT(4)) ) OR (3 AND 5)"

Default: "" // (Temporary hack behavior) If no failure logic string is present, and the objective is ongoing, the objective fails if any component is false. Otherwise, the objective does not fail and remains incomplete until completed.

 

 

Component Spawnargs (Apply to Individual Objective Components)

All component spawnargs have the following prefix: "obj<i>_<j>_*", where i is the objective number and j is the component number. Component numbering also starts at 1, not 0. Replace 1,1 below with the indices of the objective and component you want to set.

 

Key: obj1_1_state

Value: 0 => false / not satisfied, 1 => true / satisfied

Default: "0"

 

Key: obj1_1_not

Value: If true, this objective component is NOTed after evaluation. I.e., if the component is "kill at least 1 AI", and the component is NOTed, it will start out true and change to false if the player kills 1 AI.

Default: "0"

 

Key: obj1_1_irreversible

Value: If true, component only changes state once and latches.

Default: "0"

 

Key: obj1_1_type

Value: One of the following from the enum below

List of Objective Component Types:

COMP_KILL, // also includes non-living things being destroyed
COMP_KO,
COMP_AI_FIND_ITEM,
COMP_AI_FIND_BODY,
COMP_AI_ALERT,
COMP_ITEM, // Add inventory item or imaginary loot
COMP_LOCATION, // Item X is at location Y
COMP_CUSTOM_ASYNC, // asynchronously updated custom objective (updated by mapper from script)
COMP_CUSTOM_CLOCKED,
COMP_INFO_LOCATION, // like location, but uses existing info_location areas instead of an info_objectivelocation entity
COMP_DISTANCE // distance from origin of ent X to that of ent Y

See forthcoming documentation for detailed descriptions of each type and the arguments they take.

Default: "-1" // will throw up an error if component type is not specified

 

Component Argument Spawnargs:

The following are general argument spawnArgs that may be set for all component types, but specific component types do different things with these args, and expect certain ones to be set. It is therefore recommended that the GUI has the player set the component type first, and then label the input boxes corresponding to how that specific component uses them. Also, arguments that are not used by the selected component type should be grayed out.

 

Keys: "obj1_1_spec1" , "obj1_1_spec2"

Value: Specifier types for specifiers 1 and 2, chosen from the following enum

Enum of Objective Component Specifier Types:

SPEC_NONE,
SPEC_NAME,
SPEC_OVERALL,
SPEC_GROUP, // for inventory items, info_location groups, etc
SPEC_CLASSNAME, // soft/scripting classname
SPEC_SPAWNCLASS, // hard / SDK classname

// Specifically for AI:
SPEC_AI_TYPE,
SPEC_AI_TEAM,
SPEC_AI_INNOCENCE // combatant or noncom

Default: "0", "0" // SPEC_NONE

 

Keys: "obj1_1_spec_strval1" , "obj1_1_spec_strval2"

Value: Strings to match against the specified attributes. For example, if the "group" specifier is chosen, spec_strval would be the string name of the group to check for comparison.

Default: "", ""

 

Keys: "obj1_1_spec_intval1" , "obj1_1_spec_intval2"

Value: Integers to match against the specified attributes. For example, if the "group" specifier is chosen, spec_intval would be the team integer to check for comparison.

Default: "0", "0"

 

Key: "obj1_1_args_str"

Value: Space-delimited list of additional string arguments required by the component type.

Default: ""

 

Key: "obj1_1_args_int"

Value: Space-delimited list of additional int arguments required by the component type. E.g. "1 2 3"

Default: ""

NOTE: For example, suppose you had a KO at least 5 AI nobleman. The type would be KO, the specifier could be classname, spec_strval1 would be "atdm:ai_nobleman", and args_int would be "5". So you pass in the specifier, the string to match the specified attribute, and for a KO objective, you must also pass in the minimum number to KO, so that goes in the int args.

 

Key: "obj1_1_clock_interval"

Value: Only applies to component types that are checked on a system clock rather than asynchronously. The number in seconds to wait inbetween evaluating the state of this component.

Default: "1.0" // [seconds]

 

That's it for now. Next up is a description of all the component types, and how they use these general arguments.

 

@OrbWeaver: Let me know if you have any questions.

 

@Spar: I didn't watch it on the TV card, but you didn't miss that much. :) The first two quarters were interesting, but it got pretty bad near the end.

Link to post
Share on other sites

Thanks, that's pretty detailed and certainly enough to get started with. I think the GUI will need three main components:

 

(1) management of target_addobjectives objects, which displays all of the currently existing objects and allows the creation of one if there aren't any in the map

(2) management of the objectives applied to the selected target_addobjectives, and

(3) management of the spec and args for the selected objective, which may require custom widgetry for each objective type (like the entity inspector's custom property editors)

Link to post
Share on other sites

@Greebo: Yeah, I'll let you know when I've posted part 2 that details the arguments for each objective component type, and by then I'll probably have found errors in part 1 also. :)

 

@Orbweaver: Yeah, that sounds reasonable. Also, I forgot to point out that I added functionality on the worldspawn where you can set targets on it to trigger things right at the beginning of the map, so the initial starting objectives could be added as a target to the worldspawn, if you want to differentiate between starting objectives and ones that are added later in the GUI. Gildoran mentioned another way to do that that's already in D3 though, like maybe setting WaitForTrigger to 0 on any target_* entity, or something.

 

One pro of having them as target_* ents is you can trigger them with things in the map too, if you wanted to add objectives when getting to some area in space, just set up a trigger_once and point it at a target_addobjectives.

 

Sparhawk also brought up a good point that objectives should have a unique name as well as an int handle, to make it easier to display/reference them, so I'll add that to the TODO list.

 

We may also want to do some kind of hierarchical display of objectives and components, e.g.

 

(+) Objective 1 ("Loot Objective")
(-) Objective 2 ("No Kill Objective")
  Component 1 (Kill)
		<component arguments>
(+) Objective 3 ("Get out alive")

Or maybe a GUI where you only view the properties of one objective at a time would work better, whatever works. I'm just suggesting that the objective properties and component properties could be separated somehow so as not to overwhelm one with all the objective flags and component flags at once.

Link to post
Share on other sites
@Orbweaver: Yeah, that sounds reasonable. Also, I forgot to point out that I added functionality on the worldspawn where you can set targets on it to trigger things right at the beginning of the map, so the initial starting objectives could be added as a target to the worldspawn, if you want to differentiate between starting objectives and ones that are added later in the GUI. Gildoran mentioned another way to do that that's already in D3 though, like maybe setting WaitForTrigger to 0 on any target_* entity, or something.

 

I thought you could trigger at map start already, by targeting from the info_player_start entity?

 

We may also want to do some kind of hierarchical display of objectives and components, e.g.

 

(+) Objective 1 ("Loot Objective")
(-) Objective 2 ("No Kill Objective")
  Component 1 (Kill)
		<component arguments>
(+) Objective 3 ("Get out alive")

Or maybe a GUI where you only view the properties of one objective at a time would work better, whatever works. I'm just suggesting that the objective properties and component properties could be separated somehow so as not to overwhelm one with all the objective flags and component flags at once.

 

I like the tree idea, it makes better use of screen space than having a separate list box for objectives and components. It could be a simple left/right affair, with a custom widget panel displayed for each selection type (parent objective, and each type of component).

Link to post
Share on other sites
@Orbweaver: Yeah, that sounds reasonable. Also, I forgot to point out that I added functionality on the worldspawn where you can set targets on it to trigger things right at the beginning of the map, so the initial starting objectives could be added as a target to the worldspawn, if you want to differentiate between starting objectives and ones that are added later in the GUI. Gildoran mentioned another way to do that that's already in D3 though, like maybe setting WaitForTrigger to 0 on any target_* entity, or something.

 

Ah, that's how you did it. :) I added a scriptcall in my map adding it to the player like this.

 

entity ent = findEntity("myObjectiveEntity");
ent.Activate($player1);

 

Or maybe a GUI where you only view the properties of one objective at a time would work better, whatever works. I'm just suggesting that the objective properties and component properties could be separated somehow so as not to overwhelm one with all the objective flags and component flags at once.

 

I think having the GUI for the objective as a treeview (kind of) would be best. After all, any given objective can be constructed by an arbitrary number of components that contribute to this particular objective. So probalby a split window with one side having a tree, showing the main objective, the leaves being the components, and on the other side the properties for a selected node would be a good representation of it IMO.

Gerhard

Link to post
Share on other sites
  • 1 month later...

Brief progress update on the Objectives Editor:

 

* Enumeration, creation and deletion of Objectives Entities (target_tdm_addobjectives) from the map, along with detection of whether they are active at map start (triggered by worldspawn)

* Display and editing of Objectives on a given Objectives Entity, with the description, initial state and flags (visible etc)

* Creation and deletion of Objectives

* Writing new Objectives to keyvalues on the entity (obj2_blah_bleh)

 

TODO:

 

* Change the triggered-by-worldspawn status, currently it is only displayed

* Parsing and handling of objective Conditions (probably in a separate dialog).

Link to post
Share on other sites

Looks good so far!

 

I have a question: relative to what point is the add_objectives entity placed in the map? I gather that this is done randomly in a given environment. Does this happen relatively to the origin? If yes, this could be outside of the map in the void as well (admittedly for strange map layouts, most maps start at the world origin).

Link to post
Share on other sites

That's a very good point. I wanted to keep things simple by spawning the entity withing a certain distance of the origin, rather than having the mapper type in a numerical location, but as you point out this could result in the entity being placed outside the map.

 

Perhaps I should spawn the entity within a certain distance of the camera's location, rather than the world origin?

Link to post
Share on other sites

I would choose the info_player_start entity, if it exists. If that is non-existent, the camera position could be used (or a warning could be displayed so that the mapper can check if the entity is within bounds).

Link to post
Share on other sites

That's a good idea, I will try that. It is unlikely that a mapper will create objectives before he has created an info_player_start (which is necessary to playtest the map), and if so a warning and fallback to create-at-origin would be sufficient.

Link to post
Share on other sites

You can also require the mapper to place the info_start_player first. After all, what sense does a map make if this is not present? None. So you can just as well require it as a pre-condition and show an error message in that case.

Gerhard

Link to post
Share on other sites

Yeah, that makes sense that initial starting objectives would be placed around the player start. Maybe we can do the same thing for starting inventory items and weapons as well? (As I understand it, these will be actual entities that are placed, given a certain flag and then get sucked into the player's inventory?)

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.


×
×
  • Create New...