Jump to content
The Dark Mod Forums

Used_action_script not working


Destined

Recommended Posts

Hi all,

 

I cannot get the used_by_action_script to work. I have created a cutom inventory item (name Item, inv_name Item) that I want to be used on another entity to run a script. The second entity is a func_static with "frobable 1", "used_by Item" and "used_action_script test_usedby", the latter of which only prints a "script is running" to the console. This should be how it is described on t he Wiki. But for some reason I cannot figure out, the setup does not work. The script is working (I tested that by using frob_action_script). Can anyone tell me what I am missing? It may be worth to mention that the "Item" flashes green, whenever I use it from the inventory. Maybe I am missing something on the inventory item?

Link to comment
Share on other sites

Can you post the entity definitions and the script. Would make it easier to understand what is going on.

 

I have used some similar setup in my first FM. There is a lever that is used as a 'key' on a generator.

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

For the inventory item I used a "atdm:moveable_custom_item" entity (I have deleted the "editor*" spawnargs here).

 

"classname" "atdm:moveable_custom_item"

entityDef atdm:moveable_custom_item
{
"inherit" "atdm:moveable_small_base"
"model" "models/darkmod/player_equipment/airpotion.lwo"
"mass" "0.6"
"friction" "0.1"
"bouncyness" "0.1"
"snd_bounce" "tdm_impact_small_hard_object"
"notpushable" "0"
"inv_category" "Special"
"inv_droppable" "1"
"inv_icon" "guis/assets/hud/inventory_icons/breathpotion_icon"
"inv_map_start" "0"
"target" "-"
"scriptobject" "InvTriggerScript"

"name" "Item"

"inv_name" "Item"
}

 

 

The item to be used on is a func_static:

 

 

"name" "func_static_1"

"frobable" "1"

"model" "models/darkmod/kitchen/cauldron_large.lwo"

"used_action_script" "test_usedby"

"used_by" "Item"

 

and the script is a simple test script

void test_usedby()
{
sys.print("\nscript is running");
}

I have attached the test map and the script. According to the Wiki the "used_by" and "used_action_script" should suffice to get it to work, unless I am missing somehting...

test_usedby.map.txt

test_usedby.script.txt

Link to comment
Share on other sites

IIRC the it is intented to derive your entity from this one in your own def. Btw.: Used_action_script is intented to be used on entities that get used by anouther entity. So the script gets called when you use the inventory item defined under used_by on it. However, if it is an entity that gets put in your inventory, the entity in your inventory will probably have a different name then the one you put in the map, as they are not the same entities normally. The typical approach when picking up something (like an arrow or a flashbomb for example) is, that the entity in the world gets removed and a new inventory entity gets spawned and added to inventory. This is because the entities in the world and the ones used in your inventory are normally different kinds of entites (different defs). You could try using "used_by_inv_name" "item", as this one will be like you defined 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

What do you mean by your first sentence? I don't really get it.

 

I already tried the "used_by_inv_name" apporach, but it also did not work. I also tried to specify the used item with "used_action_script_Item" as described on the Wiki. Do you know of a FM that uses this mechanism? I would like to check a working example and compare, but don't really know which mission uses it.

Link to comment
Share on other sites

Derivation means that you do the following

 

entityDef nameOfYourEntity
{
    "inherit"    "atdm:moveable_custom_item"
     // add custom spawnargs here
}

This way you create an entity that inherits all the properties from atdm:moveable_custom_item (as it is derived from it), but have it tweaked the way you need it to be. This is useful if you want to use several entities of that kind. In your case it might not be needed. It is a term from object-oriented programming. The definition system is based on that principle (the german term is Vererbung).

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

Ok, I think I got that, but what does it have to do with the problem at hand? Do I need a completely new definition for my custom item? If so, it should be mentioned on the Wiki. As I said, it would be great to have a working example, as it is easier to determine the error in my case...

Link to comment
Share on other sites

Ok, I tried something new and did not use my custom item, but used "used_by_classname" "atdm:playertools_lantern" and it worked, so the problem appears to lie on the custom item. I also tried "used_by_classname" "atdm:moveable_custom_item", but it did not work again. So, the item that gets transfered to the inventory does not appear to be registered as a moveable_custom_item anymore, but I think we are getting closer. I just don't know, why "used_by_inv_name" did not work, as this is definite.

