Below is my WIP synced saber ai cog. For some reason, after the AI is killed and respawns is runs the sector of the code that seeks an old target, which is good...but should not be happening after they die! It doesn't make sense because when its killed its flags are reset, oldtarget is set to -1 and oldtargetpos is set to the ai's pos. Not only should it fail the relational test for the flags and not ever even run that code in the first place...but if it did, the code should result in the ai going nowhere.
But no, it seeks out the oldtargetpos right after respawning. Why? Am I missing something?
The AI also no longer attacks, which it once did great...I'm not sure how I broke that.
Btw...this includes the clever little hack by DSLS_DeathSythe to make sabers work on spawned actors.
[This message has been edited by Wave_Of_Mutilation (edited August 31, 2004).]
But no, it seeks out the oldtargetpos right after respawning. Why? Am I missing something?
The AI also no longer attacks, which it once did great...I'm not sure how I broke that.
Btw...this includes the clever little hack by DSLS_DeathSythe to make sabers work on spawned actors.
Code:
flags=0x80
symbols
message startup
message timer
message damaged
message killed
message pulse
message activated
message touched
thing aipos nolink
int trig
int team=0
flex movespeed=0.35
flex firerate=1.0
flex awarerange=4.5
flex maxrange=4.5
flex minrange=.3
flex respawndelay=10.0
int lives=0
template drop1=+dstrifle
template drop2=+denergycell
template aitpl=ais_st2
keyframe AttackKey=kycharge.key
keyframe AttackKey2=s5punch.key
keyframe AttackKey3=s5punch.key
sound firesnd=hsblaster.wav
sound firesnd2=hsblaster.wav
sound firesnd3=hsblaster.wav
#used internally
thing ai local mask=0xfff
thing oldtarget local
thing player local
vector oldtargetpos local
flex disttotarg local
vector relpos local
int aimode local
int stopcount local
int targetok local
int targetpriority local
int newtargetpriority local
flex dist local
flex mindist local
thing target local
thing newtarget local
flex Dot local
flex MaxDot local
flex damage local
int damagetype local
thing damager local
model saberMesh=sabg.3do local
material tip_mat=saberblue0.mat local
material side_mat=saberblue1.mat local
template tpl_wall=+ssparks_wall local
template tpl_blood=+ssparks_blood local
template tpl_saber=+ssparks_saber local
int debug=0
end
# ========================================================================================
code
# ========================================================================================
startup:
sleep(4.0);
print("run");
if(!IsMulti() || IsServer())
call makeai;
return;
# ========================================================================================
makeai:
//if(BitTest(controlflags, 0x8)) return;
ai = GetGuidThing(CreateThing(aitpl, aipos));
CaptureThing(ai);
//give them a saber
jkSetWeaponMesh(ai, saberMesh);
jkSetSaberInfo(ai, side_mat, tip_mat, 0.003, 0.001, 0.120, tpl_wall, tpl_blood, tpl_saber);
jkSetFlags(ai, 0x5);
SetActorFlags(ai, 0x2000);
//set move speed
AiSetMoveSpeed(ai, movespeed);
//team stored in userdata
SetThingUserData(ai, team);
//we died so forget about who we were after
oldtarget = -1;
oldtargetpos = aipos; // set to ai start spot
aimode = BitSet(aimode, 0x100); // ai alive
//run the thing pulse
SetPulse(0.1);
return;
# ========================================================================================
# called from pulse
findtarget:
newtarget=-1;
maxdot = -1;
mindist = 100;
targetpriority = 0;
newtargetpriority = -1;
potential = FirstThingInView(ai, 270, 8.0, 0x404); // find (0x404 - player or actor)
while(potential != -1) // valid target
{
targetok = 1;
if (GetThingType(potential) == 2 && GetThingUserData(potential) == team)
targetok = 0; // target is an actor and is on our team
if (GetThingType(potential) == 10 && GetPlayerTeam(potential) == team)
targetok = 0; // target is a player and is on our team
if (GetThingFlags(potential) & 0x200)
targetok = 0; // target is dead
if (BitTest(GetSectorFlags(GetThingSector(potential)), 0x40))
targetok = 0; // target in pit
if (targetok && potential != ai && HasLOS(ai, potential)) // target is still ok, is not itself and ai can see it
{
// Work out target priority
dist = VectorDist(GetThingPos(ai), GetThingPos(potential));
if (dist > 0 && dist < 1)
targetpriority = 6;
else
targetpriority = 3; // closer targets get higher priority
if (damager != -1 && GetThingParent(damager) == potential)
targetpriority = 7; // whoever hurt the ai last is higher priority
if (targetpriority > newtargetpriority)
{
newtarget = potential;
newtargetpriority = targetpriority;
}
}
potential = NextThingInView();
}
if(target != -1) //don't dump a null target to the old target as we use it to find lost targets that are real
{ //old target will be used to find a foe we lost sight of, but is still near us
oldtarget = target;
//grab the pos the target is currently at, if we lose the target we will try to find him by going to where he was.
aimode = BitSet(aimode, 0x80); //ai now has oldtarget pos to seek from
oldtargetpos = GetThingPos(target);
}
target = newtarget;
if (target == -1) // ai doesn't have a target
{
aimode = BitClear(aimode, 0x40); //no target for ai
if(Bittest(aimode,0x80)) // we will seek where a target was last seen first, so look at it
AiSetLookPos(ai, oldtargetpos);
//if(oldtarget != -1 && VectorDist(GetThingPos(ai), GetThingPos(oldtarget)) < awarerange)
//{
//KillTimerEx(500);
//SetTimerEx(0.2 + Rand(), 500, -1, -1); // after a short time, find the target again if he is close
//print("recover target attempt");
//AiSetLookPos(ai, getthingpos(oldtarget));
//}
print("no target");
}
else // ai has a target
{
print("target found");
AiSetFireTarget(ai, target);
AiSetLookPos(ai, getthingpos(target));
aimode = BitSet(aimode, 0x40); //ai now has target, allow next part of code
}
return;
# ========================================================================================
# called from pulse
offense:
if (!Bittest(aimode,0x100)) return; // ai has died
if (BitTest(aimode,0x200)) return; // ai is already attacking, timers will handle repeat attacks from now on
if(!Bittest(aimode,0x40) && !Bittest(aimode,0x80)) return; //if we don't have a target in our sights or an old pos to go after, bail out
//disttotarg = VectorDist(GetThingPos(ai), GetThingPos(target));
if(Bittest(aimode,0x40) && VectorDist(GetThingPos(ai), GetThingPos(target)) < minrange && HasLOS(ai, target))
//meets requirements to be attacked now, has target, distance is good, has LOS
call fireattarget;
else
call movetotarget;
return;
# ========================================================================================
# called from offense
movetotarget:
if (!BitTest(aimode, 0x100)) // ai dead or no target, timer indicates they where lost,
// but firetarget must remove flag
return;
//AiSetLookPos(ai, getthingpos(target));
if(Bittest(aimode,0x40)) //go after the target if we have one
AiSetMovePos(ai, GetThingPos(target));
else //if we have no target, proceed to the old targets pos
if(Bittest(aimode,0x80))
{
if(VectorDist(GetThingPos(ai), oldtargetpos) < 0.1) //allow for some margin of error here, because of different sized actors
{
if(VectorDist(GetThingPos(ai), GetThingPos(ai)) < awarerange)
AiSetLookPos(ai, getthingpos(oldtarget)); //once we arrive at last know pos, take once last glance attempt to find our lost target
oldtarget = -1; //give up on target
aimode = BitClear(aimode, 0x80); //no longer have an old target
oldtargetpos = GetThingPos(ai); //set us as arrived
}
else
AiSetMovePos(ai, oldtargetpos);
//print("running seek old code");
}
else //this probably won't ever get called
return;
if (VectorY(GetThingVel(ai)) < 0.01) // bot is not moving forward
{
stopcount = stopcount + 1;
if (stopcount == 30)
{
ApplyForce(ai, VectorScale(VectorSub(GetThingLVec(ai), '0 0 -90'), 3.0)); // force bot to jump
stopcount = 0;
}
}
else
stopcount = 0;
return;
# ========================================================================================
# called from offense
firetarget:
//return; // hack to stop ais firing - testing only
KillTimerEx(300); // make sure no other 'fire' target is active, stop attack loop
if (!BitTest(aimode, 0x100) || !Bittest(aimode, 0x40)) // ai dead or no target, timer indicates they where lost,
// but firetarget must remove flag
{
aimode = BitClear(aimode, 0x200); //turn off attacking mode and cancel
return;
}
AiSetMovePos(ai, getthingpos(ai));
aimode = BitSet(aimode, 0x200); // ai is now attacking, turn on attack mode flag
//disttotarg = VectorDist(GetThingPos(ai), GetThingPos(target));
//relpos = VectorSet("0.0","0.0", VectorZ(GetThingPos(target))-VectorZ(GetThingPos(ai))); // work out relative position of
//target to ai
if(VectorDist(GetThingPos(ai), GetThingPos(target)) < minrange && HasLOS(ai, target)) // reality check, can we still attack the
//target from here?
{
//AiSetLookPos(ai, getthingpos(target));
print("attack");
SetThingType(ai, 10);
jkEnableSaber(ai, 50.0, 0.3, 0.5);
SetThingType(ai, 2);
PlayKey(ai, AttackKey[Rand() * 3], 2, 0x38);
PlaySoundThing(firesnd[Rand() * 3], ai, 1.0, -1.0, -1.0, 0x80);
SetTimerEx(firerate, 300, -1, -1); // wait for a short time before firing again
}
else
{
aimode = BitClear(aimode,0x200); // ai is no longer attacking, turn off attack flag
KillTimerEx(300); // make sure no other 'fire' target is active, stop attack loop
}
return;
# ========================================================================================
pulse:
if(!IsMulti() || IsServer())
{
//setpulse(0);
call findtarget;
call offense;
if(IsMulti())
syncthingpos(ai);
}
return;
return;
# ========================================================================================
damaged:
if(!IsMulti() || IsServer())
{
damage = GetParam(0);
damagetype = GetParam(1);
damager = getsourceref(); // projectile - attacker=GetThingParent()
if (damager != -1 && (GetThingType(GetThingParent(damager)) == 2 || GetThingType(GetThingParent(damager)) == 10)) // attacker is another ai or player
AiSetLookPos(ai, getthingpos(GetThingParent(damager))); // briefly look at who damaged the ai
//if (BitTest(gamemode,0x8) && ((GetThingType(GetThingParent(damager)) == 10 && GetPlayerTeam(GetThingParent(damager)) == team) || (GetThingType(GetThingParent(damager)) == 2 && GetThingUserData(GetThingParent(damager)) == team)))
// damage = 0;
ReturnEx(damage);
}
return;
# ========================================================================================
touched:
if (GetThingType(GetThingParent(GetSourceRef())) == 2 || GetThingType(GetThingParent(GetSourceRef())) == 10) // attacker is another ai or player
AiSetLookPos(ai, getthingpos(GetThingParent(GetSourceRef()))); // briefly look at who damaged the ai
return;
# ========================================================================================
blockstuff:
return;
if (curweap == 10 && BitTest(aimode,0x200000)) // ai has saber - check if it can block
{
// Check for saber blocking
dot = ThingViewDot(ai, getthingparent(damager));
if ((BitTest(damagetype, 0x10) && dot > 0.9 && dot < 1.1 && difficulty < 2) || (BitTest(damagetype, 0x10) && dot > 0.5 && dot < 1.5 && difficulty < 4) || (BitTest(damagetype, 0x10) && dot > 0.3 && dot < 1.7)) // attacker has saber & ai is facing attacker
{
SendTrigger(-1, 2100, aiid, ai, -1, -1); // send trigger to client to play saber block animation
ReturnEx(0);
return;
}
if ((BitTest(damagetype, 0x2) && dot > 0.9 && dot < 1.1 && difficulty < 2) || (BitTest(damagetype, 0x2) && dot > 0.5 && dot < 1.5 && difficulty < 4) || (BitTest(damagetype, 0x2) && dot > 0.3 && dot < 1.7)) // attacked by energy weapon & ai is _mainly_ facing attacker
{
SendTrigger(-1, 2100, aiid, ai, getthingtemplate(damager), -1); // send trigger to play saber block animation & deflect projectile
ReturnEx(0);
return;
}
}
return;
# ========================================================================================
killed:
if(!IsMulti() || IsServer())
{
print("killed");
setpulse(0);
StopThing(ai);
aimode = 0; // ai no longer alive, clear all flags
KillTimerEx(300); // stop firing at target?
KillTimerEx(400); // stop checking if ai is in a pit?
KillTimerEx(500); // no save for find
ReleaseThing(ai);
SetTimerEx(respawndelay, 10, -1, -1); // respawn ai
}
return;
# ========================================================================================
timer:
if (GetSenderId() == 10) // respawn
{
call makeai;
}
else if (GetSenderId() == 130) // allow ai to run full speed again after slowdown
{
aimode=BitClear(aimode, 0x100000);
}
else if (GetSenderId() == 170) // Forget who damaged ai
{
damager = -1;
}
else if (GetSenderId() == 300) // fire again at target
{
call firetarget;
}
else if (GetSenderId() == 450) // Allow ai to block again
{
aimode = BitClear(aimode, 0x2000);
}
else if (GetSenderId() == 500) // try to find a lost target again
{
if (!Bittest(aimode,0x40) && Bittest(aimode,0x100))
{
print("recover target");
AiSetLookPos(ai, getthingpos(oldtarget));
}
//oldtarget = -1; //do not try again
}
return;
# ========================================================================================
end[This message has been edited by Wave_Of_Mutilation (edited August 31, 2004).]