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

Simple Character That Attacks baddies

Started by VGames, June 08, 2015, 08:52:06 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

VGames

Could somebody please help me write some simple code for a character script file that makes him stand in one spot and shoot monsters that come along. I've tried so hard to modify scripts that belong to characters that do just this but they never attack. I'm not as good as I thought going into this idea. Please help if you can. I got the def stuff figured out but AI is so hard for me.
Get the latest on Perfected Doom 3 here - http://www.moddb.com/mods/perfected-doom-3-version-500

BielBdeLuna

you could setup a loop that kept shooting rays from the center to forward inside a triangle, and if one of those rays get a idAI or idPlayer then get it as the target, once you have a target, you need another loop for the shooting mechanic

those two loops could coexist at the same time ,for which you would need the use of threading or you could either have one or the other, in the shooting emchanic then you could develop a way to check if the target is visible to the turret/guy and see if you need to find him again or keep shooting.

if it moves then you need somethign else much more complicated

the rays in d3 (or lines) have a start position and an end position this end position doesn't mean the ray will reach it,only that it will ext the start position and that it will continue towards the end position unless it hits a wall or an entity, since you get a reference of that entity, you can check out it's spawnargs, and in that case you can check it's "spawnclass" spawnarg so you can get what kind of entity it is.

now idtech4 can't make lists in scripting,so you might need to check every one of the rays you casted one after the other inside a loop

you know the origin of the rays but how do you know the end positions? the end positions should be really far away (at least as far as the longest distance the turret/character could see) but since you need to cover a cone of view (or in a simplified version) a triangle of view (in a case of a flat terrain) you could settle on a number of rays (let's say 8 rays) and divide the angle of view by the ammount of rays you want to use (don't get too mad with this number) then start from one side of the angle and keep putting the end position at increments

with this method you could get an entity and store it until you finished all the rays checks and be sure this is the entity you want, and then target it if you need to target it.

motorsep

You gotta be kidding me, BielBdeLuna  :o

Look into doom_events.script - it's full of AI higher level script functions where you can find enemy, face it and shoot it. No need to do any tracing/shooting rays!

VGames

Ok I'm glad u said that motor I was starting to freak out. Could u please elaborate on what u said a little. I'm really not good at starting from scratch on character AI. I can edit the crap out of stuff that's there but I'm at a loss with freshly made stuff.
Get the latest on Perfected Doom 3 here - http://www.moddb.com/mods/perfected-doom-3-version-500

solarsplace

Hi

An idea to potentially save you lots of time could be to use Ivan_the_B's Smart AI mod: http://planetdoom.gamespy.com/View993a.html?view=POTD.Detail&id=616

The Smart AI mod lets you have one or more friendly AI squad mates to fight along side you. All the work you need is already done. They have follow and wait modes and their own set of special path entities to let you configure special behaviors for them.

Trouble is, I can't find a download for it online now, and I don't have the original source, only a highly modified version incorporated into the Arx code that would not work for you.

Perhaps you could PM Ivan and see if he could re-up or send you the files? - http://idtechforums.fuzzylogicinc.com/index.php?action=profile;u=91

Cheers

The Happy Friar

The turret does this currently.  I'd say just use that & replace the model/animations.

VGames

Get the latest on Perfected Doom 3 here - http://www.moddb.com/mods/perfected-doom-3-version-500

oneofthe8devilz

I got six little friends and they all run faster than you ;)


Check out our mods at
moddb or the SPS Homepage

motorsep


VGames

Monster_turret does nothing. I set him to be on my team and he just sits there. Doesn't react to baddies.
Get the latest on Perfected Doom 3 here - http://www.moddb.com/mods/perfected-doom-3-version-500

The Happy Friar

