News:

One Minute Game Review by The Happy Friar: https://ugetube.com/@OneMinteGameReviews
Also on Rumble: https://rumble.com/c/c-1115371

idTech 4 (aka Doom 3 tech) Discord Server! https://discord.gg/9wtCGHa

Main Menu

help with a script

Started by argoon, September 24, 2016, 05:15:28 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

argoon

Hello guys can anyone that knows coding and specially doom 3 scripting see why this script of mine is not working? Is a experience of mine about making a mouse over functionality without the need to mess with the source c++ (that i don't really know at all).

First a disclamer i'm not a coder i'm just a noob at c++ coding and at Doom 3 scripting, what you see below is what i came up with, by trial&error, by reading and copypasting from various sources.

Now the important part, the code that doesn't work as i want it, is the entity.setShaderParm() bit, it highlights the object like i want it too, when i mouse over the "frob" object (inspiration from TDM ;p), but when i stop "mouse overing" the object it stays highlighted still, i tried everything some of my tries made me turn on and off the highlight but only when i mouse overed the object again, what i'm i  missing here?

The funny thing is that the code that turns off the test light (that i put for debugging) and the code to activate the func_animate works just fine. Only problem the func_animate hides it self after playing all the animations.

Sorry for the messy code...


////////////////////
//
//    global vars

#define FROB_NONE  0
#define FROB_OVER  1

entity frobEntity; // detected entity with frob enabled
float isOver_obj = false; // Is the player looking to frob object ?
float   command     = FROB_NONE;
vector traceStart, tracEnd;
float useBtn, btn0; // use button for frob, same as attack
//float highlight_on = false;
float parm11_state;
float isPressed = false;
float isFrobable; // check for the frob spwn arg value
///////////////////

/*
============
trace_objs
============
*/
void trace_objs() {



// bind objs to player head position
$ml_start.bindToJoint( $player1, "headcontrol", 1 );
$ml_end.bind($ml_start);



}

/*
void draw_ent_text_type(){
if(isOver_obj == true){
vector bbox_size = frobEntity.getSize();
vector frob_ent_origin = frobEntity.getWorldOrigin();
vector text_origin = frob_ent_origin;
text_origin_z = text_origin_z + bbox_size_z + 30.0f;
string ent_type = frobEntity.getKey("type");
frobObjText = sys.drawText(ent_type, text_origin,0.5,'0 1 0', 1, 1);
}
}*/

/*
void obj_higlight(){

parm11_state = frobEntity.getShaderParm(SHADERPARM_FROB);
sys.println("\n\nInit parm11 value is: " + parm11_state);

if( parm11_state == 0 ){
//highlight_on = false;
frobEntity.setShaderParm(SHADERPARM_FROB, 1);
sys.println("\n\nOff parm11 value is: " + parm11_state);
}
if( parm11_state == 1 ){
//highlight_on = true;
frobEntity.setShaderParm(SHADERPARM_FROB, 0);
sys.println("\n\nON parm11 value is: " + parm11_state);
}

}*/


void mouseOver()
{
traceStart = $ml_start.getWorldOrigin();
//sys.println("\n\ntraceStart value is: " + traceStart);

tracEnd = $ml_end.getWorldOrigin();
//sys.println("\n\ntraceEnd value is: " + tracEnd);

//sys.drawText("end",tracEnd,1,'0 1 0', 1, 1);

useBtn = $player1.getButtons();
btn0 = 1 & useBtn;

sys.trace( traceStart, tracEnd, '0 0 0','0 0 0', MASK_SOLID|CONTENTS_RENDERMODEL, $player1 );

sys.debugLine('0 1 0', traceStart, tracEnd, 1 );

frobEntity = sys.getTraceEntity();
isFrobable = frobEntity.getIntKey("frob");

parm11_state = frobEntity.getShaderParm(SHADERPARM_FROB);
sys.println("\n\nInit parm11 value is: " + parm11_state);

if( !(!frobEntity) && (frobEntity != $world ) ){
if(isFrobable && isOver_obj == false){
isOver_obj = true;
if(parm11_state == 0){
frobEntity.setShaderParm(SHADERPARM_FROB, 1);
}
$test_light.On();
}
if(!btn0){
isPressed = false;
return;
}
if ( btn0 && isPressed == false ){
sys.println("use was pressed.");
isPressed = true;
frobEntity.activate($player1);
}
} else {
$test_light.Off();
if(parm11_state == 1){
frobEntity.setShaderParm(SHADERPARM_FROB, 0);
}
isOver_obj = false;
}

}


void MO_loop_control(){
while( true ){
command = FROB_NONE;
while( command == FROB_NONE){
mouseOver();
sys.waitFrame();

}
}
}

/*
===============
initialisation
================
*/

void main ()
    {
sys.waitFrame(); // wait for init() routines to finish
$player1.disableWeapon();
/*sys.setCamera($cam1);
sys.wait(20);
sys.firstPerson();*/
trace_objs();
//mouseOver();
thread MO_loop_control();
    }



The "SHADERPARM_FROB" is a custom #define in the doom_defs.script not one that exist in vanilla Doom 3.

here is the material of the "frob" object


textures/boat/boat_woodtable
{

wood

qer_editorimage textures/boat/boat_woodtable.tga

diffusemap textures/boat/boat_woodtable.tga
bumpmap textures/boat/boat_woodtable_bump.tga
Specularmap textures/boat/boat_woodtable_s.tga

// This is the code required for frob highlighting this texture
    {
        if ( parm11 > 0 )
        blend       blend
        map         _white
        color       0.99, 0.95, 0.62, 0.25
    }
}




BTW is there a way to attach a object to the player camera (is it even a entity?) and have it follow all the movements of the player camera? looking up and down, sides to sides, etc.

In my script i attach the trace origin to the $player 1 joint (headcontrol) but it is the head of the invisible character (for shadows and mirrors) so it lags behind the cursor and doesn't follow it precisely, but it more or less works . Help on this would also be appreciated. 

BielBdeLuna

#1
any entity in the engine can have it's own scriptobject you could control all the shader stuff within a loop (per frame or at lower intervals) and call the scriptobject from the player


you could have the player detecting a "detectable entity" and sending a request to the "detected entity" every nth of a second, this object could be maintaing it's state as detected and maintaing this state as long as a nth of a second until the next request, so if the next request never comes then the object falls back to the original state.

keep in mind though that the state of the detectable entity shouldn't be administered like the state of the AI monsters as those states are controlled via c++ within the AI code and that code isn't active in the general entities, a simple boolean controlling the on/off state should suffice


scirptObject code for the frobable entity:


#define SUPERCOOL_TICK 0.1

object supercool_object {  //any "object" is a sub object from "entity"
   boolean IS_ON;
   float thread_id;
   void signalOn();
   void signalOff();
   void mainLoop();
   void init(); // called by entity.cpp
   void destroy(); //called by entity.cpp
}

void supercool_object::init() {
    //called when the entity is spawned
    IS_ON = false;
    thread_id = thread mainLoop();
}

void supercool_object::destroy() {
    // called when the entity is erased
    float t_id;
    if ( thread_id > 0 ) {
        t_id = thread_id;
        thread_id = 0;
        sys.terminate( t_id );
    }
}

void supercool_object::mainLoop() {
    float t_id;

    while( true ) {
        /*
        if ( "some situation that should de-enable forever the entity from such effect but not erase the entity from the map" ) {
            if ( IS_ON ) {
               IS_ON = false;
                self.setShaderParm(SHADERPARM_FROB, IS_ON);
            }
            t_id = thread_id;
            thread_id = 0;
            sys.terminate( t_id );
        }
        */

        self.setShaderParm(SHADERPARM_FROB, IS_ON);
        sys.wait( SUPERCOOL_TICK );
    }
}

void supercool_object::signalOn() {
    IS_ON = true;
}

void supercool_object::signalOff() {
    IS_ON = false;
}


and script functions to call from the player:


#define FROBBING_TICK 0.1;

object player : player_base {

    supercool_object frobable_entity; //the type is a "supercool_object" type (so the file that defines that type has to come earlier in doom_main.script)
    supercool_object last_frobable_entity; // those two variables won't be initiated until we first encounter a frobable object (can scriptobject variables be NULL? IDK )
    supercool_object nullifier_frobable_entity; //since "NULL" is a "float" scriptobjects can't be nullified with "= NULL"

    boolean FROBBING;
    boolean testFrobable();

    float frob_manager;
    void frobUpdate();


    (...)
}

boolean player::testFrobable() {
    ent entity_to_check;

    if ( frobable_entity ) {
        last_frobable_entity = frobable_entity;
        nullifier_frobable_entity = frobable_entity;
    }

    //check using whatever method if the entity the cursor is pointing to is frobable
        //if not
            FROBBING = false;
            return false;
        //if yes           
            frobable_entity = entity_to_check;
            FROBBING = true;

            if ( frob_manager == 0 ) { //only start the frobUpdate loop if it doesn't exist
                frob_manager = thread frobUpdate();
            }

            return true;
}

void player::frobUpdate() {
    float t_id, time_now, next_tick;   

    next_tick = 0;

    while( true ) {
        time_now = sys.getTime();
        if ( time_now >= next_tick ) {
            next_tick = time_now + FROBBING_TICK;

            if ( ( nullifier_frobable_entity && ( frobable_entity == nullifier_frobable_entity ) ) { //a strange case
                frobable_entity.callFunction( "signalOff" );
                FROBBING = false;
            }

            if ( last_frobable_entity ) {
                last_frobable_entity.callFunction( "signalOff" );
            }           

            if ( FROBBING ) {               
                frobable_entity.callFunction( "signalON" );
            } else {
                t_id = frob_manager;
                frob_manager = 0;
                sys.terminate( t_id ); //the loop self kills itself if not frobbing anything
            }     
        }       
       
        sys.wait( FROBBING_TICK ); //or it could be sys.waitFrame();
    }
}


you then should call testFrobable()  every time you want it to test for frobables when "mouse overing"

argoon

Thanks man! That is more than i asked for, i'm sure that will help a tonne. I will study that code carefully and see what i can come up with, when i have some news i will let you know, thanks for your time. :)

BielBdeLuna


argoon

#4
Hello guys

BielBdeLuna i implemented your code and i'm getting some errors that i don't seam to be able to debug without help.

This error
QuoteERROR: Error: file script\ai_player.script, line 171: type mismatch for '&&'
is in this part of your code

if ( ( nullifier_frobable_entity ) && ( frobable_entity == nullifier_frobable_entity ) ) { //a strange case

by the way you lacked a ) in front of nullifier_frobable_entity was that intentional?

and seams to be caused by this variables definitions:


supercool_object frobable_entity; //the type is a "supercool_object" type (so the file that defines that type has to come earlier in doom_main.script)
    supercool_object last_frobable_entity; // those two variables won't be initiated until we first encounter a frobable object (can scriptobject variables be NULL? IDK )
    supercool_object nullifier_frobable_entity; //since "NULL" is a "float" scriptobjects can't be nullified with "= NULL"


How is the script able to get supercool_object  that is defined in another scrip? Do i need to include it somehow?

I also add a error on the var definition "  ent entity_to_check;" add to change ent to entity.

Btw how do i call the testFrobable() function, if my player "mouse over" detection code (using the trace lines method) is inside the testFrobable() funtion itself? Do i call it on the player::Init() function?

argoon

Man debugging this stuff is really frustrating, a code that works in a place, gives a error on another, being a noob at coding doesn't help either, i'm trying to implement the code that BielBdeLuna graciously gave me, i know this is all my fault for being a noob not his, but i'm just getting script errors that are totally alien to me.

for example this part of the code


void frob_object::destroy() {
    // called when the entity is erased
    float t_id;
    if ( thread_id > 0 ) {
        t_id = thread_id;
        thread_id = 0;
       sys.terminate( t_id );
    }
}


of the frob_object (supercool_object) gives me this error.

QuoteERROR: Error: file script\frob_obj_defs.script, line 25: Unknown value "terminate"

What that even means?

I comment that "sys.terminate()" part i get a error on the code


void frob_object::mainLoop() {
    float t_id;

    while( true ) {
        /*
        if ( "some situation that should de-enable forever the entity from such effect but not erase the entity from the map" ) {
            if ( IS_ON ) {
               IS_ON = false;
                self.setShaderParm(SHADERPARM_FROB, IS_ON);
            }
            t_id = thread_id;
            thread_id = 0;
            sys.terminate( t_id );
        }
        */

        self.setShaderParm(SHADERPARM_FROB, IS_ON);
        sys.wait( FROB_TICK );
    }
}


with the error

QuoteERROR: Error: file script\frob_obj_defs.script, line 45: setShaderParm is not a member of frob_object

i don't really know how to solve this, can anyone help me? Please.  :-[

BielBdeLuna

erase the "self." from the setShader function because it's not needed, you can do without it.

on sys.terminate( float threadNumber ), it should work!
the terminate function, in the script I posted only terminates the thread that controls the loop in the frobable object in case it's entity gets erased. (threads in c++ code are separated from entities, and threads in script are the same than c++ threads )

yeah it should be:
if ( nullifier_frobable_entity && ( frobable_entity == nullifier_frobable_entity ) ) { //a strange case

code gets compiled in order (defined in doom_main.script) , so every scriptobject called in some place, should be defined before it's called

in that case if player calls the frobbable objects functions, then the frobable objects should be defined before then player script

also keep in mind that you can define variables in the scriptObject that other scriptObjects inherit, and in those "heir" scriptObjects you can use those variables as if they where defined in them and not in their super-scriptObjects ( this is all like classes ) so you can define variables and functions in "weapon_base" and use them in weapon_pistol::weapon_base as if they where initiated in weapon_pistol


BielBdeLuna

keep in mind that the action you are doing is a two-parter:

first you need to tell the other entity that you're seeing it, so it should light up
then you have to tell the other entity that you're not seeing it, so it should light down

now keep in mind that you might go from entity_frobable1 to entity_frobable2, so you need to check if the current frobable entity is one of the following cases:
1) the same
2) none
3) or is another frobable entity different than the one that you started the check in the last tick

