Jump to content
The Dark Mod Forums

Scripting feature proposal: discovering entities


SteveL

Recommended Posts

Proposal: a new Script Event that'll let a script find out what entities are in a map.

 

This is something I really wanted when I first discovered TDM -- I just checked back to see whether it was my first post, and it turns out it was my 5th. It would let scripters write "general purpose" scripts that don't need a lot of configuration by the mapper to use them, and it'd make it a lot easier for scripters to write custom scripts for other mappers to use in a single map. That would do a lot to open up the power of scripting to people who don't write them because there'd be more off-the-shelf scripts possible, and failing that, getting someone to write a script for you would often be a lot less work for both scripter and mapper.

 

The kind of scripts I'm thinking about:

  • Make all undead turn into ragdolls when the player drops the bewitched mace into the holy water stoup.
  • Make all unarmed commoners panic and run to their flee points.
  • Disable all traps or arm all mines or put out all the electric lights.

Right now these kinds of scripts need the mapper to set them up specifically for each affected entity in the map. They either have to edit the script and list the entities by name, or they have to set up a single tracker entity that targets all the others. When they add or remove entities in the map, the setup has to be amended. And if you're a scripter writing a script for a mapper, you have to start off with a conversation about what method they'll use and tell them how to adapt it. You can't just respond to a question in the newbie thread with a fully working script that took you 2 minutes to write.

 

There are some ways round it in some situations. The best examples I've seen are in Obsttorte's Hitman-style script and his ingenious use of stims added at runtime. But there are plenty of examples where entity discovery would be really useful.

 

Obviously, cycling through all entities isn't something you'd do every frame else it'd drag down performance. But it could be done once when a special event happens, or once at map start (the script can store the list of eligible targets that it discovers for later use by making them targets of a dummy entity. I always use a target_null.).

 

Implementation

I'd suggest a single script event that works like the others that cycle through list of things: sys.getNextEntity(string classname, entity lastMatch); where classname is optional and you start the search with $null_entity.

 

The game stores the entity list in several forms. I judge the best one for this purpose is the array gameLocal.entities. In the game code, every entity knows its position in that index, so picking up the search and proceeding to the next one would be easy.

Link to comment
Share on other sites

The entities listed by you are all using scriptobjects. This allows for a pretty easy implementation of the examples you've mentioned on a per map basis.

 

Nevertheless it may be a useful feature. I would also recommend an additional function like sys.getNextEntity(string key, string value, entity lastMatch);, which would allow to traverse through entities which have the spawnarg key set to value. This way you could also traverse through a set of entities which do not belong to the same spawnclass (as the spawnclass is stored as a spawnarg itself, this would actually include the above feature).

 

I guess doing so in the game code would be faster then doing it in a script?!

FM's: Builder Roads, Old Habits, Old Habits Rebuild

Mapping and Scripting: Apples and Peaches

Sculptris Models and Tutorials: Obsttortes Models

My wiki articles: Obstipedia

Texture Blending in DR: DR ASE Blend Exporter

Link to comment
Share on other sites

The entities listed by you are all using scriptobjects. This allows for a pretty easy implementation of the examples you've mentioned on a per map basis.

By overriding the script object you mean? Ok, but there are plenty of more general problems (find all entities of any type currently in this bit of the map, for example), where a script object wouldn't help.

 

I would also recommend an additional function like sys.getNextEntity(string key, string value, entity lastMatch);, which would allow to traverse through entities which have the spawnarg key set to value. This way you could also traverse through a set of entities which do not belong to the same spawnclass (as the spawnclass is stored as a spawnarg itself, this would actually include the above feature).

That's not quite true unfortunately, else I'd say yes that's better idea still. Every entity has a spawnclass, but they don't all have a matching spawnarg. AI Heads are an example I've seen recently in my LOD testing: their spawnclass is idAFAttachment, but they don't have a spawnarg to say so either in their entity def or in their in-game spawnargs.

 

The filter key isn't really needed though, so we could make it anything, whatever we think would be most useful, or even not have one. The script would always be able to cycle through ALL entities and do its own filtering.

 

