{gatling gun settings}
gAmmo = 600; //1 shoot uses 2 bullets, use only even value
gPower = 0.35;
gSpeed = 30; //bullet speed;
gInt = 2; //NOTE Modifing can cause issues. '1' gives 40 rounds per secound, but may be unstable.
gAccuracy = 7;
//gStarting = 10; (disabled)
Hey, How can a bot stay without shooting or moving ? :SCall him dummy.... everyone knows that :P
Call him dummy.... everyone knows that :Pwoah. Is there another special name ?
(...)It is not attack the creator/creators team already.
Question: Can you assign the sentry guns to teams/players, so they won't attack the creator/creators team?
(...)
woah. Is there another special name ?No, only Dummy.
What would be nice is an automatic turret that could somehow be scripted, one that wouldn't need someone standing by it, Sentry style.The bot is only there as a marker for where the turret is, the turret is automatic, it aims and shoots at the enemies when it can.
(in addition) it needs to be visible somehow, a bot works out well (especially on realistic, you don't see it until it becomes in sight, unlike a stat gun itself)What would be nice is an automatic turret that could somehow be scripted, one that wouldn't need someone standing by it, Sentry style.The bot is only there as a marker for where the turret is, the turret is automatic, it aims and shoots at the enemies when it can.
Do not use the script in teammatch gamemode because delta team is reserved only for sentrys.
This is a pitty, because the script would be nice to use in climb maps. Did you try making a sentry with a bot from DM-team (team 0)? I guess it does make the bots shoot at each other aswell?Climb is ctf...? :P
Climb is ctf...? :P
{Sentry Gun script by tk}
{version 0.92}
const
{settings}
MAX_NUM_OF_PLAYERS = 16; //max number of players on the server. Do not set value greater than 26.
SENTRY_TEAM = 0;
SENTRY_DURATION = 120;
cRed = $EE5C42;
cGreen = $BCEE68;
{gatling gun settings}
gAmmo = 800000;
gPower = 0.35;
gSpeed = 30; //bullet speed;
gInt = 2; //NOTE Modifing can cause issues. '1' gives 40 rounds per secound, but may be unstable.
gAccuracy = 8;
{heavy mg settings}
hgAmmo = 300;
hgPower = 1;
hgSpeed = 35;
hgInt = 3; //NOTE Modifing can cause issues.
hgAccuracy = 6;
{flak cannon}
fcAmmo = 200;
fcPower = 10;
fcSpeed = 22;
fcInt = 2; //NOTE Modifing can cause issues.
fcDivergence = 10;
{shotgun settings}
sgAmmo = 80;
sgPower = 1.8;
sgSpeed = 20;
sgPellets = 7; //number of shotgun pellets
sgInt = 17; //NOTE Modifing can cause issues.
sgSpread = 12;
{auto aiming missile settings}
mlAmmo = 8;
rocketFuel = 45; // recommended not to use value greater than 50.
accuracy = 40; //0 - the best accuracy. Recommended not to use value greater than 40.
acceleration = 3; // 3
flametraceMovement = 2; // 2
MAX_PLAYERS = MAX_NUM_OF_PLAYERS + 5; //do not modify it
type
tPlayer = record
is_sentry: boolean;
sentry_ID: byte;
end;
type
tSentry = record
owner,botID,style,target: byte;
duration,ammo: word;
last_fire: integer;
end;
var
player: array[1..MAX_PLAYERS] of tPlayer;
sentry: array[1..5] of tSentry;
missile_reload: integer;
sgBullID: byte;
disabled: boolean;
procedure nova(X,Y,dir_x,dir_y,r,speed,power: single; n: word; style, id: byte);
var
angle,sine,cosine: single;
begin
angle:=6.28318/n;
for n:=n downto 1 do
begin
sine:=sin(angle*n);
cosine:=cos(angle*n);
CreateBullet(cosine*r + X, sine*r + Y,cosine*speed + dir_x,sine*speed + dir_y,power, style, ID);
end;
end;
procedure Missile(owner_ID, target_ID: Byte; X, Y: Single);
{v. 1.6}
var
poly_coll, target_coll: Boolean;
n, interval: Word;
X2, Y2, dist, next_dist_x, next_dist_y, prev_dist_x, prev_dist_y, rd: Single;
begin
GetPlayerXY(target_ID,X2,Y2);
dist:=Distance(X,Y,X2,Y2);
next_dist_x:=(X2-X)/(dist/10);
next_dist_y:=(Y2-Y)/(dist/10);
X:=X + next_dist_x;
Y:=Y + next_dist_y;
prev_dist_x:=next_dist_x;
prev_dist_y:=next_dist_y;
interval:=40;
while n < rocketFuel do
begin
Sleep(interval);
next_dist_x:=((X2-X)/(dist/(20+accuracy*2))+prev_dist_x*accuracy) / (accuracy+1);
next_dist_y:=((Y2-Y)/(dist/(24+accuracy*2))+prev_dist_y*accuracy) / (accuracy+1);
prev_dist_x:=next_dist_x;
prev_dist_y:=next_dist_y;
X:=X + next_dist_x;
Y:=Y + next_dist_y;
GetPlayerXY(target_ID,X2,Y2);
dist:=Distance(X,Y,X2,Y2);
if dist > 80 then //poly dodging
begin
if not rayCast(X,Y,X+15,Y,rd,16) then X:=X - 15 else
if not rayCast(X,Y,X-15,Y,rd,16) then X:=X + 15;
if not rayCast(X,Y,X,Y+18,rd,19) then Y:=Y - 18 else
if not rayCast(X,Y,X,Y-18,rd,19) then Y:=Y + 18;
end;
if dist < 25 then //check for collision
begin
target_coll:=true;
break;
end else
if not RayCast(X,Y,X,Y,rd,1) then
begin
poly_coll:=true;
break;
end;
if dist > 10*flametraceMovement then //create one flame
CreateBullet(X, Y, next_dist_x/10*flametraceMovement, next_dist_y/10*flametraceMovement, 0, 5, owner_ID);
if interval > 9 then
interval:=interval-acceleration; //acceleration
n:=n+1;
end;
if target_coll then //collision with target
begin
DoDamageBy(target_ID, owner_ID, GetPlayerStat(target_ID, 'health')-1);
nova(X,Y,next_dist_x/2,next_dist_y/2,20,5,2,7,14,owner_ID);
nova(X2,Y2,0,0,30,8,2,9,14,owner_ID);
nova(X2,Y2,0,0,12,-3,10,5,4,owner_ID);
end else
if poly_coll then //collision with poly
begin
nova(X,Y,next_dist_x/2,next_dist_y/2,20,5,2,7,14,owner_ID);
nova(X,Y,0,0,20,-3,10,4,4,owner_ID);
end else
begin //no fuel
nova(X,Y,next_dist_x/3,next_dist_y/2,20,5,2,7,14,owner_ID);
CreateBullet(X, Y, next_dist_x/2, next_dist_x/3, 10, 4, owner_ID);
end;
end;
function Name(_type: byte): string;
begin
case _type of
1: Result:='Gatling gun';
2: Result:='Heavy machine gun';
3: Result:='Flak cannon';
4: Result:='Shotgun';
5: Result:='Missile launcher';
end;
end;
//PlaceSentry (ID of owner, type of sentry, X, Y, show WriteConsole info?)
//Returns ID of created sentry (0 if failed)
function PlaceSentry(ID,gun_type: byte; X,Y: single; show_info: boolean): byte;
var
i,j,k: byte;
place: boolean;
spawn_active: array[1..254] of boolean;
begin
if (GetPlayerStat(ID, 'Active') = true) and (GetPlayerStat(ID, 'Alive') = true) then
begin
if GetPlayerStat(ID, 'Ground') = true then
begin
if gun_type = 5 then //check if there is missile launcher in game
for i:=1 to 5 do
if sentry[i].style = 5 then
begin
if show_info then WriteConsole(ID, 'One "Missile launcher" is already placed. Choose another type of the gun.',cRed);
exit;
end;
for i:=1 to 5 do
if sentry[i].duration = 0 then
begin
place:=true;
break;
end;
if place then //force bot to spawn at given coords \/
begin
for j:=1 to 254 do
if GetSpawnStat(j, 'style') = SENTRY_TEAM then
begin
if GetSpawnStat(j, 'active') = true then spawn_active[j]:=true;
SetSpawnStat(j, 'active',false);
k:=j;
end;
SetSpawnStat(254, 'active',true);
SetSpawnStat(254, 'style',SENTRY_TEAM);
SetSpawnStat(254, 'X',X);
SetSpawnStat(254, 'Y',Y-10);
Result:=Command('/addbot'+inttostr(SENTRY_TEAM)+' Dummy');
SetSpawnStat(254, 'active',false);
for j:=1 to k do
if GetSpawnStat(j, 'style') = SENTRY_TEAM then
if spawn_active[j] then SetSpawnStat(j, 'active',true);
case gun_type of
1: begin sentry[i].ammo:=gAmmo; ForceWeapon(sentry[i].botID,10,255,0); end;
2: begin sentry[i].ammo:=hgAmmo; ForceWeapon(sentry[i].botID,3,255,0); end;
3: begin sentry[i].ammo:=fcAmmo; end;
4: begin sentry[i].ammo:=sgAmmo; ForceWeapon(sentry[i].botID,5,255,0); end;
5: begin sentry[i].ammo:=mlAmmo; end;
end;
GiveBonus(sentry[i].botID,3);
sentry[i].duration:=SENTRY_DURATION;
sentry[i].owner:=ID;
sentry[i].style:=gun_type;
sentry[i].botID:=Result;
player[sentry[i].botID].sentry_ID:=i;
player[sentry[i].botID].is_sentry:=true;
DrawText(ID,Name(gun_type)+' placed.',240,cGreen,0.112,20,360);
if show_info then WriteConsole(ID, 'Sentry gun placed. (Type: '+Name(gun_type)+'; Ammo: '+IntToStr(sentry[i].ammo)+'; Duration: '+IntToStr(SENTRY_DURATION)+' seconds)',cGreen);
end else if show_info then WriteConsole(ID, 'Sentry gun count limit exceeded. Gun can not be placed.',cRed);
end else if show_info then WriteConsole(ID, 'You have to be on the ground to place a sentry gun.',cRed);
end else if show_info then WriteConsole(ID, 'You have to be alive to place a sentry gun.',cRed);
end;
//RemoveSentry (ID of sentry(1..5), explode?, show WriteConsole info?)
procedure RemoveSentry(sID: byte; explosion, show_info: boolean);
var X,Y: single;
begin
if show_info then
if sentry[sID].ammo <= 0 then
WriteConsole(sentry[sID].owner, 'One of your sentry guns: '''+Name(sentry[sID].style)+''' has been destroyed (no ammo).',cRed) else
if sentry[sID].duration <= 0 then WriteConsole(sentry[sID].owner, 'One of your sentry guns: '''+Name(sentry[sID].style)+''' has been destroyed (duration exceeted).',cRed) else
WriteConsole(sentry[sID].owner, 'One of your sentry guns: '''+Name(sentry[sID].style)+''' has been destroyed.',cRed);
if explosion then begin
GetPlayerXY(sentry[sID].botID,X,Y);
nova(X,Y,0,0,12,4,0,5,4,sentry[sID].botID);
CreateBullet(X, Y, 0, 0, 0, 4, sentry[sID].botID);
end;
sentry[sID].duration:=0;
sentry[sID].style:=0;
sentry[SID].owner:=0;
sentry[sID].target:=0;
sentry[sID].ammo:=0;
sentry[SID].last_fire:=0;
KickPlayer(sentry[sID].botID);
end;
// for CrossFunc
function GetSentryStat(ID, stat: byte): integer; //ID of sentry gun, not of Dummy
begin
case stat of
1: Result:=sentry[ID].owner; //owner's ID
2: Result:=sentry[ID].duration; //time left
3: Result:=sentry[ID].style; //Type of sentry
4: Result:=sentry[ID].ammo; //Ammo left
end;
end;
procedure SetSentryStat(ID, stat: byte; value: integer); //ID of sentry gun, not of Dummy
begin
case stat of
1: sentry[ID].owner:=value; //owner's ID
2: sentry[ID].duration:=value; //time left
3: sentry[ID].style:=value; //Type of sentry
4: sentry[ID].ammo:=value; //Ammo left
end;
end;
//ID of bot(1..32) to ID of sentry(1..5);
function IdToSid(Bot_ID: byte): byte; begin
Result:=player[Bot_ID].sentry_ID; end;
//ID of sentry(1..5) to ID of bot(1..32);
function SidToId(Snt_ID: byte): byte; begin
Result:=sentry[Snt_ID].botID; end;
procedure Shoot(X,Y,X2,Y2,accuracy,divergence,speed,power: single; bullets,style,shooter: byte);
//v. 1.1
var i: shortint;
dist_x,angle: single;
a: boolean;
begin
dist_x:=X2 - X;
if dist_x < 0 then
begin
dist_x:=-dist_x;
a:=false;
end else
a:=true;
if dist_x <> 0 then
begin
angle:=arctan((Y2-Y)/(X2-X));
if not a then angle:=angle+Pi;
end else
if Y > Y2 then angle:=4.71239
else
angle:=2.35619;
if accuracy > 0 then
accuracy:=Random(1, Round(accuracy) + 1) / 500 * iif(Random(1, 3) = 1, 1, -1);
if style <> 5 then angle:=angle + divergence * bullets * 0.5 + accuracy - sqrt((dist_x*1.2)/(speed*speed)) / (3+speed*0.4)*iif(a,1,-1)
else angle:=angle + divergence*bullets*0.5 + accuracy;
for i:=1 to bullets do
CreateBullet(X, Y, cos(angle - i*divergence)*speed, sin(angle - i*divergence)*speed, power, style, shooter);
end;
procedure ProcessSentry(ID, SID: byte);
var
X,Y,X2,Y2,rand: single;
begin
if sentry[SID].ammo > 0 then
begin
GetPlayerXY(ID, X, Y);
Y:=Y-10;
if sentry[SID].style < 5 then
begin
GetPlayerXY(sentry[SID].target, X2, Y2);
Y2:=Y2-10;
end;
if GetPlayerStat(sentry[SID].botID, 'direction') = '>' then X:=X+4 else X:=X-4;
case sentry[SID].style of
1: if GetTickCount-sentry[SID].last_fire >= gInt then
begin //MINIGUN
CreateBullet(X, Y-10-gInt, 0, 0, 2, 14, sgBullID);
Shoot(X,Y,X2,Y2,gAccuracy, 0, gSpeed+Random(1,4),gPower,1,1,ID);
Shoot(X,Y,X2,Y2 ,gAccuracy, 0, gSpeed-Random(1,4),gPower,1,1,ID);
end;
2: if GetTickCount-sentry[SID].last_fire >= hgInt then
begin //HMG
CreateBullet(X, Y-10-hgInt, 0, 0, 2, 14, sgBullID);
Shoot(X,Y,X2,Y2,hgAccuracy,0,hgSpeed-Random(1,5),hgPower,1,1,ID);
end;
3: if GetTickCount-sentry[SID].last_fire >= fcInt then
begin //FLAK
CreateBullet(X, Y-10-fcInt, 0, -0.4-Random(0,3)/3, 2, 14, sgBullID);
rand:=Random(fcDivergence div 2,fcDivergence)/100;
Shoot(X,Y,X2,Y2,0,rand, fcSpeed,fcPower*0.5,1,10,ID);
Shoot(X,Y,X2,Y2,0,rand, fcSpeed,fcPower ,1,14,ID);
end;
4: if GetTickCount-sentry[SID].last_fire >= sgInt then
begin //SHOTGUN
CreateBullet(X, Y-10-sgInt, 0, -0.4, 2, 14, sgBullID);
Shoot(X,Y,X2,Y2 ,sgSpread, Random(2,6)/1000*sgSpread, sgSpeed+1, sgPower, sgPellets div 4, 3, ID);
Shoot(X,Y,X2,Y2,sgSpread, Random(2,4)/1000*sgSpread, sgSpeed-2, sgPower, sgPellets div 4, 3, ID);
Shoot(X,Y,X2,Y2 ,sgSpread, Random(2,6)/1000*sgSpread, sgSpeed+2, sgPower, sgPellets div 4, 3, ID);
Shoot(X,Y,X2,Y2,sgSpread, Random(2,7)/1000*sgSpread, sgSpeed-1, sgPower, sgPellets div 4, 3, ID);
Shoot(X,Y,X2,Y2 ,sgSpread, Random(3,6)/1000*sgSpread, sgSpeed, sgPower, sgPellets mod 4, 3, ID);
end;
5: if missile_reload > 0 then missile_reload:=missile_reload-1 else
begin
ThreadFunc([sentry[SID].owner, sentry[SID].target, X, Y], 'Missile');
missile_reload:=5;
end;
end;
sentry[SID].last_fire:=GetTickCount;
sentry[SID].ammo:=sentry[SID].ammo-1;
end;
end;
function OnPlayerDamage(Victim, Shooter: byte; Damage: integer): integer;
begin
if player[Victim].is_sentry then
begin
if shooter = sgBullID then
if sentry[player[Victim].sentry_ID].target > 0 then
ProcessSentry(Victim, player[Victim].sentry_ID);
Result:=-999999;
end else Result:=Damage;
end;
function lookForTarget(SentryID,SentryOwner: byte; X,Y,MaxDistance: integer; UsingRaycast: boolean): byte; {SentryID - ID of sentry (1..5), not of Dummy}
var
i, t: byte;
X2,Y2,sqrdist,maxdist: single;
begin
maxdist:=MaxDistance*MaxDistance;
Result:=0;
t := GetPlayerStat(SentryOwner, 'Team');
for i:=1 to MAX_PLAYERS do
if GetPlayerStat(i, 'Active') then
if (i <> SentryID) and (i <> SentryOwner) then
if GetPlayerStat(i, 'Alive')=true then
if ((not player[i].is_sentry) and (t <> GetPlayerStat(i, 'Team'))) or (t = 0) then
begin
GetPlayerXY(i,X2,Y2);
if UsingRayCast then
if not RayCast(X,Y-7,X2,Y2-7,sqrdist,MaxDistance+1) then continue;
X2:=X2-X;
Y2:=Y2-Y;
sqrdist:=X2*X2+Y2*Y2;
if sqrdist < maxdist then
begin
Result:=i;
maxdist:=sqrdist;
end;
end;
end;
procedure AppOnIdle(Ticks: integer);
var
i: byte;
begin
if (paused) or (disabled) then exit;
for i:=1 to 5 do
begin
if sentry[i].duration = 0 then continue else
begin
sentry[i].duration:=sentry[i].duration - 1;
if sentry[i].ammo > 0 then
begin
sentry[i].target:=lookForTarget(sentry[i].botID, sentry[i].owner, GetPlayerStat(sentry[i].botID, 'X'), GetPlayerStat(sentry[i].botID, 'Y'), 800, true); //find a target
if sentry[i].target > 0 then
if GetTickCount - sentry[i].last_fire >= 45 then
// ProcessSentry(sentry[i].botID, i);
DoDamageBy(sentry[i].botID, sgBullID, 3);
end else
sentry[i].duration:=0;
if sentry[i].duration = 0 then RemoveSentry(i, false, true);
end;
end;
end;
procedure OnPlayerKill(Killer, Victim: byte; Weapon: string);
begin
if player[Killer].is_sentry then
if sentry[player[killer].sentry_ID].target > 0 then
sentry[player[killer].sentry_ID].target:=0//lookForTarget(Killer, sentry[player[killer].sentry_ID].owner, GetPlayerStat(Killer, 'X'), GetPlayerStat(Killer, 'Y'),700,true);
end;
function OnCommand(ID: Byte; Text: string): boolean;
var i: byte; x,y,rd:single; facing: integer;
begin
case lowercase(Text) of
'/delsgun', '/dsg':
for i:=1 to 5 do
if sentry[i].duration > 0 then
if Distance(GetPlayerStat(ID, 'X'), GetPlayerStat(ID, 'Y'), GetPlayerStat(sentry[i].botID, 'X'), GetPlayerStat(sentry[i].botID, 'Y')) < 50 then
RemoveSentry(i, false, true);
'/switch':disabled:=not disabled;
'/swt':sentry[1].owner:=3;
'/mss':missile(2, id, GetPlayerStat(2, 'X'), GetPlayerStat(2, 'Y'));
'/nova':nova(GetPlayerStat(ID, 'X'), GetPlayerStat(ID, 'Y'), 0, 0,35,-15,60,100,14,ID);
else begin
if MaskCheck(Text, '/sgun *') then
if (GetPiece(Text, ' ', 1) <> nil) and (StrToInt(GetPiece(Text, ' ', 1)) <= 5) then PlaceSentry(ID,StrToInt(GetPiece(Text, ' ', 1)),GetPlayerStat(ID, 'X'),GetPlayerStat(ID, 'Y'),true);
if MaskCheck(Text, '/esgun *') then
if (GetPiece(Text, ' ', 1) <> nil) and (StrToInt(GetPiece(Text, ' ', 1)) <= 5) then PlaceSentry(ID+1,StrToInt(GetPiece(Text, ' ', 1)),GetPlayerStat(ID, 'X'),GetPlayerStat(ID, 'Y'),true);
end;
end;
end;
procedure GetBulletID; //finds owner ID for bullets which hurt bots.
var i: byte;
begin
for i:=1 to MAX_PLAYERS do
if GetPlayerStat(i, 'Active') then
if GetPlayerStat(i, 'Team') <> SENTRY_TEAM then
begin
sgBullID:=i;
exit;
end;
end;
procedure OnJoinGame(ID, Team: byte);
begin
GetBulletID;
end;
procedure OnJoinTeam(ID, Team: byte);
begin
GetBulletID;
end;
procedure OnLeaveGame(ID, Team: byte; Kicked: boolean);
var i: byte;
begin
if not player[ID].is_sentry then
begin
for i:=1 to 5 do
if sentry[i].owner = ID then
RemoveSentry(i, false, false);
GetBulletID;
end;
end;
procedure ActivateServer();
var i: byte;
begin
GetBulletID;
for i:=1 to MAX_PLAYERS do
if IDToName(i) = 'Dummy' then kickplayer(i);
end;
procedure OnMapChange(NewMap: String);
var i: byte;
begin
GetBulletID;
for i:=1 to 5 do
if sentry[i].botID <> 0 then
RemoveSentry(i, false, false);
end;
100% sure.Change its name to Dummy in the actual file as well.
I made a .txt file and named it Dummy.bot and put it in bots.
Doesn't matter(except that it won't be a dummy...). String in /addbot is file name.100% sure.Change its name to Dummy in the actual file as well.
I made a .txt file and named it Dummy.bot and put it in bots.