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

idTech 4 (aka Doom 3 tech) Discord Server!

Main Menu


Started by BielBdeLuna, October 17, 2014, 05:19:39 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.


I'm working in the OpenTech group, which is a group of developers that work on the gpl idtech4-BFG version of the engine, and we need to recreate the assets of d3 (all/some) but remake them gpl wise. so people can use the "openTech" engine to make games

In the future I'm looking forward to implement a planner more akin to what F.E.A.R. and S.T.A.L.K.E.R. had. but for the moment I will keep the Finite State Machine ( FSM ) model for I still need my c++ knowledge to grow before I can implement the planner.

right now I've made the distinction of:

ai_base -> npc_base -> npc_enemy_base -> npc_enemy_bipped_base

ai_base is for both the player and the npcs
npc_base is for npc_characters and npc_enemies
npc_enemy_base is for all kind of enemies, fliying, swiming,... any kind of enemy
npc_enemy_bipped_base is for human enemies

I've included a traits system where, several enemies that share the same script-object should react differently due to several distinct personality traits

I'm looking forward to implement a different scheme for the bipped motion, I want them to be able to take into account the direction they are facing (legs, torso, head, eyes) in order to move, this is meant to help add to the player the capacity to disjoint the direction of looking form the direction of the player is facing (a la Assassin's Creed ) and at the same time allow the enemies and characters to move in a more fluid way.

in order to implement this I'm adding a "motionState" that reside in-between "states" and "animStates" that is independent of both, reads the AI inputs from the game code (as well as player's) and acts upon the "animStates" so the "states" are left to a more cerebral level, I'm abstracting then the motion more closer to a planer, the "motionStates" are less defined (I'm planing just two)

Still ( the ai_base is not willing to move) he could be falling (so in motion but not willing) or just could be looking around
inMotion (the ai_base is willing to move ) the motion should use a "will direction" that would not always be the same direction he is facing, so he could be walking forward, or going backwards, or need to turn around and walk forward, or dodging, or simply step left in order to peep to the enemy and shoot at him

so to sum up "motionStates" should be freed up from the "animChannel" while still be able to control them separately, yet still be able to receive orders from the "states" in form of bool flags and "will direction" angles

in order to implement the "motionStates" I'm adding them to "actor.cpp/.h" so, players, characters, and enemies can use them.

so do you guys know anything to implement with the gpl AI? any idea or suggestion?



Just a small suggestion on where you could look for ideas:

Perhaps you could get some ideas from the Dark Mod source code. I know they have done wonders with the AI behavior and various states of alertness.

Not entirely sure if this is quite what you meant? this is kind of more related to making the AI more intelligent, which is what I thought you meant.



indeed, but now I'm at a more primal stage, I'm concentrating on movement, I guess stages of alertness belong to the most cerebral part (the "states" in my new system) along some calculus for get a certain strategy at play (although we don't have planning (which involves memory, therefore lists of objects, and we don't have the luxury of such infrastructure yet ) and we don't have objects either ( script-objects are not classes, at least I don't know how to start'em from the scripting code ) we can though trace lines and, with such, we could strategize the environment around as well as strategize the enemy's environment)

indeed the Darkmod is a precious gem to look at, and to be inspired by!  O0


Doom 3 AI system is animation-based. The delta of origin bone in walk/run animation defines movement speed (I don't recall if that's true for flying monsters).

So if you want to make AI to be independent from animations, you'd have to not only rewrite C++ code for AI, but also rewrite some, if not all, animation system.


Quote from: motorsep on October 17, 2014, 09:25:24 AM
Snip... The delta of origin bone in walk/run animation defines movement speed (I don't recall if that's true for flying monsters).


The origin bone should remain stationary for the flying monsters. Their speed is controlled by parameters such as "fly_speed" and the code moves them based on this speed rather than by animation.



animations are called from the scripting system, and can be overridden whenever one wants,

flying monsters have a mixed bag of "slide" animation and animation based motions.
but biped enemies have a mixbag of animation based and Ik based motions, as well as heads following the player via script orders,

so no, no need to rewrite anything.

I might want though to add some new animation types, like speed up the animation as much as a given float rises. for ladder animation
as well as using one single frame animations as bone target and re-target bone positions in between targets also given a percentage in a float variable, so npcs and players can run and walk following a scheme like in the game Overgrowth. but for all of this I will need to learn more c++ than what currently I know.


added a new class for making threaded independent states.

now I'm implementing a new direction for player/npcs so the direction the monster is willing to go next isn't defined by forward backward and strafe but by an angle and a velocity flag (which should point to several different velocity animations) all of this still retaining the old method of AI_FORWARD, AI_BACKWARD... etc. therefore enabling working with all the old scripts possible.

my first test for the new AI should consits of the following:

four computer terminals one next to the other, and an NPC should "work" on those terminals, sequentially, since stepping to the next terminal should be a small strafing step, he should be able to, then when he reaches the fourth terminal, he then he is required to go back to the first but not by strafing back but by facing first the farthest terminal and then walking all the way to it, and eventually face the actual computer.

so the motion should display two new behaviours, first disconnection between legs and torso for all NPCS, and the ability to choose between moving and adapting his angle

I'm setting up two new motion status:

stopped: which governs the NPC when it doesn't change position (yet the legs and torso can change rotation))
moving: which should handle moving in n directions as well as legs and torso rotations also

so the stopped and the moving motion states more than an actual movement, they reflect the will to move and the will to remain still, once this will changes the motion states changes.

this will is expressed by a will direction and velocity which could be opposite to the direction the npc is facing (therefore the need for a n direction movement system)

