Attack Script: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
(3 intermediate revisions by 2 users not shown) | |||
Line 2: | Line 2: | ||
<big> | <big> | ||
== Introduction == | == Introduction == | ||
This is a server along with necessary npcscripts and plugins. This is the script used for Public Test [https://youtu.be/bs1axQpQY0A (Video)](Thanks Sebastian) of a recent version. | This is a server along with necessary npcscripts and plugins. This is the script used for Public Test [https://youtu.be/bs1axQpQY0A (Video)](Thanks Sebastian) of a recent version. The npcclient version is 1.5 patch1. The later versions 1.5 patch2, 1.6 are incompatible with this script.(ConnectNPC, ConnectNPCEx functions parameters changed) | ||
==Download Links== | ==Download Links== | ||
Server with all necessary scripts, plugins and npc program and directories. | |||
{| | {| | ||
|- | |- | ||
Line 13: | Line 14: | ||
|} | |} | ||
==The npc-Script== | ==The npc-Script== | ||
attack_script.nut | File: npcscripts/attack_script.nut | ||
<source lang="lua"> | <source lang="lua"> | ||
enum CONSTANTS{ | enum CONSTANTS{ | ||
Line 516: | Line 517: | ||
} | } | ||
</source> | </source> | ||
weapons.nut | File: npcscripts/weapons.nut | ||
<source lang="lua"> | <source lang="lua"> | ||
class WEAPON | class WEAPON |
Latest revision as of 14:37, 22 January 2023
Introduction
This is a server along with necessary npcscripts and plugins. This is the script used for Public Test (Video)(Thanks Sebastian) of a recent version. The npcclient version is 1.5 patch1. The later versions 1.5 patch2, 1.6 are incompatible with this script.(ConnectNPC, ConnectNPCEx functions parameters changed)
Download Links
Server with all necessary scripts, plugins and npc program and directories.
Linux x64 | [Zip] | |
Windows x32 | [Zip] | [Zip-Link2] |
The npc-Script
File: npcscripts/attack_script.nut
enum CONSTANTS{ SHOOT_INTERVAL = 60, //MY_WEAPON = 27, //we request to server for this weapon by command /givemeweapon 27 IS_FIRST_PERSON = 0, //0 or 1 FIRING_RANGE = 60, //If target player within this range, it will shoot! INVINCIBLE = 0, //responds to bullets by dec of health FIGHTBACK = 1 //If a player shoot, shoothim back } enum SERVER{ ALLOCATE_TARGET=0x0a0a0a, //rgb=10 10 10 //Tell a target ( player) so it can attack DEALLOCATE_TARGET=0x0b0b0b, //Tell to stop attacking a target (player) COMPILE_SCRIPT=0x0c0c0c, //Pass a string and program will compile it. If it contains functions, it will be called from the program SHOT_BY_WEAPON = 0x0d0d0d, //Server tells using client data that npc has been shot. So decrease health! PROCESS_LINE_OF_SIGHT = 0x0e0e0e, //Unable to know whether player has shot npc. So asking server to raytrace in a client computer NPC_COMMUNICATION = 0x0f0f0f, //This is meant to be a communication between npcs. AI. CALL_REMOTE_FUNCTION = 0x1a1a1a //What is this? } dofile("npcscripts/weapons.nut"); //myTarget<- null; //The ID of the target player Enemies<-[]; //An array containing current weapon details so that a timer can be used to firing it taking into //account its clipsize, reloading time etc. Highly developed.. class WEPDATA { weaponid = 0; range = 2.4; firingrate = 250; reloadingtime = 400; //ms clipsize = 1000; lastfired = 0.0; isreloading = false; shotsfired = 0;// used for calculating reloading time constructor( weaponid, range, clipsize, reloadingtime, firingrate ) { this.weaponid = weaponid; this.range= range; this.firingrate=firingrate; this.reloadingtime=reloadingtime; this.clipsize=clipsize; } }; //Below is a class. myWeapon <- null; //Below is an integer PrimaryWeapon <- 0; //Initialize timer function OnNPCScriptLoad(params) { timer<- null; if(params.len()>0 && params[0]=="Sniper") PrimaryWeapon = 29; else PrimaryWeapon = 27; } //Grab npc ID as a player function OnNPCConnect(myplayerid) { npcid<-myplayerid; } function OnNPCSpawn() { //SendCommand("givemeweapon "+CONSTANTS.MY_WEAPON);// command /givemeweapon 27 if(!CONSTANTS.INVINCIBLE) SendCommand("SYNCSHOTS"); } //When an npc is shot down, that is the end of the script. In next version it may be implemented to spawn //them again. Pretty simple though. function OnPlayerDeath(playerid) { if( playerid == npcid ) { if(timer) { KillTimer( timer ); timer = null; } } } //Shoot at a point. Most important function function ShootAt(tPos, isReloading = false, isHeadShot=false) { if(isHeadShot)tPos.z+=0.627299; local Pos= GetMyPos();//print(GetPlayerArmedWeapon(npcid)); local angle= atan2(-(tPos.x-Pos.x), tPos.y-Pos.y); /* This will always work*/ local aimPos= Vector(tPos.x,tPos.y,tPos.z); local aimDir = Vector( PI, PI, -angle ); //local aimPos= Pos; //local aimDir= GetAimDir( aimPos, tPos ); local keys= KEY_ONFOOT_FIRE + CONSTANTS.IS_FIRST_PERSON ; SetLocalValue(I_KEYS, keys ); local ammo = GetLocalValue(I_CURWEP_AMMO ); SendOnFootSyncData( keys, Pos.x,Pos.y, Pos.z, angle, GetPlayerHealth( npcid ), GetPlayerArmour( npcid ), GetPlayerArmedWeapon( npcid ),ammo, 0.0, 0.0, 0.0, aimPos.x, aimPos.y, aimPos.z, PI, PI, -angle, false, isReloading ); } //Sniper Rifle function SnipeAt(tPos, isReloading=false, isHeadShot=false) { if(isHeadShot)tPos.z+=0.627299; local Pos= GetMyPos(); local aimPos = Vector( Pos.x, Pos.y, Pos.z-0.2); local angle= atan2(-(tPos.x-aimPos.x), tPos.y-aimPos.y); local alpha = atan2( tPos.z - aimPos.z, sqrt( pow( tPos.y - aimPos.y, 2 ) + pow( tPos.x - aimPos.x , 2 ) ) ); local dx = cos(alpha) * sin(-angle); local dy = cos(alpha) * cos(-angle); local dz = sin(alpha); local keys= 577 ; local ammo = GetLocalValue(I_CURWEP_AMMO ); aimPos+=Vector( dx, dy, dz); SendOnFootSyncData( keys, Pos.x,Pos.y, Pos.z, angle, GetPlayerHealth( npcid ), GetPlayerArmour( npcid ), GetPlayerArmedWeapon( npcid ),ammo, 0.0, 0.0, 0.0, aimPos.x, aimPos.y, aimPos.z, dx, dy, dz, false, isReloading ); SetTimerEx("FireSniperRifle", 60, 1, GetPlayerArmedWeapon(npcid), Pos.x, Pos.y, Pos.z, 16.0*dx, 16.0*dy, 16.0*dz ); } function DoMeleeAttack( pid ) { local ppos = GetPlayerPos( pid ); local mpos = GetMyPos( ); local angle = atan2( - (ppos.x- mpos.x), ppos.y-mpos.y); SetLocalValue( F_ANGLE , angle ); SetLocalValue( I_KEYS, 576 ); SendOnFootSyncDataLV(); } function AttackPrimaryTarget() { /*if(myTarget==null) return; local pid = myTarget;*/ if( Enemies.len() == 0 ) return; local pid = Enemies[0]; //Primary Target at position Zero if(IsPlayerStreamedIn(pid) && GetPlayerState(pid)!=PLAYER_STATE_WASTED) { local pos = GetPlayerPos(pid); if(GetDistanceFromMeToPoint(pos) < myWeapon.range ) { if( myWeapon.weaponid <= 11 ) { DoMeleeAttack( pid ); } else if( myWeapon.weaponid>=17 && myWeapon.weaponid<= 29 ) { if( ! myWeapon.isreloading ) { local t=GetTickCount(); if( (t - myWeapon.lastfired) >= ( myWeapon.firingrate) ) //time comparison in milliseconds { SetLocalValue(I_CURWEP_AMMO, GetLocalValue(I_CURWEP_AMMO)-1 > 0?GetLocalValue(I_CURWEP_AMMO)-1 :1); if(myWeapon.weaponid<=27) ShootAt( pos ); else SnipeAt( pos, false, true ); myWeapon.shotsfired++; if(myWeapon.shotsfired % myWeapon.clipsize == 0 ) myWeapon.isreloading=true; myWeapon.lastfired = GetTickCount(); }else { //Send a packet, same as last one. if(myWeapon.weaponid<= 27) SendOnFootSyncDataLV(); } }else { //Weapon is reloading if( (GetTickCount() - myWeapon.lastfired) >= (myWeapon.reloadingtime) ) { //reloading done ! myWeapon.isreloading=false; SetLocalValue(I_CURWEP_AMMO, GetLocalValue(I_CURWEP_AMMO)-1 > 0?GetLocalValue(I_CURWEP_AMMO)-1 :1); if(myWeapon.weaponid<=27) ShootAt( pos ); else SnipeAt( pos, false, true ); myWeapon.shotsfired++; if( (myWeapon.shotsfired % myWeapon.clipsize) == 0 ) myWeapon.isreloading=true; }else { //still reloading... if(myWeapon.weaponid<= 27) ShootAt( pos, true ); } } } }else { SetLocalValue(I_KEYS, 0 ); //Face NPC towards player if near if( GetDistanceFromMeToPoint( pos ) < 30 ) { local turnhead = WhereIsPlayer( pid ); if( abs( turnhead ) > 0.1 ) SetLocalValue( F_ANGLE, atan2(-(pos.x-GetMyPosX()), pos.y-GetMyPosY()) ); } SendOnFootSyncDataLV(); } } } function AddEnemy( pid ) { if(Enemies.find( pid ) == null ) Enemies.push( pid ); } function SetTargetPlayerForShooting(pid, weaponid=-1) { weaponid= weaponid==-1?PrimaryWeapon:weaponid; if( Enemies.find( pid ) != null ) { //If it is at index 0? Enemies.remove( Enemies.find( pid ) ); Enemies.insert( 0, pid ); }else Enemies.insert(0, pid ); //Set as primary target. (index 0) local wid = GetPlayerSlotWeapon( npcid, GetSlotFromWeaponId(weaponid) ); local s = SetLocalValue(I_CURWEP, wid );//s=true means server given that weapon already if(!s)return ; if( wid != 0 ) { local range = Weapon[wid].range; local clipsize = Weapon[wid].clipsize; //30 local reloadingtime = Weapon[wid].reload; //1000 ms local firingrate = Weapon[wid].firingrate; //150 ms myWeapon = WEPDATA( wid, range, clipsize, reloadingtime, firingrate ) }else myWeapon = WEPDATA( 0, 2.4, 250, 400, 1000 ); if(!timer) { timer = SetTimerEx( "AttackPrimaryTarget", 60, 0 ); print(format("Weapon: %d, Range: %0.1f, Clipsize: %d, reloadingtime: %d, firingrate: %d \n", wid, myWeapon.range, myWeapon.clipsize, myWeapon.reloadingtime, myWeapon.firingrate) ); } } function UnsetTarget() { //myTarget = null; KillTimer( timer ); timer = null; return true; } function ToInteger(s) { try{return s.tointeger();}catch(e){return null;} } function OnClientMessage(r,g,b,message) { local hex = ( r << 16 ) + ( g << 8 ) + b; switch(hex) { case SERVER.ALLOCATE_TARGET: local pid = ToInteger(message); if( pid!=null && IsPlayerConnected( pid )) { SetTargetPlayerForShooting( pid ); } break; case SERVER.DEALLOCATE_TARGET: local pid = ToInteger(message); if( pid!=null && IsPlayerConnected( pid )) { if( Enemies.find( pid ) != null ) Enemies.remove( Enemies.find( pid ) ); } break; case SERVER.SHOT_BY_WEAPON://ClientMessage("pid damage bodypart boolheadshot",r,g,b); //If headshot, it assumes npc is shot down by ruger or etc.( and not with colt 75) //print("data arrived\n"); local idx= [0]; local plrid = strtok( message, idx ); local weapon = strtok( message, idx ); local damage = strtok( message, idx ); local bodypart = strtok( message, idx ); try { plrid = plrid.tointeger(); bodypart = bodypart.tointeger() ; damage = damage.tointeger() ; weapon = weapon.tointeger() ; }catch(e){ break; } PlayerAttackedNPC( plrid, bodypart, damage, weapon); break; case SERVER.COMPILE_SCRIPT: try { local script = compilestring(message ); script(); }catch(e) { print(e); } break; case SERVER.NPC_COMMUNICATION: { local idx=[0]; local cmd = strtok( message, idx ); switch( cmd ) { case "ATTACKED" : { local npcid = strtok( message, idx ); local plrid = strtok( message, idx ); //if(myTarget==null) try{ plrid = plrid.tointeger(); }catch(e){ return;} if(Enemies.len()==0) { if(IsPlayerConnected( plrid )) { SetTargetPlayerForShooting( plrid ); } }else if( Enemies.find( plrid ) == null ) { //Enemy of another npc is still enemey..right? Enemies.push( plrid ); } } break; } } break; case SERVER.CALL_REMOTE_FUNCTION: { local idx=[0]; local funcname = strtok( message, idx ); local f = strtok( message, idx ); local params=[]; //empty array for passing arguments if( funcname!="" ) { try { for(local i=0; i < f.len(); i++ ) { local parameter = strtok( message, idx ); if( parameter=="" && f[i]!='s')break; switch( f[i] ) { case 'f': params.push( parameter.tofloat() ); break; case 'i': params.push( parameter.tointeger() ); break; case 's': params.push( parameter ); break; default: return; } } }catch(e) { print(e); } if( rawin( funcname ) ) { local functionObj = rawget( funcname ); params.insert(0, this); functionObj.acall(params ); } } } break; default: break; } } function PlayerAttackedNPC(plrid, bodypart, damage, weapon) { local health= GetPlayerHealth(npcid); local armour= GetPlayerArmour(npcid); if(armour>0) armour-=damage; else health-=damage; if(armour< 0) { health+=armour; armour=0; } if( health <= 0 || damage == 255 ) { local anim; switch( bodypart ) { case BODYPART_BODY: anim = 0xd; break; case BODYPART_HEAD: anim = 17; break; case BODYPART_TORSO : anim = 13; break; case BODYPART_LEFTARM : anim = 19; break; case BODYPART_RIGHTARM : anim = 20; break; case BODYPART_LEFTLEG: anim = 21; break; case BODYPART_RIGHTLEG : anim = 22; break; default: anim = 0xd;break; } //clear targets //myTarget = null; Enemies.clear(); SendShotInfo( bodypart, anim ); SetTimerEx("SendOnFootSyncDataLV", 100, 1); SetTimerEx("SendDeathInfo", 2000, 1, weapon, plrid, bodypart ); }else { SetLocalValue( I_HEALTH, health ); SetLocalValue( I_ARMOUR, armour ); SendOnFootSyncDataLV(); //Small Artificial intelligence if( CONSTANTS.FIGHTBACK && Enemies.len()==0 ) { if( weapon<= 11 ) { local wep = GetPlayerSlotWeapon( npcid, 1 ); if(wep == 0 )wep= GetPlayerSlotWeapon( npcid, 0 );//Brass knuckes available?? SetTargetPlayerForShooting( plrid, wep ); }else { SetTargetPlayerForShooting( plrid ); SendCommand("NPC_COMMU ATTACKED "+npcid+" "+ plrid ); } } } } function OnSniperRifleFired( playerid, weaponid, x, y, z, dx, dy, dz ) { local outputstr=format("Sniper Rifle, x,y,z= %f, %f, %f and dir = ( %f, %f, %f )\n", x,y,z, dx/16, dy/16, dz/16); local command= format("PLOS %d %.4f %.4f %.4f %.4f %.4f %.4f %d %d", playerid, x, y, z, dx/16, dy/16, dz/16, 2, weaponid ); SendCommand( command ); } //Attack every player coming into that area. function OnPlayerStreamIn(playerid) { if( GetPlayerName(playerid).len()!=2 ) { if(GetPlayerState(npcid) != PLAYER_STATE_WASTED ) { if( Enemies.len() == 0 ) SetTargetPlayerForShooting( playerid ); else AddEnemy( playerid ); } } } function OnPlayerUpdate( playerid, updateType ) { if(updateType == PLAYERUPDATE_NORMAL || updateType == PLAYERUPDATE_AIMING) { if( (GetPlayerKeys(playerid) & 576)== 576 ) //On server and player on same pc, health may be reduced before hit { local mypos = GetMyPos(); local plrangle = GetPlayerFacingAngle( playerid ); local plrpos = GetPlayerPos( playerid ); local _angle = atan2( -(mypos.x - plrpos.x ), mypos.y - plrpos.y ); if( _angle < 0 && plrangle > 0 )_angle+=2*PI; else if( plrangle <0 && _angle > 0 )_angle-=2*PI; if( abs( _angle - plrangle ) < PI/2 ) //take PI/2. 0 means straight to npc { //player is facing npc local weapon = GetPlayerArmedWeapon( playerid ); if( weapon >=0 && weapon <= 11 ) { local range = Weapon[ weapon ].range ; if( GetDistanceFromMeToPoint( plrpos ) <= range ) { //player is in range of weapon local damage = Weapon[ weapon ].damage /5 ; //many packets arrive. so damage must be controlled PlayerAttackedNPC(playerid, 0, damage, weapon); } } } } } } function strtok(string,array) { local index=array[0]; local length=string.len(); /* Skip the leading white space */ while(index<length && string[index]<=' ') index++; local result=""; local offset = index; while( index < length && string[index] > ' ' && index-offset < 20-1) { result+=string.slice(index,index+1); index++; } array[0]=index; return result; }
File: npcscripts/weapons.nut
class WEAPON { range=80; firingrate=250; //interval ms reload=500; //ms clipsize=30; damage=25; constructor( range, firingrate, reload, clipsize, damage) { this.range= range; this.firingrate=firingrate; this.reload=reload; this.clipsize=clipsize; this.damage=damage; } }; Weapon<-array( 34 ); //minigun id is 33. plus 1 for weapon 0 Weapon[0] = WEAPON(2.4,250, 100, 1000, 8); Weapon[1] = WEAPON(2.0,450, 100, 1000, 16); Weapon[2] = WEAPON(1.8,250, 100, 1000, 45); Weapon[3] = WEAPON(1.5,450, 100, 1000, 21); Weapon[4] = WEAPON(1.5,450, 100, 1000, 21); Weapon[5] = WEAPON(1.8,250, 100, 1000, 21); Weapon[6] = WEAPON(2.0,450, 100, 1000, 21); Weapon[7] = WEAPON(1.5,450, 100, 1000, 21); Weapon[8] = WEAPON(1.9,250, 100, 1000, 24); Weapon[9] = WEAPON(2.0,250, 100, 1000, 24); Weapon[10] = WEAPON(2.1,250, 100, 1000, 30); Weapon[11] = WEAPON(1.7,900, 100, 1000, 35); Weapon[12] = WEAPON(30.0,100, 1, 1, 75); Weapon[13] = WEAPON(30.0,100, 1, 1, 75); Weapon[14] = WEAPON(30.0,100, 1, 1, 75); Weapon[15] = WEAPON(25.0,100, 1, 1, 75); Weapon[16] = WEAPON(30.0,100, 1, 1, 75); Weapon[17] = WEAPON(30.0,210, 450, 17, 25); Weapon[18] = WEAPON(30.0,630, 1000, 6, 135); Weapon[19] = WEAPON(20.0,250, 450, 1, 80); Weapon[20] = WEAPON(15.0,250, 750, 7, 100); Weapon[21] = WEAPON(10.0,250, 250, 1, 120); Weapon[22] = WEAPON(30.0,119, 500, 50, 20); Weapon[23] = WEAPON(45.0,59, 500, 30, 20); Weapon[24] = WEAPON(30.0,60, 500, 30, 15); Weapon[25] = WEAPON(45.0,90, 500, 30, 35); Weapon[26] = WEAPON(90.0,90, 1000, 30, 40); Weapon[27] = WEAPON(90.0,150, 1000, 30, 35); Weapon[28] = WEAPON(100.0,89, 1401, 1, 125); Weapon[29] = WEAPON(100.0,180, 1401, 7, 125); Weapon[30] = WEAPON(55.0,100, 1200, 1, 75); Weapon[31] = WEAPON(5.1,100, 100, 500, 25); Weapon[32] = WEAPON(75.0,119, 500, 100, 130); Weapon[33] = WEAPON(75.0,30, 350, 500, 140); /* Generated from server side code function makecode() { for(local i=0; i< 34; i++) { local string=format("Weapon[%d] = WEAPON(%0.1f,%d, %d, %d, %d);", i, GetWeaponDataValue( i, 2 ), GetWeaponDataValue( i, 3 ), GetWeaponDataValue( i, 4 ), GetWeaponDataValue( i, 5 ), GetWeaponDataValue( i, 6 ) ); print(string); } } */