I guess doing so in the game code would be faster then doing it in a script?!

You mean the filtering? Yes it would be faster in the game code, if we can think of a useful option. Doing it in a script means copying strings back and forth, and lots of handovers between the interpreter and the game engine. But that's what happens with every script, and it's not too important for a script that runs only once or twice during a map.

Link to comment
Share on other sites

I would also recommend an additional function like sys.getNextEntity(string key, string value, entity lastMatch);

That's not quite true unfortunately,

That said, I still like the idea of being able to filter by key-value. Most filters the scripter wanted to apply would be based on spawnargs, so it would mean shorter and faster scripts in most cases.

I could use this in the update to AC that I am doing, I already the item and its drop location.

Cool, a use case already! I'll be happy to provide the script too if you haven't already got it sorted.

Link to comment
Share on other sites

@Biker:

 

Script object for the undead ai:

custom_ai : ai_darkmod_base
{
 void init();
 void suicide(entity e, entity f); //entities not needed, you can name them whatever you want
};
void custom_ai::init()
{
 ResponseAdd(1000);  //custom stim, you may have to use a higher number if you already use some
 ResponseSetAction(1000, "suicide");  //the script to run once the stim got applied
 ResponseEnable(1000,1);  //enable the respnse
}
void custom_ai::suicide(entity e, entity f)
{
 kill();  //kill myself
}

Create a func_static in your mission, maybe your blue room and add a stim and a response to it as follows:

  • the stim is custom with the above number, custom stims are numbered beginning with 1000 (you can see the stim number in the custom stim tab)
  • the stim is inactive, the radius should be as big so it covers the whole map, and it only needs to fire once
  • the response should be to trigger stim, the effect should be activate stim (custom stim) on _SELF

Use an objective (possible hidden) that requires the player to drop the item in the specified location and add the above created func_stetic entity as completion target (so it's name).

 

What will happen than is that if the player drops the item in the location, the objective gets completed and triggers the func_static. Due to its response setting it will apply a stim over the whole map, which will cause all undead using the above script object to response to it by calling the suicide method, which will kill them.

 

EDIT: Note that this is only one of several ways to do it.

FM's: Builder Roads, Old Habits, Old Habits Rebuild

Mapping and Scripting: Apples and Peaches

Sculptris Models and Tutorials: Obsttortes Models

My wiki articles: Obstipedia

Texture Blending in DR: DR ASE Blend Exporter

Link to comment
Share on other sites

Hmm, that solution is ingenious but it's also is a good illustration of why the new script event will be useful. The script event would save you having to remember to attach a script object to all affected AI, and you wouldn't need to set up stims or anything anything else in your blueroom.

 

Back to the original topic, I second your proposal for using key-value as the filter. I reckon it's the option most likely to result in no filtering having to be done in the script itself.

 

Assuming that's what we go for, I think we should make it prefix-based like the current key search. So if you supply the key "target", you'll get "target1", "target2", etc.

 

You could also just filter by a value without a key. Find anything that uses a certain attachment, for example, without worrying whether it's a def_head or a def_attach. Or that references a certain door, without needing to know whether it's a target or a door_controller or a used_by. Even if a scripter did something silly like ask for the value "1" with no key, it'd still do no harm. You'd just get all entities like you would if using no filter.

Link to comment
Share on other sites

  • 3 weeks later...

If no-one has any objections or further suggestions, we'll go with Obsttorte's key-value filter. I'll raise the tracker this eve.

 

The normal C++ code already has methods to run through a list of entities by "spawnarg" by getting the "next entity with that spawnarg" (Or do I misremember this being just stepping through multiple spawnargs on one entity?). Adding this to the scripting side sounds very useful to me.

 

As for the heads not having a spawnarg, maybe in this case it could/should be added, so you can also find these entities by "isAIHead" "1" instead of by entity class. But this is independent from wether the scripting side should be able to loop through all entities with a certain spawnarg set, or not.

 

Adding array support to the scripting side would be another nice feature, although we have managed without it so far and it is independet of the looping, too.

"The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man." -- George Bernard Shaw (1856 - 1950)

 

"Remember: If the game lets you do it, it's not cheating." -- Xarax

Link to comment
Share on other sites

The normal C++ code already has methods to run through a list of entities by "spawnarg" by getting the "next entity with that spawnarg" (Or do I misremember this being just stepping through multiple spawnargs on one entity?)

Well, the script only allows the per entity case.

 

The easiest way to mimic arrays is a custom entity with a suitable scriptobject, which stores the entries as spawnargs on itself.

 

If you want to access the head of an ai, you have to use entity getHead().

FM's: Builder Roads, Old Habits, Old Habits Rebuild

Mapping and Scripting: Apples and Peaches

Sculptris Models and Tutorials: Obsttortes Models

My wiki articles: Obstipedia

Texture Blending in DR: DR ASE Blend Exporter

Link to comment
Share on other sites

The normal C++ code already has methods to run through a list of entities by "spawnarg" by getting the "next entity with that spawnarg" (Or do I misremember this being just stepping through multiple spawnargs on one entity?). Adding this to the scripting side sounds very useful to me.

Hi Tels, good to meet you :) I already committed this using idDict::MatchPrefix(). It looks through the spawnargs dict of 1 entity at a time, but doesn't search redundantly because it starts on the next entity after the last match.

