One Minute Game Review by The Happy Friar:
Also on Rumble:

idTech 4 (aka Doom 3 tech) Discord Server!

Main Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - BielBdeLuna

id Tech 4 Scripting / Re: Debug HUD?
February 05, 2017, 02:14:37 AM
id Tech 4 Scripting / Re: Debug HUD?
February 04, 2017, 06:10:45 AM
is there a way to download that file again?
id Tech 4 Scripting / Re: LOD system
December 09, 2016, 05:23:12 AM
so every grass has a loop in script? every entity has a loop that runs every frame within the c++ code, look for the "think" function, you could code this in c++ and so you would not waste resources in the scripting side, you can also look into how The Dark Mod implemented their LOD system too.
id Tech 4 Scripting / Re: LOD system
December 08, 2016, 07:06:11 PM
this thing is much better resolved in the rendering side of the engine, and as Motorsep pointed out this might need other tech in the engine than just simply replacing models.
id Tech 4 Scripting / Re: help with a script
October 05, 2016, 11:37:43 AM
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...  ???
id Tech 4 Scripting / Re: help with a script
September 30, 2016, 12:25:29 PM
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.
id Tech 4 Scripting / Re: help with a script
September 30, 2016, 12:17:37 PM
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

id Tech 4 Scripting / Re: help with a script
September 26, 2016, 11:34:00 AM
no problem :)
id Tech 4 Scripting / Re: help with a script
September 25, 2016, 06:38:28 PM
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"
id Tech 4 Scripting / Re: How to debug AI scripts?
September 23, 2016, 11:12:30 AM
I've never tried the combat nodes extensively, but for what I could gather, you just put them in the map, and the AI script calls a c++ that returns the combat nodes that is closest to the player, it's pretty straight forward, and for what I could see very buggy (animations, and so the monsters) jumped from place to place incorrectly (with jumpy animations, not well blended) when there where too many combat nodes around, I think the combat nodes need to be targeted by the monster in order to get called latter.

combat nodes and path corners can have their own individual animations, so can be used for special case animations
id Tech 4 Scripting / Re: How to debug AI scripts?
September 20, 2016, 04:17:29 AM
all those ircc are c++ functions called from script code

facing ideal: there are two facing values the current facing direction and the ideal direction the idAi plans to aim (that is the direction the the enemy, or the direction to the next path target)

combat node: those entities that can be used so enemies display combat animations (firing from behind a box, so crouching and un-crouching from behind it as a protection) an example of this can be the two pistol zombieman in mc_underground after you activate the bridge, the second runs to a box, when he sees the player, in order to hide behind it, and he keeps shooting from behind it

attack cone, is the cone from the monster vision that he uses to determine if the enemy is aligned to the ideal direction or not, and I think combat cone, has to do with the same alignment when the monster is chasing the enemy

become solid/canBecomeSolid is pretty explanatory isn't it? I guess this has to do with corpses (that no longer are solid to the player) or with disappearing enemies like Wraiths

charge attack is any attack the monster runs towards the enemy to perform a melee attack (lost soul fly towards the enemy to hurt him as their charge attack)

the fact that terrain has to be caulked underneath show that idTech4 as it is in doom3 doesn't have support for terrain, that one has to force the aas to create the aas for that surface with added effort. Sure the monsters will walk, but walking to the player can be done without path-finding (like quake1) the question is that without added effort taking the shortest path to the player saving the obstacles is not possible.

@oneofthe8devilz your video shows a fairly even environments with two levels and one bridge, but more uneven terrain could be problematic to recreate with brushes. specially when the quads on the mesh are not squared, or when the quads from their neighbours are angled very different.

the solution would be to add to the aas compiler some form of aas data adapted to triangles instead of strictly brushes, somewhat similar to the triangle based process Robert Beckebans added to RBDoom3BFG dmap compiler, so that the two systems coexisted and worked along. without any added effort by the mapper.
it might not be as trivial or easy as this, specially if the terrain isn't flat which should be the point of making any terrain with a mesh.
I'm working as the coder for I guess it's an unannounced mod, and I was tasked on adding a feature from the fragging free mod, the dodge activated by double tapping the left or the right keys on the keyboard. in FF they did it within doom3 script (which is always a fall-back option) I thouth on implementing it via c++, and so I have it implemented in c++:

void idPhysics_Player::PerformDodge( bool dodge_right ) {
const float DODGE_POWER = 550.0f;
const float DODGE_HEIGHT = 300.0f;

idPlayer* player = static_cast<idPlayer*>(self);

idVec3 current_vel = GetLinearVelocity();
idVec3 push;
idAngles viewangles = idAngles( player->viewAngles[0], player->viewAngles[1], player->viewAngles[2] );
viewangles[2] = 0.0f;

idVec3 viewangles_to_right;
viewangles.ToVectors( NULL, &viewangles_to_right ); // viewangles to right...
idVec3 dodgedir = viewangles_to_right;
if ( !dodge_right ) {
dodgedir = -dodgedir;
//idVec3 normaldir = viewangles.ToForward();

push = dodgedir * DODGE_POWER;
push[2] = DODGE_HEIGHT;

player->StartSound("snd_jump_small", SND_CHANNEL_VOICE, 0, false, NULL);

current_vel += push;

SetLinearVelocity( current_vel );

command.flags ^= UCF_DOUBLE_TAP; //revert the flag so the player can go back to double tap again


the way to perform the dodge is the added code in idPhysics_Player::WalkMove:

               if ( ( command.flags & UCF_DOUBLE_TAP ) && ( waterLevel <= WATERLEVEL_FEET ) ) {
if ( command.rightmove > 0 ) {
PerformDodge( true );
} else if ( command.rightmove < 0 ) {
PerformDodge( false );

so it all moves around that flag: UCF_DOUBLE_TAP
if we have a direction (left or right) and we have the flag on, then on that tick we're double tapping (in the end of PerformDodge I lower the flag)

I did it this way, because I thought that recreating every button and key just for the double tapping would create more problems that become any solution. the flag system has flaws, it can only handle a single double tap at the time, so it fails to recognize more than one double tap (that is double tapping two or three keys at the time). but for testing should be fine.

my problem comes on how to activate this flag, my system doesn't seem to work:

void idUsercmdGenLocal::DoubleTap( void ) {
// the double tap feature for left / right keys, TODO generalize with a method that serves all keys and buttons
// only serves a single dobule tap motion

//if ( ( idUsercmdGenLocal::in_doubleTap.getBool() ) && ( cmd.flags && !UCF_DOUBLE_TAP ) ) {
if ( cmd.flags & !UCF_DOUBLE_TAP ) {
int cur_time = Sys_Milliseconds()

if ( !ButtonState( UB_RIGHT ) && !ButtonState( UB_LEFT ) ) {
last_key = selected_key;
selected_key = -2;
double_tap_time = cur_time + 750; // let not last more than that time before making the next tap
} else {
//pressing the two keys always waste the chance!
last_key = -1;
selected_key = -2;
double_tap_time = 0;
next_double_tap_chance_time = 0;
common->Printf( "pressed both" );

if ( ButtonState( UB_RIGHT ) && !ButtonState( UB_LEFT ) ) {
if ( selected_key == UB_LEFT ) {
last_key = -1;
selected_key = UB_RIGHT;+
common->Printf( "pressed right" );
} else if ( ButtonState( UB_LEFT ) && !ButtonState( UB_RIGHT ) ) {
if ( selected_key == UB_RIGHT ) {
last_key = -1;
selected_key = UB_LEFT;
common->Printf( "pressed left" );

if ( ( selected_key == last_key ) && ( cur_time < double_tap_time ) && ( cur_time >= next_double_tap_chance_time ) ) {
cmd.flags ^= UCF_DOUBLE_TAP;
common->Printf( "double Tap" );
next_double_tap_chance_time = cur_time + 1500;

this code is called from idUsercmdGenLocal::MakeCurrent when creating the command of the frame.

it seems that ButtonState( UB_LEFT ) and ButtonState( UB_RIGHT ) doesn't react as those buttons are pressed, can someone help me solve this, is there any way to make it even more general purpose?

double tapping is a three part situation, you first tap, then you stop tapping ,and then you tap again, I'm using two int variables to keep the key that was tap in the beginning, and a timer to know if we are legit when it comes to double tapping, it's I think a very heavy handed way to keep track of it all but it's just testing code. any idea why it doesn't work?
with one exception, AI will never abandon AAS for an unknown area, so you either have a character on the terrain or on the AAS but never on both, it might be that the character starts on the terrain and then afterwards it enters an AAS but he will never leave it. if you want AAS on the terrain then you have to clip the whole navigable area, defeating the purpose of using a terrain mesh. maybe an improvement on the AAS compiler needs to be added in order to make it compile AAS areas for terrain meshes.