Edited by Destined
Link to comment
Share on other sites

I finally figured it out: The custom item needs the spawnarg "usable 1", so it actually can be used on another item. I will add this information to the Wiki page. Maybe we should consider to include this spawnarg to the *_custom_item's general definition.

However, now a new error occurs: The script runs 10 times directly in succession. This only happens when I use the custom item. When I use a setup with a "frob_action_script" it runs only once.

Link to comment
Share on other sites

Glad you've figured it out. :)

 

 


what does it have to do with the problem at hand?

 


This is useful if you want to use several entities of that kind.

Regarding your script problem, there is a simple workaround. You need a global variable to store whether the function has already been called.

 

 

float hasBeenExecuted;
void testScript()
{
    if (hasBeenExecuted) return;
    hasBeenExecuted=1;
    //your code goes here
}
void main()
{
    hasBeenExecuted=0; //add this line to main method, to make sure the variable really starts as zero
    //moar code
}

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

Ok, now I think I am going crazy. I tried to modify the script, so it would only run once. I used a script that looks as follows:

void test_usedby()
{
float RunScript = 0;
if (RunScript == 0);
{
sys.print("Start script\n");
RunScript = 1;
}
}
and thought, this should let the RunScript start at 0, so the if-function is applied, the script runs and as the RunScript is now 1 it would not run again. But the script still ran several times. I know my scripting skills are crap, but this looked like it would pretty straight forward :( Could you tell me, what I am doing wrong?

Link to comment
Share on other sites

Every time the script function gets executed, you set RunScript to zero, and than check whether it is zero :D The initialization of RunScript (thus meaning setting it to zero) takes place only once and it happens in the main routine. So put the line RunScript = 0 in the main method. Note that RunScript is global, so the definition (float RunScript;) has to happen outside the functions. The rest is fine except that RunScript=1 should be executed before all other commands.

 

This is how your script could look like:

 

float Runscript;  // define global variable
 
void test_usedby()
{
    if (RunScript) return; // skip execution if the function has already been called
    RunScript=1;            // flag that the function has already been called
    sys.println("Start script"); // when using println, you don't have to use \n at the end
    ...                               // additional code
}
 
void main()
{
    RunScript = 0; // initialize global variable
}

 


I know my scripting skills are crap

they are

 


but this looked like it would pretty straight forward

it is :P

 

When you talk to a human it isn't that important to be a houndret percent precise with everything you say, as the person you are talking to will normally possess some intelligence to interpret what you are saying and get the idea. Programming however means that you are trying to explain something very simple to someone very, very stupid. The way of thinking or in better words non-thinking of a computer is something everyone who attempts any sort of programming has to get used to. This is normal and took everyone of us quiet some time. Don't get demotivated by that. :)

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

I hope you understood that I meant the computer, not you :)

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

Yes, I did :smile:

I played around with it a bit and the only thing I still don't get are two things:

1. what does "if (RunScript) return" actually do? I.e. how does it check that if this script already ran?

2. Why does it not work with if (RunScript == 0)? The code should run the first time and set RunScript = 1. When it tries to run it again, it should check if RunScript = 0, note that it isn't and consequently not run the script again. But it does, and that does not make sense to me.

Link to comment
Share on other sites

  1. floating point numbers in logical expression are evaluated as true if they are nonzero, and false if they are zero. This is a C-Style convention and doesn't work in most programming languages, but as the script is loosely based on C/C++ (the language the game was written in), it was overtaken. The return command causes the code to return to the point where the function was called and proceed from there on. It basicely causes the function to be exited
  2. you can do it like that, too, but you will have an additional code block (the stuff inside the curled brackets). More brackets make the code harder to read and create an (minor) overhaul on performance. In addition, don't write (RunScript == 0), use (!RunScript) instead. As said, floats are interpreted as booleans by the code and you never compare to constant boolean values (it is not false per se, but it is terrible, terrible style :) )

 

note that it isn't and consequently not run the script again. But it does, and that does not make sense to me

It is zero, because you set it to zero at the beginning of the function. So everytime the function gets called the first thing it does is setting RunScript to zero and than checks whether it is zero, which is obviously always true because you always set it to zero.

 

Go through your program step by step and write down the values of your variable(s). A table can help here. You will pretty easely see the issue.

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

Thanks again for explaining and for being so patient with me!

