Jump to content
The Dark Mod Forums

Can I pass an entity name to a map script?


Fidcal

Recommended Posts

I'm experimenting with player notes and can add them to the inventory but using a separate script event for each readable entity. This is fine but I was wondering if I could do it with one script event.

 

Is there any such construction as:

 

Get Calling Entity Name (the atdm:target_callscriptfunction entity name that is triggered)
getEntityKey from above (eg, name of readable entity to go in inventory)

As a test I tried passing the readable entity name from a named atdm:target_callscriptfunction using getEntityKey without success. I've passed floats before OK but maybe spawnargs that are not defined in the code default to floats? Nor could I convert the float value to an entity value in the script. But there is no value in this anyway if I can't get the calling entity name as I would still need separate script events for each.

Link to comment
Share on other sites

  • Replies 62
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Posted Images

The target_callscriptfunction entity just calls the method, without passing any parameters, this is not supported.

 

Several possibilities:

 

- Is this happening on frob? If yes, you could use a custom frob action script which reads the name directly from the player note entity on frob.

- Let somebody/me add support for that option and wait for TDM 1.03.

- Add a custom entityDef with a custom scriptobject defined in your map script. Then use target_callobjectfunction to call that entity. You can place multiple entities of that type in your map, with each entity carrying the desired entity name in its spawnargs. The object is then using the info in its spawnargs to add the player notes. One script, but multiple entities in the map. Maybe more work than it's worth, imo.

 

Finally, it is possible to create a custom response effect, which is defined in your map's .def files, which might be a nearly no-code solution, but a bit on the complex side. I can elaborate on this, if the above possibilities are not satisfying. You'll need to create a new script event once, but still need multiple blue-room func_statics for each player note.

Link to comment
Share on other sites

Thanks for your ideas greebo.

 

It's not exclusively on frob - new player notes might be added to the inventory triggered by all kinds of situations.

 

As you say, your other ideas might be more work than it's worth. Currently my method is very simple and I'm inclined to stick with that for the time being.

Link to comment
Share on other sites

I think it's worth getting a function to do this job in 1.03, because this issue comes up a lot. There are so many things that could be made so much easier if one script could have any arbitrary entity call it and the script could get its name (and through that its spawnargs) -- writing notes after events, mixing ingredients to make potions, multistage elevators... You could fill a blueroom with buttons and control all manner of complex puzzles and sequences very intuitively with one script.

What do you see when you turn out the light? I can't tell you but I know that it's mine.

Link to comment
Share on other sites

Maybe a general purpose template script object def is what we want. I don't even know if it's possible. Where you copy the template to your map script, rename it and set any spawnargs then set the script object name in the map with spawnargs.

 

The same thing might then be used for almost anything. To get a friendly AI to give you something might only need one of these where in a conversation he is carrying said object, moves to you, leans forward to hold it out then it is added to the player grabber.

 

I just don't know enough about it to evaluate its worth.

Link to comment
Share on other sites

Could you please create a testmap with two notes and some triggers or whatever you want to cause these be added to the inventory?

 

I am pretty sure the already existing spawnargs can acomplish what you want, but your description is a bit vague (a testmap really helps!)

 

The the code for "callobjectfunction" to optinally pass arguments was already created by me:

 

idTarget_CallObjectFunction

Tels:

If "pass_self" is true, the first argument of the called object function is the
triggered entity. This is useful for teleportTo(target), for instance.

If "pass_activator" is true, the first argument of the called object function
is the entity that caused the trigger.
This is useful for atdm:voice, for instance.

If "pass_self" and "pass_activator" are true, then the order of arguments
is first "target", then as second argument "activator".

Note that the method you want to call needs to have exactly the number
of arguments, e.g. zero (pass_self and pass_activator false), 1 (pass_self
or pass_activator true) or two (both are true).

 

Look for instance at:

 

