I'm trying to make zombies that will chase a player if it's close enough, but if not will move towards the nearest light. So I took a script I found and tried to add the light code.
Here's my code:
$Pref::Bot::Intelligence = 500; // raise to max of 1000, 500 default
$Pref::Bot::MaxLightDist = 300;
$Pref::Bot::MinLightDist = 7;
$Pref::Bot::MaxPlayerDist = 50;
deactivatepackage(dren);
package dren
{
function AIPlayer::canSeeObject(%this, %object)
{
%ev = %this.getEyeVector();
%pos = %this.getPosition();
if(!isObject(%object))
return 0;
if(isFunction(%object.getClassname(), getEyePoint))
%ep = %object.getEyePoint();
else
%ep = %object.getPosition();
%vd = vectorDist(%pos, %ep);
if(%vd > 64)
return 0;
%cast = containerRaycast(%pos, %ep, $TypeMasks::FxBrickObjectType);
if(isObject(%cast))
return 0;
%adjp = vectorSub(%pos, %ep);
%angle = mATan(getWord(%adjp,1), getWord(%adjp,0));
%ea = mATan(getWord(%ev,1), getWord(%ev,0));
%cansee = %ea - %angle;
%canSee = mAbs(%canSee);
if(%cansee > 3.92689 || %cansee < 2.35629)
return 0;
return 1;
}
function AIPlayer::canSeePos(%this, %ep)
{
%ev = %this.getEyeVector();
%pos = %this.getPosition();
%vd = vectorDist(%pos, %ep);
if(%vd > 64)
return 0;
%cast = containerRaycast(%pos, %ep, $TypeMasks::FxBrickObjectType);
if(isObject(%cast))
return 0;
%adjp = vectorSub(%pos, %ep);
%angle = mATan(getWord(%adjp,1), getWord(%adjp,0));
%ea = mATan(getWord(%ev,1), getWord(%ev,0));
%cansee = %ea - %angle;
%canSee = mAbs(%canSee);
if(%cansee > 3.92689 || %cansee < 2.35629)
return 0;
return 1;
}
function closestLight(%pos)
{
%closestplayer = -1;
%closestdist = -1;
for(%a=0;%a<$numlights;%a++)
{
%playerpos = $lightpos[%a];
if(%closestdist == -1 || vectorDist(%pos,%playerpos) < %closestdist)
{
%closestdist = vectorDist(%pos,%playerpos);
%closestplayer = %a;
}
}
return %closestplayer;
}
function AIPlayer::doThinkMove(%this)
{
if(isObject(%this.getMoveObject()))
%this.setMoveObject(0);
%ev = %this.getEyeVector();
%pos = %this.getPosition();
for(%i = 0; %i < clientGroup.getCount(); %i++)
{
if(!isObject(%o = clientGroup.getObject(%i).player))
continue;
if(%o.getObjectMount() == %this.getID())
continue;
%ep = %o.getEyePoint();
%vd = vectorDist(%pos, %ep);
if(%vd > $Pref::Bot::MaxPlayerDist)
continue;
%cast = containerRayCast(%pos, %ep, $TypeMasks::FxBrickAlwaysObjectType);
if(isObject(%cast))
continue;
%adjp = vectorSub(%pos, %ep);
%angle = mATan(getWord(%adjp,1), getWord(%adjp,0));
%ea = mATan(getWord(%ev,1), getWord(%ev,0));
%cansee = %ea - %angle;
%canSee = mAbs(%canSee);
if(%cansee > 3.92689 || %cansee < 2.35629)
continue;
if(%vd > %closestDist && %closestDist !$= "")
continue;
%closestDist = %vd;
%closestObj = %o;
}
if(isObject(%closestObj))
{
%this.chasePlayer(%closestObj, %closestDist);
return;
}
else if((closestLight(%this.position) > -1) && vectorDist($lightpos[closestLight(%this.position)],%this.position) > $Pref::Bot::MinLightDist && vectorDist($lightpos[closestLight(%this.position)],%this.position) < $Pref::Bot::MaxLightDist)
{
%this.moveSchedule = %this.schedule(100,chaseLight,$lightpos[closestLight(%this.position)]);
return;
}
%this.goToPos(vectorAdd(%this.getPosition(), getRandom(-5,5) SPC getRandom(-5, 5) SPC 0));
%this.moveSchedule = %this.schedule(1000, doThinkMove);
}
function aiPlayer::goToPos(%this, %pos)
{
%this.thinkNextMove(%pos);
}
function aiPlayer::ChasePlayer(%this, %player)
{
if(!isObject(%player))
{
%this.doThinkMove();
return;
}
if(%player.getState() !$= "Move" || vectorDist(%this.getPosition(),%player.getPosition()) > $Pref::Bot::MaxPlayerDist)
{
%this.doThinkMove();
return;
}
if(%this.canSeeObject(%player))
{
%this.setMoveObject(%player);
if(vectorDist(%this.getPosition(),%player.getPosition()) < 4 && %player.getState() $= "Move")
%this.attack(%player);
if(isObject(%player) && %player.getState() !$= "")
%this.moveSchedule = %this.schedule(500, chasePlayer, %player);
else
%this.doThinkMove();
//announce("Returning");
return;
}
if(isObject(%this.getMoveObject()))
%this.setMoveObject(0);
//announce("dynamic chase");
%this.thinkNextMove(%player);
%this.moveSchedule = %this.schedule(1000-$Pref::Bot::Intelligence, chasePlayer, %player);
}
function aiPlayer::ChaseLight(%this, %pos)
{
if(closestLight(%this.position) == -1)
{
%this.doThinkMove();
return;
}
if(vectorDist(%this.getPosition(),%pos) > $Pref::Bot::MaxLightDist || vectorDist(%this.getPosition(),%pos) < $Pref::Bot::MinLightDist)
{
%this.doThinkMove();
return;
}
if(%this.canSeePos(%pos))
{
%this.moveSchedule = %this.schedule(500, chaseLight, %pos);
return;
}
if(isObject(%this.getMoveObject()))
%this.setMoveObject(0);
%this.thinkNextMove(%pos);
%this.moveSchedule = %this.schedule(1000-$Pref::Bot::Intelligence, chaseLight, %pos);
}
function AIPlayer::attack(%this, %player)
{
%this.setImageTrigger(0,1);
%this.schedule(100, setImageTrigger, 0, 0);
}
function AIPlayer::ThinkNextMove(%this, %dest)
{
if(isObject(%dest) && (%dest.getClassName $= "fxDTSBrick" || %dest.getClassName $= "PlayerData"))
%destination = %dest.getPosition();
else
%destination = %dest;
%this.destination = %dest;
%realism = 10; // Higher = more realistic
%realismAngles = mFloor(180/%realism);
%myangle = mRadToDeg(mATan(getWord(%ev=%this.getEyeVector(),1),getWord(%ev,0)));
for(%i = 0; %i <= %realism; %i++)
{
%angle = mDegToRad(%realismAngles * %i);
%angle = mCos(%angle) * 90;
%angle += %myangle;
%x = mCos(mDegToRad(%angle))*2;
%y = mSin(mDegToRad(%angle))*2;
%ray = containerRaycast(%this.getEyePoint(), %pos = vectorAdd(%this.getEyePoint(), %x SPC %y SPC -0), $TypeMasks::FxBrickObjectType);
%dir = vectorAdd(%this.getPosition(), %x SPC %y SPC 0);
if(isObject(getWord(%ray,0)))
{
//%ray.getID().setColor(%ray.getID().getColorID()+1);
continue;
}
%dist = vectorDist(%pos, %destination);
if(%dist < %closest || %closest $= "")
{
%ray = containerRayCast(vectorAdd(%this.getEyePoint(),mCos(mDegToRad(%myAngle)+1.5708) SPC mSin(mDegToRad(%myAngle)+1.5708) SPC 0), %pos, $TypeMasks::FxBrickObjectType);
if(isObject(%ray))
continue;
%ray = containerRayCast(vectorAdd(%this.getEyePoint(),mCos(mDegToRad(%myAngle)-1.5708) SPC mSin(mDegToRad(%myAngle)-1.5708) SPC 0), %pos, $TypeMasks::FxBrickObjectType);
if(isObject(%ray))
continue;
%closest = %dist;
%closestpos = %pos;
%closestdir = %dir;
}
}
if(%closestpos $= "")
{
%myangle -= 180;
%x = mCos(mDegToRad(%myangle))*3;
%y = mSin(mDegToRad(%myangle))*3;
%pos = vectorAdd(%this.getEyePoint(), %x SPC %y SPC 0);
%closestpos = %pos;
}
if(getWord(vectorSub(%this.getPosition(), %destination),2) < -1.5)
{
if(%this.getMountedImage(2) != 0)
%this.mountImage(BlankImage2,2);
%this.setImageTrigger(2,1);
%this.schedule(330,setImageTrigger,2,0);
}
//announce(%closestpos);
//m(%closestpos);
%this.setMoveDestination(%closestpos,0);
//%this.setAimLocation(getWords(%closestpos,0,1) SPC getWord(%this.getPosition(),2)+2.1);
//%this.moveSchedule = %this.schedule(500,ThinkNextMove,%dest);
}
function eulerToAxis(%euler)
{
%euler = VectorScale(%euler,$pi / 180);
%matrix = MatrixCreateFromEuler(%euler);
return getWords(%matrix,3,6);
}
function axisToEuler(%axis)
{
%angleOver2 = getWord(%axis,3) * 0.5;
%angleOver2 = -%angleOver2;
%sinThetaOver2 = mSin(%angleOver2);
%cosThetaOver2 = mCos(%angleOver2);
%q0 = %cosThetaOver2;
%q1 = getWord(%axis,0) * %sinThetaOver2;
%q2 = getWord(%axis,1) * %sinThetaOver2;
%q3 = getWord(%axis,2) * %sinThetaOver2;
%q0q0 = %q0 * %q0;
%q1q2 = %q1 * %q2;
%q0q3 = %q0 * %q3;
%q1q3 = %q1 * %q3;
%q0q2 = %q0 * %q2;
%q2q2 = %q2 * %q2;
%q2q3 = %q2 * %q3;
%q0q1 = %q0 * %q1;
%q3q3 = %q3 * %q3;
%m13 = 2.0 * (%q1q3 - %q0q2);
%m21 = 2.0 * (%q1q2 - %q0q3);
%m22 = 2.0 * %q0q0 - 1.0 + 2.0 * %q2q2;
%m23 = 2.0 * (%q2q3 + %q0q1);
%m33 = 2.0 * %q0q0 - 1.0 + 2.0 * %q3q3;
return mRadToDeg(mAsin(%m23)) SPC mRadToDeg(mAtan(-%m13, %m33)) SPC mRadToDeg(mAtan(-%m21, %m22));
}
};
activatepackage(dren);
The first problem is they're not aggressive enough. They'll chase people sometimes, but you usually have to wait a bit.
The second and far worse problem is that it seems to crash, but nothing shows in the console, and it takes far too long to make tracing it a possibility.
Could anyone offer some assistance to at least make this not crash, and maybe make it a bit better?
edit: I tried leaving trace on, but the console log becomes over 20 megabytes and then bl crashes from a buffer overrun. So yeah, tracing isn't an option.