I never thought that the float would be interpreted as a boolean by the srcipt :blush: With that in mind, it makes sense.

Regarding my script (even if it is terrible style ;) ), I still cannot get the "if" function to run properly. I changed it, so the definition of RunScript is done in the main() function and got a script like this:

void test_usedby()
{
if (RunScript == 0);
    {
    sys.println("RunScript = "+RunScript);
    RunScript = 1;
    }
}

Now the script still runs several times and prints "RunScript = 1" every time after the first. So, RunScript is definitely set to 1 (otherwise it would not be printed as such), but the "if" function appears to get ignored. After this, I won't bother you anymore, as either everything is cleared up, or I will just accept, that I will need help for each little piece of script I will try to whip up for missions I make.

 

BTW: I still don't know why the used_by function calls the script several times in the first place. In my case, it is fine to deactivate the script after the first run,but what if I want it to use the script on multiple occasions or count how often the item was used? Maybe I could ask greyman, if he knows what's going on here? In general, the multiple runs complicate the system unnecessarily.

Edited by Destined
Link to comment
Share on other sites



void test_usedby()
{
if (RunScript == 0); // <-- semicolon terminates the if
{
sys.println("RunScript = "+RunScript);
RunScript = 1;
}
}


The 'if' statement is a no-op because it is terminated with a semicolon,

and the following block is no longer a part of the if statement.


I've been bit by that bug many times.


That syntax is used for one line statements:



if (condition) DoStuff();

You could write 'if' statements with only brackets:



if (condition) { /*do stuff*/ }

if (condition) {
/*do stuff*/
/*do stuff*/
}

if (condition) //<-- no semicolon here
{
/*do stuff*/
/*do stuff*/
}


Link to comment
Share on other sites

 


BTW: I still don't know why the used_by function calls the script several times in the first place

I would guess that the code checks whether you use or frob an item every frame. This means a check every 16ms or so. So if you press the button you probably do so for several frames, and each frame the function gets called. It actually makes sense if you think about automatic weapons for example, but I'm not sure on this. Let's just accept it is like that. (To really find out why this happens one would have to investigate the respective parts in the source code).

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

That sounds likely. Especially, because the number of calls varies. I will leave it at that. Thanks again for your time and small scripting lesson :)

 

One afterthought (I hope this really is a short one, this time): Do you think it might work (using my inelegant method) to "block" the script from being run several times for a specific time, by using something like this:

void test_usedby()
{
if (RunScript == 0);
    {
    sys.println("RunScript = "+RunScript);
    RunScript = 1;
    sys.wait(1);
    RunScript = 0;
    }
}

This should block the script for 1 s as RunScript is turned back to 0 after that time. Is that correct? That way it would be possible to call the script several times, but only after waiting 1 s.

Link to comment
Share on other sites

This will work in theory. However, sometimes you have to start a function in a thread to be able to use the wait command (this varies). If you are doing this, you don't have to wait a specific time, though. You can let the script function be accessible again once it has finished. This would look like this.

 

void myFunction() // this gets only called by the script, not the game
{
  // put your code here
}
void test_usedby() //the function called by the game
{
  float threadnum;  // variable to store the threadnumber later on
  if (RunScript == 0)
  {
    sys.println("RunScript = "+RunScript); // this is nonsense, the output will always be "RunScript = 0"
    RunScript = 1;
    threadnum = thread myFunction(); // perform the actual code in a seperate thread
    sys.waitForThread(threadnum); // wait until the above called thread has terminated
    RunScript = 0;                           // reset flag to enable the game to call this code again
  }
}

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

Thanks! I think I will try this soon. I want to update the Wiki article about the used_by system (add the requirement of the "usable" spawnarg and the multiple call issue) and thought about adding a solution to the problem as well, but am not sure if I should, as the article states that scripting is required anyway. Still, the multiple calls may be confusing, especially for people who did not write the script themselves and just got it from another person.

Link to comment
Share on other sites

I still have not found the time to test the threaded script, but I have updated the Wiki article with the following note:

 

 

Note: The inventory item will have to have the spawnarg "usable" set to "1" in order to be used. This spawnarg is not automatically included in the custom item entities. Furthermore, when the item gets used, it will get called once per frame for as long as the item is used. Please take precautions if you want your script to only run once.
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.
      · 2 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...