this means that you need to save at least two references of those entities, so at least you can say to last-but-not-current entity_frobable to light down.

argoon

#8
It seams it was my fault that the sys.terminate and the self.setshaderParm was not working, i add two entries of the frob_object script in the doom_main.script one at the very top other just before the ai.player.script,  it was causing problems, after deleting the one at the very top, they worked, now i only get (still) the error:

QuoteERROR: Error: file script\ai_player.script, line 171: type mismatch for '&&'

int the code:

if ( nullifier_frobable_entity  && ( frobable_entity == nullifier_frobable_entity ) ) { //a strange case

even after the changes you said, but i'm sure is just me messing something up, need to study more.





Ivan_the_B

DoomScript fails on certain kinds of combined expressions even if they look valid on their own.
You should probablly split the instruction like this:

if ( nullifier_frobable_entity ) {
   if ( frobable_entity == nullifier_frobable_entity ) {

   }
}


argoon

Quote from: Ivan_the_B on October 01, 2016, 07:03:50 PM
DoomScript fails on certain kinds of combined expressions even if they look valid on their own.
You should probablly split the instruction like this:

if ( nullifier_frobable_entity ) {
   if ( frobable_entity == nullifier_frobable_entity ) {

   }
}


That was it!! Thanks. :D

BielBdeLuna

it is strange though, it should work it's not different than the script when you shoot where you can only do it if there are bullets in the clip, the check is very similar, but in that case the type is different. oh well...  ???

argoon

Yes is indeed strange BielBdeLuna, but i would not blame the script engine right now, i don't get any errors but it still is not working so i most be doing something wrong along the way.  :P


Now the code compiles but when the player spawns the loop seams to run one time than stop, i know because i have a debug line showing the trace and it goes away after a frame or something, i think is this code:

} else {
                t_id = frob_manager;
                frob_manager = 0;
                sys.terminate( t_id ); //the loop self kills itself if not frobbing anything
            }     


that is being called and killing the loop, don't know why tho. // noob at coding


This is what i'm doing.

I made a script for the custom object using your code with slight modifications, naming mostly.

I put that scrip call in the doom_main.script above the player_base.script and ai_player.script.

I implement the extra player code into the ai_player.script as instructed.

I call the testFrobable() in the player::init(); function // don't know if this is the right way perhaps is why is failing.

I made a def for the mesh and i call or associate the script within it with "objectScript"     "script_name"

I put the object in the test map, dmap&map the player spawns, the trace shows for a frame or two then goes away, i "mouse over" the object nothing happens.