I'm not finished yet, now I need to transpose all the relevant AI_xxx booleans to and actual direction (compare this direction to the viewAxis. and such) once I'm finished I commit the c++ changes to Github and I can start the reactive work in scripting.


a less FSM system I'm currently working on which should be able to play in standard d3, it is highly work in progress
//this code is GPL v3

object newai {

    boolean SHARPEN_SENSES = true;
    boolean SEEK_ENEMY = false;
    boolean SEE_ENEMY = true;
    boolean HEAR_ENEMY = true;
    boolean IN_COMBAT = false;





    vector  ideal_head_dir;
    vector  ideal_dir;

    boolean STRAIGHTEN_LEGS = false;
    boolean HEAD_MOTION_DONE = true;
    boolean TORSO_MOTION_DONE = true;
    boolean LEGS_MOTION_DONE = true;

    void    init();
    void    destroy();
    void    t_motion();
    void    t_senses();
    void    t_rational();

    entity  current_target = NULL;
    entity  current_enemy = NULL;

void newai:init() {
    thread t_motion();
    thread t_senses();
    thread t_rational();


void newai:destroy() {


void t_motion() {

    //it goes at 60fps

    while ( true ) {


void t_senses() {

    time_delta = 0.1; // starts at 10fps

    while ( true ) {
        next_tick = utils_set_next_tick( time_delta );

        if ( utils_check_next_tick( next_tick ) ) { continue };

void t_rational() {

    time_delta = 0.04 //starts at 25fps

    while ( true ) {
        next_tick = utils_set_next_tick( time_delta );

        if ( current_enemy == NULL ) {
            IN_COMBAT = false;

            current_target = getEntityKey( "target" );

            if ( current_target == NULL ) {
                //there are no routines
                MOVE_SPEED = "STAY";
                MOVE_DIR = "FORWARD";
                HEAD_DIR = "FORWARD";
                TORSO_DIR = "FORWARD";
                STRAIGHTEN_LEGS = true;

                if ( LEGS_MOTION_DONE ) {
                    STRAIGHTEN_LEGS = false;
                SHARPEN_SENSES = true;
            } else {
                // there is a routine
                // path system
                SHARPEN_SENSES = true;
        } else {
            IN_COMBAT = true;

        if ( IN_COMBAT ) {
            if ( SEE_ENEMY ) {
                SEEK_ENEMY = false;
                //attack him
            } else {
                // we might want to keep attacking him before seeking him
                //SEEK_ENEMY = true;
        } else {
            SEEK_ENEMY = false;

        //for every tick

            // ask the senses

            // follow a routine

            // too much an FSM

            //check for enemies <-- ASK THE SENSES
            //check if in combat

            //check if in routine


        if ( utils_check_next_tick( next_tick ) ) { continue };

it should use angles for the motion and use routines for the change of angles, the motion should be untied to the willing of the motion, inclination of the surfaces could play a role in the speed

it will use FSM for the animations, but a future improvement with c++ work could make the FSMs unneeded for animations with the legs.

I will try to de-FSM the combat, making the combat integral to the character, and not a separate state.

also I want to include "reaction time" in-between actions so the same 3d models can play several personalities for every character.

most of the functions will be separated in "utils_ai_motion.script", "utils_ai_rational.script", and "utils_ai_sense.script" scripts so can be reused for other different AIs, and will all be GPL v3

can't do planing because there are no lists in d3 in any easy way. but if lists could be done then I would consider a planner scheme where actions for the character could be whighted and compared.


Quote from: solarsplace on October 17, 2014, 09:40:01 AM
The origin bone should remain stationary for the flying monsters. Their speed is controlled by parameters such as "fly_speed" and the code moves them based on this speed rather than by animation.

It doesn't - any moving monster has to have moving origin bone. Load up Cacodemon into Blender and see the animation - origin bone moves with any linear motion.


Quote from: motorsep on June 10, 2015, 12:13:09 PM
Quote from: solarsplace on October 17, 2014, 09:40:01 AM
The origin bone should remain stationary for the flying monsters. Their speed is controlled by parameters such as "fly_speed" and the code moves them based on this speed rather than by animation.

It doesn't - any moving monster has to have moving origin bone. Load up Cacodemon into Blender and see the animation - origin bone moves with any linear motion.


Perhaps there is more to the flying monster type then, as I have monster fish in Arx that are "MOVETYPE_FLY" and their origin position remains permanently rooted to 0,0,0 and they zoom around the map with no problems!

Perhaps the "fly_speed" is a speed in addition to the translation of the animation... I will have a look if I remember later... I notice actually that the Cacodemon does indeed translate and also does some funky bobbing about and tentacle wafting in the process, I suspect the effects are additive.



in flier monsters you can have both animation based, or code based motion, in fact with any monster you can have whatever you like, if idSoftware choose that path you don't have to.

quake 1 monsters where all stationary and advanced via code

I once did a flier monster that attacked with a fixed position animation and a code enabled movement, and fled with a moving position. which I think it's the same with the lost soul, you can see this within engine with the testmodel command, and the g_showskel iirc, no need to use Blender here.


can someone explain me in layman terms how to do a cover system? I can't get it to work in my mind in any significant way that isn't casting one thousand rays and checking their distances and... and... madness.

The Happy Friar

Quake 4 had helper entities that said where the cover was available.  It wasn't a required point the AI went to, but if the AI was close it had the option to move to a cover entity point & do it's cover stuff there.

ETQW might of had similar, not sure.


ok, I'll look into it. thanks!