Try this, the new version of the script which works correctly with the new core. It's also faster and should be more stable. I've been too lazy to relase it.
{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;