entityDef atdm:trigger_voice
{
   "inherit"                       "atdm:target_callobjectfunction"
   "editor_displayFolder"          "Sound"

   "call"                          "speak"

   // the activator entity is not actually used in speak() but it demonstrates
   // that passing it works (usualy giving $player1 as activator):
   "pass_self"                     "1"     // the setup of these two pass_foo spawnargs
   "pass_activator"                "1"     // will call "atdm:voice->speak( trigger, activator );"

 

Instead atdm:target_callobjectfunction you would want to inherit from:

 

entityDef atdm:teleport
{
       "inherit"                               "atdm:target_postscriptevent"

 

Although looking at the code for postscriptevent, I have the hunch that the code is actually buggy and only passes the argument when "pass_self" is false. (Edit: Fixed in code, this was only in the fallback path on postscriptevent when there was no event, in which case we tried to call the "object function".).

 

In addition, "pass_activator" is not implemented for postscriptevent.

 

So a testmap would be really cool, so I don't waste my first half hour constructing one, but instead can just fix the bugs and implement your wanted feature :)

"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

OK. test/player_notes.map and map script committed along with test_player_notes.xd

 

Two levers each puts one of the two test notes into the inventory.

 

This works fine but uses two script events.

 

Thanx, I'll look into it the next half hour (while I wait for a recompile :)

"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

Looked into it, but it needs a new spawnarg for callobjectfunction so needs more than 5 minutes. Could you please file a tracker entry and assign it to myself (and also please link this thread in the "additional info" box). Thank you!

"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

When you get this running we need to write a tutorial in a generic form.

 

I'll ask a dumb question to see if I get this. So can I make like 3 buttons or generic targets or whatever in-game (with a custom .def that inherits "atdm:target_callobjectfunction" or "atdm:target_postscriptevent"), each with the same spawnargs "call" "do_something" and "pass_self" "1", so that when triggered they call the same object and it does X Y or Z based on which button was pushed / target was triggered?

 

Then I just make a .script file with something like

void do_something( entity target )
{ 
if target = "$button1" { do X }; 
if target = "$button2" { do Y }; 
if target = "$button3" { do Z }; 
}

Is that how it goes?

 

That seems to me to be the generic situation.

Well, I'll let you guys write a tutorial. But that's how I seem to understand it.

What do you see when you turn out the light? I can't tell you but I know that it's mine.

Link to comment
Share on other sites

I understood "pass_activator" will almost always pass $player1 to the argument unless an AI causes the trigger, then it'd be $AI_name; but anyway just one of those two, not useful at all for in-game conditional puzzles and set-ups because you'll almost always get $player1. But if you want the button name itself to pass, you use "pass_self". And actually it's probably better to use a "target_..." entity to call the script function and not a button just to remember that it's getting targeted that makes the "call"; not being frobbed or pushed.

 

As for what you actually label the argument, "target" or "activator" -- the part you're correcting -- it doesn't really matter; you could use any arbitrary label. "Pass_activator" passes the player/AI name to it, "pass_self" passes the target-entity (button) name to it, and the label just helps you remember which one. Tels used the label "target" for "pass_self" because my"self" is from the "target" entity's pov, and the "activator" isn't "me" but "the guy triggering me", usually $player1. So what I wrote followed that convention. (In fairness, the terms "target" and "activator" can be a little easy to mix up.)

 

But it's probably just as good to label the argument & entities very specifically by their task like

void do_something(entity pill_condition) {
if pill_condition = "$target_ate_the_red_pill" { do X }; 
if pill_condition = "$target_ate_the_blue_pill" { do Y }; }

. The point is "pass_self" is what you want here.

What do you see when you turn out the light? I can't tell you but I know that it's mine.

Link to comment
Share on other sites

@demagogue and @fidcal:

 

No, not really :)

 

First, I think there shouldn't be a script nec. unless you really want to do wildly different things. But if you just want to call a function with some "fixed" arguments, currently possible are:

 

atdm:target_callobjectfunction:

 

Lever/Trigger == linked to ==> atdm:target_callobjectfunction == linked to ==> (multiple) targets

 

For each target, it calls a Method on the target. This only works for entities which have a script object, e.g. light holders (where you could f.i. call LightsOff()).

 

* target->Method() (callobjectfunction)

* target->Method(triggered_entity (the atdm:target_callobjectfunction itself)) (callobjectfunction, pass_self=1)

* target->Method(activator) (callobjectfunction, pass_activator=1)

* target->Method(triggered_entity, activator) (callobjectfunction, pass_self=1, pass_activator=1)

 

Triggered_entity is the atdm:target_callobjectfunction entity, and activator is the player if he runs through a trigger, or if he frobs a leaver. Or an AI if they run through a trigger etc.

 

The atdm:target_postscriptevent works almost the same, but it doesn't all a Method(), instead if posts a script event. Which is just a fancy way to do $entity->somescriptevent().

 

Lever/Trigger == linked to ==> atdm:target_postscriptevent == linked to ==> (multiple) targets

 

 

However, it currently only supports "pass_self":

 

* target->ScriptEvent() (atdm:target_postscriptevent)

* target->Method(triggered_entity (the atdm:target_callobjectfunction itself)) (atdm:target_postscriptevent, pass_self=1)

 

There is also atdm:target_callscriptfunction, but it doesn't even have pass_self, so it only allows:

 

* GlobalScriptFunction()

 

Lever/Trigger == linked to ==> atdm:target_callscriptfunction

 

As you can see, in this case the function doesn't know who triggered the action, and which entity relayed it and on what target (as targets are not considered at all).

 

 

Now, what Fidcal wants to do is:

 

activator->AddInvItem($target);  // activator is the player here

 

E.g. the roles of activator and target are reversed. The reason is that "AddInvItem()" always adds the given item to the inventory of the entity it is called on, so you MUST call it on player1.

 

But if you look at the options above, this is simply not possible. Either is the Method ("AddInvItem") called on the target (and not on the player), or you don't get any target as argument and so on.

 

Now, you could use for instance create a function like so:

 

function AddToPlayerInventory(entity target)
{
 $player1.AddInvItem(target);
}

 

But currently there is no way to call it, as "callscriptfunction" does simply not pass the target along (in fact, it isn't even called for each target, but only once).

 

So we can either:

 

* spice up callscriptfunction

* or add another script event on each entity, called "AddToInv", which is the reverse of AddInvItem and can be called like so:

 

$entity->AddToInv($player1);

 

Did this description make sense? If so, it should go on the wiki :D

"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

Ok,

 

I added a script event called entity->addItemToInv(target) and it will add entity to thee target's inventory. I also added support for "pass_activator" on PostScriptEvent entities.

 

So to test it:

 

* get someone to compile a new windows DLL

* update SVN

* dmap and load test/player_notes.map

 

As you can see, it works when you pass through the arch, but not when you flip a lever. That is because the levers do not relay the activator (e.g. the player) to their target entity, but instead themselves.

 

I think that is a bug, but I am not sure.

 

So what do we do now? Fix the binaryFrobMovers to relay the proper activator along? Or work around in the postscript entity somehow?

 

Adding entity PlayerNotes3 to inventory of atdm_numberwheel_lever_3. (lever flipped, wrong)
Adding entity PlayerNotes01 to inventory of atdm_numberwheel_lever_3.
Adding entity PlayerNotes4 to inventory of player1. (step through portal, right)
Adding entity PlayerNotes7 to inventory of player1.

 

Edit: The code for BinaryFrobMovers indeed has this

 

 ActivateTargets(this);

 

which is wrong, it should be:

 

 ActivateTargets(activator);

 

However, the activator is not stored with the entity, but the ActivateTargets() happens "later" after activate (e.g. on fully close, fully open etc), so I think this needs to be fixed by:

 

* store the activator when the Activate() happens

* later use this to relay this to the targets

 

This also might tie into the problem that AI doesn't know who opens a door or flips a lever:

 

http://bugs.angua.at/view.php?id=2338

"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

I'm confused as usual. Can you define what you mean by 'activator'?

 

The entity that "touches the trigger", "rubs the beaver" er I mean "frobs the leaver" etc.

 

Here is the chain where the Activate() event passes along:

 

activator (usually player, but can also be an AI) => leaver, button, door or trigger => atdm:postscriptevent => targets of this

"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

For my purposes I'm not interested in the activator, only the triggering entity.

 

In these examples:

 

An objective completes and triggers something to add note #1 to the player inventory.

The player reads a book which triggers something to add note #2 to the player inventory.

An AI closes a door which triggers something to add note #3 to the player inventory.

An AI attacks another AI and his death triggers something to add note #4 to the player inventory.

 

 

For the add inventory what I think we need is a method of passing to a map script from a script calling entity:

 

The entity that triggered the script calling entity: button, door, whatever. Might be a stim response or an objective completing (but I don't know if they would have to trigger a relay trigger for this.)

 

So the script would say if trigger = entity7 then add note #4

 

But a more useful and generic method would also pass several other variables, by default null and often unused but available if the mapper wants them. The mapper's script would be something like:

 

void myscript(activator, triggering_entity, entity1,entity2,float1, float2, float3)

 

For add inventory only the second would be used.

 

Instead of the floats maybe strings or one of those triple value things whose name I forget. Strings can hold tons of stuff even if there were only one but I don't think scripts have any string slicing functions so that would not help.

Link to comment
Share on other sites

For my purposes I'm not interested in the activator, only the triggering entity.

 

Er, no, you are still interested in the activator. :) In your cases you "assume" the activator is the player, but somehow the code needs to know this, it can't assume it somehow.

 

In these examples:

 

An objective completes and triggers something to add note #1 to the player inventory.

The player reads a book which triggers something to add note #2 to the player inventory.

An AI attacks another AI and his death triggers something to add note #4 to the player inventory.

 

I have not seen these cases in the testmap, so I will add this. :( The next time please add all cases to the testmap - I can only fix bugs/add features if I am aware of them!

 

An AI closes a door which triggers something to add note #3 to the player inventory.

 

This case is not covered yet by the code, as it assumes that entity A activates something, but the target inventory is the player inventory. Ah crap. :(

 

So I need to extend CallScriptFunction, too....

 

Man, its now noon, and I am working on this since 8:00, I didn't plan on spending my entire sunday on this... *sigh*

 

For the add inventory what I think we need is a method of passing to a map script from a script calling entity:

 

The entity that triggered the script calling entity: button, door, whatever. Might be a stim response or an objective completing (but I don't know if they would have to trigger a relay trigger for this.)

 

So the script would say if trigger = entity7 then add note #4

 

But a more useful and generic method would also pass several other variables, by default null and often unused but available if the mapper wants them. The mapper's script would be something like:

 

void myscript(activator, triggering_entity, entity1,entity2,float1, float2, float3)

 

For add inventory only the second would be used.

 

Instead of the floats maybe strings or one of those triple value things whose name I forget. Strings can hold tons of stuff even if there were only one but I don't think scripts have any string slicing functions so that would not help.

 

No, it will will not pass multiple along. It will call the same function multiple times, but with each target like so:

 

myscript(activator, triggering_entity, target);
myscript(activator, triggering_entity, target1);
myscript(activator, triggering_entity, target2);

 

That way it will be consisten with the other target entities which also call a Method or post an event per target.

 

As for the "Multiple parameters", this would be really really hard to support in code, because you would need to:

 

* add spawnargs like "param0", "param1" etc

* but these could only be fixed strings, if you want f.i. an entity, then: "param1" "myentity" would pass the string myentity along, not "entity $myentity" what you would need.

* And all these need to be relayed to the function be called in the proper order and amount. Because D3 also checks that the number of params is correct, which means if you have:

 

myfunc(param1, param2);

 

you cannot call it as:

 

myfunc(param1);

 

as it will complain that there is a param missing.

"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

Tracked the issue with BinaryFrobMovers not relaying their activator along: http://bugs.angua.at/view.php?id=2390

 

and fixed it in code with revison #4216.

 

The code now stores the entity index number of the activator (and Save/Restores that, so you can quicksave/load between touching the leaver, and the leaver completing its movement), and upon activate it does:

 

ActivateTargets( m_iActivator < 0 ? this : gameLocal.entities[ m_iActivator ] );

 

The testmap still does not work, tho. The reason is that the levers in the testmap are:

 

atdm:numberwheel_lever

 

and these do on frob:

 

frob_lever(lever);

 

and this in turn does:

 

lever.operate();

 

which completely neglets passing the activator along. Ah crap :(

 

Edit: This could be fixed by changing the script to:

 

// For the lever
void frob_lever(entity lever)
{
       lever.Operate();
       lever.activateTargets($player1);
}

 

However, I am not sure, what would happen if an AI uses the button? How could I make an AI use the button so I can try what happens?

"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

I will try to set up the test map so the player is not the activator.

 

For player notes I don't care who pulls the lever. ;) I'm only interested in the lever. I'm not even interested if its a lever. All I care about is what is the name of the final entity that targetted the scriptCaller.

 

The specific examples are irrelevant. They were only to demonstrate the common thing needed (by me, for player notes) is the trigger name.

 

Another example (of just passing the trigger entity).....

 

AI > locks gate > delay4 > scriptCaller2 > playerNotes(delay4)

 

void playerNotes (entity)
{
if entity = delay4 then add note #6 to player inventory.
}

As for the multiple params for other general useage what I was thinking was a fixed but useful number of params. If they can only be strings then say three plus the activator and trigger entity:

 

scriptCallerEntity
param1 "99"
param2 "LordBogWorthy"
param3 [not defined by mapper so defaults to 0]

 

In this example I am not interested in the activator or the trigger and I only need 2 params even though the others are passed to the script anyway I just don't use them. If there IS an activator then the scriptCaller can pass it but the mapper script ignores it. If there is NO activator or the scriptCaller cannot detect it for some reason then the code passes NULL of some sort.

 

void myscript(activator, triggering_entity, param1, param2,param3)
{
if param1 = 99 AND param2 = "LordBogWorthy" then do...
}

 

It might also be useful if the scriptCaller can pass ITSELF.

Link to comment
Share on other sites

I've updated the test map with two added doors. One auto opens and target one script entity; the other is opened by an AI.

 

Not working at the moment but it provides a mean of testing without an activator and with an activator that is not the player.

Link to comment
Share on other sites

I've updated the test map with two added doors. One auto opens and target one script entity; the other is opened by an AI.

 

Not working at the moment but it provides a mean of testing without an activator and with an activator that is not the player.

 

Thanx, I'll see if I can find some time tonight, atm knee-deep in the LODE stuff... :wacko:

"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

It might also be useful if the scriptCaller can pass ITSELF.

 

This is exactly what "pass_self" is, I thought. So you don't even have to pass the "params" because once the scriptCaller's name passes to you, you can just getKey them directly by that name.

 

So I think you just need the spawnargs on scriptCaller1:

call "playerNotes"
pass_self "1"
param1 "99"
param2 "LordBogWorthy"

 

And the script is like, for the simple conditional (I'm adding a 2nd case for good measure):

 

void PlayerNotes (entity scriptCallerName) { 
if scriptCallerName = scriptCaller1 then {add note #6 to player inventory};
if scriptCallerName = scriptCaller2 then {add note #7 to player inventory};

 

And for the multiple params:

 

void PlayerNotes (entity scriptCallerName) { 
someNumber == getKey.scriptCallerName( param1 );
lordsName == getKey.scriptCallerName( param2 );
if someNumber = 99 AND lordsName = "LordBogWorthy" then do...
}

 

This is why I thought pass_self was so much more straight-forward than pass_activator. You can get everything directly off the scriptCaller itself and happily don't have to care who or what triggers it.

 

For my purposes I'm not interested in the activator, only the triggering entity. ... All I care about is what is the name of the final entity that targetted the scriptCaller.

 

Neither pass_self nor pass_activator pass this. You only get the triggered entity, i.e., the scriptCaller (pass_self) or the thing triggering it (pass_activator), as I understood Tels' description. You can't get whatever button or lever triggers it.

 

I don't know why Tels wants you to pass the activator (which makes me worry I misunderstand something). As I understand it, I guess you could, but then the easiest way to pass parameters would be putting them as bunk spawnargs on the AI pulling the lever and getKey them (for pass_activator) instead of on the scriptCaller itself (with pass_self, which seems more intuitive), and you'd have 2 different AI frobbing levers to call a scriptCaller to handle 2-condition schemes (like your 2 notes) with pass_activator, instead of (more logically IMO) having 2 different scriptCallers triggered for each case with pass_self. If I understand pass_self right, that seems the way to go. Or do I just really misunderstand what pass_self is?

What do you see when you turn out the light? I can't tell you but I know that it's mine.

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

    • nbohr1more

      Was checking out old translation packs and decided to fire up TDM 1.07. Rightful Property with sub-20 FPS areas yay! ( same areas run at 180FPS with cranked eye candy on 2.12 )
      · 2 replies
    • taffernicus

      i am so euphoric to see new FMs keep coming out and I am keen to try it out in my leisure time, then suddenly my PC is spouting a couple of S.M.A.R.T errors...
      tbf i cannot afford myself to miss my network emulator image file&progress, important ebooks, hyper-v checkpoint & hyper-v export and the precious thief & TDM gamesaves. Don't fall yourself into & lay your hands on crappy SSD
       
      · 5 replies
    • 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.
      · 7 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
×
×
  • Create New...