Adding array support to the scripting side would be another nice feature, although we have managed without it so far and it is independet of the looping, too.

Agreed, it would be. Before I got into the game code I thought about supporting it by encapsulating the target_null creation and spawnarg setting in an importable script, to emulate vectors and dicts. But better to enable it in the game code if poss. Any pointers on how that could be done?

Link to comment
Share on other sites

Hi Tels, good to meet you :) I already committed this using idDict::MatchPrefix(). It looks through the spawnargs dict of 1 entity at a time, but doesn't search redundantly because it starts on the next entity after the last match.

 

Good work! It is nice to see new development (and new faces) in TDM :)

 

Agreed, it would be. Before I got into the game code I thought about supporting it by encapsulating the target_null creation and spawnarg setting in an importable script, to emulate vectors and dicts. But better to enable it in the game code if poss. Any pointers on how that could be done?

 

As far as I remember, the old scripting bindings have hard-coded and fixed types, adding arrays might be a bit difficult. The scripting language in formerly-known-as-D3 is some homegrown solution with a lot of arbitrary restrictions, in typical id fashion :D I haven't touched the code for a very long time, so you probably find it much faster than me :)

Edited by Tels

"The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man." -- George Bernard Shaw (1856 - 1950)

 

"Remember: If the game lets you do it, it's not cheating." -- Xarax

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.

  • Recent Status Updates

    • OrbWeaver

      Does anyone actually use the Normalise button in the Surface inspector? Even after looking at the code I'm not quite sure what it's for.
      · 6 replies
    • Ansome

      Turns out my 15th anniversary mission idea has already been done once or twice before! I've been beaten to the punch once again, but I suppose that's to be expected when there's over 170 FMs out there, eh? I'm not complaining though, I love learning new tricks and taking inspiration from past FMs. Best of luck on your own fan missions!
      · 4 replies
    • The Black Arrow

      I wanna play Doom 3, but fhDoom has much better features than dhewm3, yet fhDoom is old, outdated and probably not supported. Damn!
      Makes me think that TDM engine for Doom 3 itself would actually be perfect.
      · 6 replies
    • Petike the Taffer

      Maybe a bit of advice ? In the FM series I'm preparing, the two main characters have the given names Toby and Agnes (it's the protagonist and deuteragonist, respectively), I've been toying with the idea of giving them family names as well, since many of the FM series have named protagonists who have surnames. Toby's from a family who were usually farriers, though he eventually wound up working as a cobbler (this serves as a daylight "front" for his night time thieving). Would it make sense if the man's popularly accepted family name was Farrier ? It's an existing, though less common English surname, and it directly refers to the profession practiced by his relatives. Your suggestions ?
      · 9 replies
    • nbohr1more

      Looks like the "Reverse April Fools" releases were too well hidden. Darkfate still hasn't acknowledge all the new releases. Did you play any of the new April Fools missions?
      · 5 replies
×
×
  • Create New...