$MIN_SCAN_GAP = 1000; $MAX_SCAN_GAP = 3000; $cardinalDirection[0] = "0 10000 0"; // N $cardinalDirection[1] = "6000 6000 0"; // NE $cardinalDirection[2] = "10000 0 0"; // E $cardinalDirection[3] = "6000 -6000 0"; // SE $cardinalDirection[4] = "0 -10000 0"; // S $cardinalDirection[5] = "-6000 -6000 0";// SW $cardinalDirection[6] = "-6000 0 0"; // W $cardinalDirection[7] = "-6000 6000 0"; // NW $NUM_CARDINALS = 8; $MAX_LEADER_RANGE = 100; $MIN_LEADER_RANGE = 10; $CATCH_LEADER_SPEED = 0.6; $JOIN_SWARM_SPEED = 0.4; $SWARM_SPEED = 0.5; $LOST_SPEED = 0.2; $STATIONARY = 0.01; datablock PlayerData(SwarmBotDB : LightMaleHumanArmor) { className = "NPC"; maxInv[CrossbowAmmo] = 500000; }; function SwarmBotDB::DoScan(%thisDB,%thisBot) { if(!isObject(%thisBot)) return; cancel(%thisBot.nextScan); %leader = %thisBot.FindLeader(%thisBot); if (isObject(%leader)) { error("LEADER FOUND!:"@%leader@" from:"@%thisBot); if (!%leader.aiPlayer) // real player, not ai { if ( (%leader != %thisBot.leader )) { %thisBot.leader = %leader; %thisBot.SetAimObject( %thisBot.leader ); %thisBot.SetMoveSpeed($CATCH_LEADER_SPEED); %thisBot.Avoid(); %thisBot.SetMoveDestination(%leader.getTransform(),0); error("GONNA CATCH LEADER!...from:"@%thisBot); } else if (isObject(%thisBot.leader)) { %thisBot.Avoid(); %thisBot.SetMoveDestination(%leader.getTransform(),0); error("TRYING TO CATCH LEADER!...from:"@%thisBot); } } else { %thisBot.leader = %leader; %thisBot.SetAimObject( %thisBot.leader ); %thisBot.SetMoveSpeed($SWARM_SPEED); %thisBot.CentreOnSwarm(); error("nearest object must be an AI!...from:"@%thisBot); } } else { %thisBot.SetMoveSpeed($LOST_SPEED); %loc = $cardinalDirection[getRandom($NUM_CARDINALS-1)]; %thisBot.SetAimLocation( %loc); %thisBot.Avoid(); %thisBot.SetMoveDestination(%loc,0); error("leaderless..:^(...from:"@%thisBot); } %thisBot.nextScan = %thisDB.schedule($MIN_SCAN_GAP+getRandom($MAX_SCAN_GAP), "doScan", %thisBot); } function InitSwarm() { new SimSet (AISwarmGroup); SpawnASwarm(); } function SpawnASwarm() { if ( (%role=nameToID("MissionGroup/AIDropPoints/Swarm")) >= 0 ) { %count=%role.getCount(); for ( %i = 0; %i < %count; %i++) { spawnbot(%i,"Swarm"); } } } function spawnbot(%index,%role) { %thisBot = new AIPlayer() { dataBlock = SwarmBotDB; aiPlayer = true; }; MissionCleanup.add(%thisBot); AISwarmGroup.add(%thisBot); %thisBot.SetAimObject( 0 ); %spawn=pickAISpawn(%index,%role); %thisBot.index = %index; %thisBot.SetTransform(%spawn.getTransform()); %thisBot.SetEnergyLevel(60); %thisBot.role = %role; %thisBot.SetName(%spawn.getName() SPC %bot.role); %thisBot.SetShapeName( %thisBot.getName()); echo("Added [" SPC %thisBot SPC "] :" SPC %thisBot.role SPC "#" SPC %thisBot.index ); %thisBot.SetMoveSpeed($LOST_SPEED); %thisBot.SetAimLocation( $cardinalDirection[getRandom($NUM_CARDINALS-1)]); %thisBot.nextScan = %thisBot.getDataBlock().schedule(2000, "doScan", %thisBot); return %thisBot; } function pickAISpawn(%index,%role) { %groupName = "MissionGroup/AIDropPoints/" @ %role; %group = nameToID(%groupName); if (%group != -1) { %count = %group.getCount(); if (%count != 0) { // %index = getRandom(%count-1); %spawn = %group.getObject(%index); return %spawn; } else DebugPrint("No spawn points found in " @ %groupName, "pickAISpawn"); } else DebugPrint("Missing spawn points group " @ %groupName, "pickAISpawn"); return %spawn; } function AIPlayer::CentreOnSwarm(%thisBot) { //get the loc for every AI in the group. //average the heading //turn to new heading %maxx=0; %minx=100000; %maxy=0; %miny=100000; %count = AISwarmGroup.getCount(); echo("count:"@%count); for (%i=0;%i<%count;%i++) { %pos=AISwarmGroup.getObject(%i).GetPosition(); %x=Getword(%pos,0); %y=Getword(%pos,1); if (%x<%minx) %minx=%x; else if (%x>%minx) %maxx=%x; if (%y<%miny) %miny=%y; else if (%y>%miny) %maxy=%y; } %dx = %maxx - %minx; %x = %minx + (%dx/2); %dy = %maxy - %miny; %y = %miny + (%dy/2); %thisBot.SetMoveDestination(%x SPC %y SPC "0",0); %thisBot.SetMoveSpeed($JOIN_SWARM_SPEED); } function AIPlayer::Avoid(%thisBot) { if (isObject(%thisBot) && isObject(%thisBot.leader) ) { %distance = VectorDist(%thisBot.getPosition(), %thisBot.leader.getPosition()); if (%distance < $MIN_LEADER_RANGE) { %thisBot.SetMoveSpeed($STATIONARY); } } } // only a buddy if he's within range function AIPlayer::FindNearestSwarmer(%thisBot) { %result = -1; %swarmer=%thisBot.GetClosestSwarmAI(); if ( isObject(%thisBot) && isObject(%swarmer) ) { echo ("looking for buddy!"); %tbp = %thisBot.getPosition(); %sp = %swarmer.getPosition(); echo ("%thisBot.getPosition():"@%tbp SPC "%swarmer.getPosition():"@%sp); %distance = VectorDist(%tbp, %sp); echo ("%distance :"@%distance ); if ( (%distance <= $MAX_LEADER_RANGE) && (%distance > $MIN_LEADER_RANGE) ) { %result = %swarmer; echo ("found a possible!"); } } return %result; } function AIPlayer::GetClosestSwarmAI(%thisBot) { %index = -1; %botPos = %thisBot.getPosition(); %count = AISwarmGroup.getCount(); for(%i = 0; %i < %count; %i++) { %ai = AISwarmGroup.getObject(%i); if (%ai == %thisBot) continue; if (isObject(%ai)) { %aiPos = %ai.getPosition(); %tempDist = VectorDist(%aiPos, %botPos); if(%i == 0) { %dist = %tempDist; %index = %i; } else { if(%dist > %tempDist) { %dist = %tempDist; %index = %i; } } } } return AISwarmGroup.getObject(%index); } // only a leader if he's within range function AIPlayer::FindLeader(%thisBot) { %result = -1; %idx=%thisBot.GetClosestHuman(); %client = ClientGroup.getObject(%idx); if ( isObject(%client.player) ) { %distance = VectorDist(%thisBot.getPosition(), %client.player.getPosition()); if ( (%distance <= $MAX_LEADER_RANGE) && (%distance > $MIN_LEADER_RANGE) ) { %result = %client.player; } } else { %idx=%thisBot.GetClosestAI(); %result = AISwarmGroup.getObject(%idx); } return %result; } function AIPlayer::GetClosestHuman(%this) { %index = -1; %botPos = %this.getPosition(); %count = ClientGroup.getCount(); for(%i = 0; %i < %count; %i++) { %client = ClientGroup.getObject(%i); if (%client.player $= "" || %client.player == 0 ) return -1; %playPos = %client.player.getPosition(); %tempDist = VectorDist(%playPos, %botPos); if(%i == 0) { %dist = %tempDist; %index = %i; } else { if(%dist > %tempDist) { %dist = %tempDist; %index = %i; } } } return %index; }