monster_turret, yes.  In my Last Stand mod I used him to attack monsters.  Here's the def & script.  I'm not 100% what I changed (this was years ago) but he does attack only monsters (download here: http://www.moddb.com/mods/the-happy-friars-last-stand/downloads/the-happy-friars-last-stand-v12-beta-2)
/***********************************************************************

    monster_turret.def

***********************************************************************/

export fred {
    options -prefix TURRET_ -keep flash barrel-sourcedir models/mapobjects/turrets/cycles -destdir models/md5/items/turret1
    mesh    idle.mb -dest turret
    anim    idle.mb
}

entityDef monster_turret {
    "inherit"                        "monster_default"
    "scriptobject"                    "monster_turret"
    "model"                            "monster_turret"
    "mins"                            "-12 -12 -24"
    "maxs"                            "12 12 0"
    "team"                            "1"
    "rank"                            "0"
    "health"                        "100"
    "turn_rate"                        "180"        //was blank
    "bleed"                            "0"
    "on_activate"                    ""
    "fov"                            "1"        //was 360
    "aas"                            ""

    "def_projectile"                "projectile_bullet_turret"
    "projectile_spread"                "1"        //was 0
    "num_projectiles"                "1"
    "attack_cone"                    "1"        //was 360
    "attack_accuracy"                "1"
    "smoke_weapon"                    "cgsmoke.smoke"

    "head_focus_rate"                "0.15"

    "bone_focus"                    "barrel"
    "bone_leftEye"                    ""
    "bone_rightEye"                    ""   
   
    "look_min"                        "-180 -180 -180"        //was -12 -180 0
    "look_max"                        "180 180 180"        //was 90 180 0
    "look_joint aim"                "1 1 0"        //was 1 1 0

    "mtr_flashShader"                "muzzleflash"
    "flashTime"                        "0.15"
    "flashColor"                    "1 0.8 0.4"
    "flashRadius"                    "120"

    "snd_wakeup"                    "char_sentry_active"    //TEMP
    "snd_shutdown"                    "char_sentry_destroyed"    //TEMP
    "snd_windup"                    "monster_zombie_commando_windup"
    "snd_winddown"                    "monster_zombie_commando_winddown"
    //"snd_fire"                    "player_chaingun_fire"
    "snd_fire"                        "monster_turret_fire"
}

entityDef monster_turret_light {
    "inherit"                        "monster_turret"
   
    "light"                            "1"
    "light_distance"                "640"
    "mtr_light"                        "lights/flashlight5"
    "skin_light_off"                ""
    "skin_light_on"                    ""
}

model monster_turret {
    mesh                        models/md5/items/turret1/turret.md5mesh
    anim idle                     models/md5/items/turret1/idle.md5anim
}

entityDef damage_bullet_turret {
    "damage"                        "8"        //was 6
    "kickDir"                        "1 0 0"

    "mtr_blob"                        "genericDamage"
    "blob_time"                        "300"
    "blob_size"                        "400"
    "blob_offset_x"                    "400"

    "knockback"                        "1"
   
    "smoke_wound_flesh"                "bloodwound.smoke"
    "mtr_wound_flesh"                "textures/decals/hurt02"
    "mtr_splat_flesh"                "textures/decals/dsplat2"
    "mtr_splat_flesh2"                "textures/decals/dsplat5"
    "mtr_splat_flesh3"                "textures/decals/dsplat7"
    "mtr_splat_flesh4"                "textures/decals/dsplat11"
    "snd_flesh"                        "bullet_impact_flesh"

    "kick_time"                        "400"
    "kick_amplitude"                "1"

    "dv_time"                        "100"
}

entityDef projectile_bullet_turret {
    "spawnclass"                    "idProjectile"
    "mins"                            "-1 -1 -1"
    "maxs"                            "1 1 1"
    "cone"                            "3"
    "scale"                            "0.1"
    "noshadows"                        "1"
//    "tracers"                        "1"
//    "model_tracer"                    "models/particles/tracer/tracer.lwo"
    "snd_tracer"                    "bullet_flight"
    "snd_ricochet"                    "bullet_ricochet"
    "snd_impact"                    "bullet_impact_metal"

    "def_damage"                    "damage_bullet_turret"

    "launchFromBarrel"                "1"
    "health"                        "0"
    "velocity"                        "5000 0 0"    // was 3500 slowed down for tracer effect
    "angular_velocity"                "0 0 0"
    "thrust"                        "0"
    "thrust_start"                    "0"
    "thrust_end"                    "0"
    "linear_friction"                "0"
    "angular_friction"                "0"
    "contact_friction"                "0"
    "bounce"                        "0.6"
    "mass"                            "2"
    "gravity"                        "0"
    "fuse"                            "4"

    "detonate_on_fuse"                "0"
    "detonate_on_death"                "0"
    "detonate_on_world"                "1"
    "detonate_on_actor"                "1"

    "impact_damage_effect"            "1"
    "impact_gib"                    "1"

    "mtr_detonate"                    "textures/decals/bulleth02"
    "decal_size"                    "10"

    "smoke_fly"                        ""
    "smoke_detonate"                "smokeandspark.smoke"
    "smoke_bounce"                    ""    //particles/bullet_sparks.particle"
    "smoke_fuse"                    ""
                                   
    "mtr_light_shader"                ""
    "light_color"                    "0 0 0"
    "light_radius"                    "0"
    "light_offset"                    "0 0 0"

    "mtr_explode_light_shader"        ""
    "explode_light_color"            "0 0 0"
    "explode_light_radius"            "0"
    "explode_light_fadetime"        "0"
}

/***********************************************************************

ai_monster_turret.script

monster_turret

***********************************************************************/

#define TURRET_FIRE_RATE        0.01
#define TURRET_MIN_ATTACK_TIME  1.0        //was 1.5
#define TURRET_SHUTDOWN_TIME    4

object monster_turret : monster_base {
    boolean        fire;
    boolean        attack_monsters;
    entity        light;
    boolean        light_is_on;
    float        attackTime;

    //
    // States
    //
    void        state_Begin();
    void        state_Idle();
    void        state_Combat();
    void        state_Killed();
    boolean        checkForEnemy( float use_fov );

    //
    // actions
    //
    void        combat_attack();

    void        init();
    void        destory();

    void        spawn_light();
    void        light_off();
    void        light_on();
   
    // anim states
    void        Torso_Death();
    void        Torso_Idle();
    void        Torso_Attack();
};

/***********************************************************************

    Torso animation control

***********************************************************************/

void monster_turret::Torso_Death() {
    finishAction( "dead" );

    // never exit
    waitUntil( 0 );
}

void monster_turret::Torso_Idle() {
    playCycle( ANIMCHANNEL_TORSO, "idle" );
   
    eachFrame {
        if ( fire ) {
            animState( ANIMCHANNEL_TORSO, "Torso_Attack", 0 );
        }
    }
}

void monster_turret::Torso_Attack() {
    float soundLen;

    playCycle( ANIMCHANNEL_TORSO, "idle" );

    soundLen = startSound( "snd_windup", SND_CHANNEL_BODY, false );
    soundLen += sys.getTime();
    while( sys.getTime() < soundLen ) {
        waitFrame();
    }

    attackTime = sys.getTime() + TURRET_MIN_ATTACK_TIME;
    while( fire || ( sys.getTime() < attackTime ) ) {
        lookAtEnemy( 1 );                //added this line
        if ( sys.influenceActive() ) {
            break;
        }
        startSound( "snd_fire", SND_CHANNEL_WEAPON, false );
        attackMissile( "barrel" );
        sys.wait( TURRET_FIRE_RATE );
    }
   
    soundLen = startSound( "snd_winddown", SND_CHANNEL_BODY2, false );
    soundLen += sys.getTime();
    while( sys.getTime() < soundLen ) {
        lookAtEnemy( 1 );                //added this line
        waitFrame();
    }

    finishAction( "attack" );
    animState( ANIMCHANNEL_TORSO, "Torso_Idle", 0 );
}

/***********************************************************************

    AI

***********************************************************************/

/*
=====================
monster_turret::init
=====================
*/
void monster_turret::init() {
    float team;

    // don't take damage
    //ignoreDamage();                commented out

    // can't move, so only fire on sight
    ambush = true;

    team = getFloatKey( "team" );
    if ( team != 1  ) {
        attack_monsters = true;
    }

    if ( getIntKey( "light" ) ) {
        spawn_light();
    }

    animState( ANIMCHANNEL_TORSO, "Torso_Idle", 0 );
    setState( "state_Begin" );
}

/*
=====================
monster_turret::destory
=====================
*/
void monster_turret::destory() {
    light.remove();
}

/*
=====================
monster_turret::spawn_light
=====================
*/
void monster_turret::spawn_light() {
    string texture;
    float distance;

    distance = getFloatKey( "light_distance" );
    if ( !distance ) {
        distance = 640;
    }
   
    // spot light
    sys.setSpawnArg( "light_target", "1 0 0" );
    sys.setSpawnArg( "light_up", "0 0 .5" );
    sys.setSpawnArg( "light_right", "0 -.5 0" );   
    sys.setSpawnArg( "light_end", distance + " 0 0" );

    texture = getKey( "mtr_light" );
    sys.setSpawnArg( "texture", texture );

    sys.setSpawnArg( "name", getName() + "_light" );
    light = sys.spawn( "light" );
    light.setAngles( getAngles() );
    //light.bindToJoint( self, "light", true );
    light.bindToJoint( self, "flash", true );
    light.setOrigin( '0 0 0' );

    light_off();
}

/*
=====================
monster_turret::light_off
=====================
*/
void monster_turret::light_off() {
    string skin;

    if ( light ) {
        light.Off();
        skin = getKey( "skin_light_off" );
        setSkin( skin );
        light_is_on = false;
    }
}
   
/*
=====================
monster_turret::light_on
=====================
*/
void monster_turret::light_on() {
    string skin;

    if ( light ) {
        light.On();
        skin = getKey( "skin_light_on" );
        setSkin( skin );
        light_is_on = true;
    }
}

/*
=====================
monster_turret::state_Begin
=====================
*/
void monster_turret::state_Begin() {
    setMoveType( MOVETYPE_STATIC );

    if ( getIntKey( "trigger" ) ) {
        setState( "state_Disabled" );
    } else {
        wait_for_enemy();
        setState( "state_Combat" );
    }
}

/*
=====================
monster_turret::state_Idle
=====================
*/
void monster_turret::state_Idle() {
    startSound( "snd_shutdown", SND_CHANNEL_VOICE, false );
    light_off();
    wait_for_enemy();
    setState( "state_Combat" );
}

/*
=====================
monster_turret::state_Disabled
=====================
*/
void monster_turret::state_Disabled() {
    entity enemy;

    startSound( "snd_shutdown", SND_CHANNEL_VOICE, false );

    lookAtEnemy( 0 );

    // wait till we stop firing and bullets are out of the air
    attackTime = 0;
    fire = false;
    while( inAnimState( ANIMCHANNEL_TORSO, "Torso_Attack" ) ) {
        waitFrame();
    }
    sys.wait( 0.2 );

    // tell all enemies to forget about us
    enemy = nextEnemy( $null_entity );
    while( !( !enemy ) ) {
        sys.print( sys.getTime() + ": clear enemy: " + enemy.getName() + "\n" );
        enemy.clearEnemy();
        enemy = nextEnemy( $null_entity );
    }

    // clear our enemy
    clearEnemy();

    // wait for trigger
    AI_ACTIVATED = false;
    while( !AI_ACTIVATED ) {
        waitFrame();
    }
    AI_ACTIVATED = false;

    setState( "state_Combat" );
}

/*
=====================
monster_turret::state_Killed
=====================
*/
void monster_turret::state_Killed() {
    stopMove();

    light_off();

    animState( ANIMCHANNEL_TORSO, "Torso_Death", 0 );
    waitAction( "dead" );
    stopThinking();
}

/*
=====================
monster_turret::checkForEnemy
=====================
*/
boolean    monster_turret::checkForEnemy( float use_fov ) {
    entity enemy;

    enemy = findEnemy( false );
    if ( !enemy ) {
        if ( !attack_monsters ) {
            return false;
        }
       
        enemy = findEnemyAI( false );
        if ( !enemy ) {
            return false;
        }
    }

    setEnemy( enemy );
    return true;
}

/***********************************************************************

    Combat

***********************************************************************/

/*
=====================
monster_turret::state_Combat
=====================
*/
void monster_turret::state_Combat() {
    float shutdownTime;

    startSound( "snd_wakeup", SND_CHANNEL_VOICE, false );
   
    light_on();
    shutdownTime = sys.getTime() + TURRET_SHUTDOWN_TIME;
    eachFrame {
        lookAtEnemy( 1 );
        if ( AI_ENEMY_DEAD ) {
            enemy_dead();
            continue;
        }

        if ( AI_ACTIVATED ) {
            setState( "state_Disabled" );
            break;
        }

        if ( AI_ENEMY_VISIBLE ) {
            if ( canHitEnemyFromJoint( "barrel" ) ) {
                combat_attack();
            } else {
                checkForEnemy( false );
            }
            shutdownTime = sys.getTime() + TURRET_SHUTDOWN_TIME;
        } else if ( !checkForEnemy( false ) ) {
            if ( shutdownTime < sys.getTime() ) {
                lookAtEnemy( 0 );
                clearEnemy();
                setState( "state_Idle" );
            }
        }
    }
}

/*
=====================
monster_turret::combat_attack
=====================
*/
void monster_turret::combat_attack() {
    faceEnemy();

    fire = true;
    while( AI_ENEMY_VISIBLE && canHitEnemyFromJoint( "barrel" ) ) {
        lookAtEnemy( 1 );
        waitFrame();
        if ( sys.influenceActive() ) {
            break;
        }
        if ( AI_ACTIVATED ) {
            setState( "state_Disabled" );
            break;
        }
    }
    fire = false;
}

VGames

He shoots the crap out of me but not the monsters. I set his team value to 0 and he does absolutely nothing except follow me until I spawn a monster. Then he just sits there. Am I missing something?
Get the latest on Perfected Doom 3 here - http://www.moddb.com/mods/perfected-doom-3-version-500

The Happy Friar

I checked the map I used them in.  I set the player's team to "0" & their team to "0".  And I see what I did.  I bound a large trigger for the range of the guns to the ship that the guns were bound to.  I set the guns to be triggered.  When a monster would activate the trigger the guns would fire on it.  That was my cheap solution for weapon range.  :)

VGames

So what would I do if I'm not editing maps?
Get the latest on Perfected Doom 3 here - http://www.moddb.com/mods/perfected-doom-3-version-500

The Happy Friar

I'd say use the walking turret.  He autofires against monsters.