namespace CustomTank{enum TANKSF{ SF_TANK_ACTIVE=0x0001, SF_TANK_PLAYER=0x0002, SF_TANK_HUMANS=0x0004, SF_TANK_ALIENS=0x0008, SF_TANK_LINEOFSIGHT=0x0010, SF_TANK_CANCONTROL=0x0020, SF_TANK_SOUNDON=0x8000}enum HIDEHUD{ HIDEHUD_WEAPONS=(1<<0), HIDEHUD_FLASHLIGHT=(1<<1), HIDEHUD_ALL=(1<<2), HIDEHUD_HEALTH=(1<<3),}const arraygTankSpread={ Vector(0,0,0), Vector(0.025,0.025,0.025), Vector(0.05,0.05,0.05), Vector(0.1,0.1,0.1), Vector(0.25,0.25,0.25), };abstract class CFuncTank : ScriptBaseMonsterEntity{ EHandle m_pController; EHandle m_pControlEntity; float m_flNextAttack; Vector m_vecControllerUsePos; float m_yawCenter; float m_yawRate; float m_yawRange; float m_yawTolerance; float m_pitchCenter; float m_pitchRate; float m_pitchRange; float m_pitchTolerance; float m_fireLast; float m_fireRate; float m_lastSightTime; float m_persist; float m_minRange; float m_maxRange; Vector m_barrelPos; float m_spriteScale; string m_iszSpriteSmoke; string m_iszSpriteFlash; string m_iszRotateSound; int m_bulletType; int m_iBulletDamage; Vector m_sightOrigin; int m_spread; int m_classify; string m_iszMaster; Vector UpdateTargetPosition(CBaseEntity@ pTarget) { return pTarget.BodyTarget(pev.origin); } int ObjectCaps() { return BaseClass.ObjectCaps()&~FCAP_ACROSS_TRANSITION; } int Classify() { if(m_pController.IsValid()) return m_pController.GetEntity().Classify(); return m_classify; } bool IsActive() { return(pev.spawnflags&SF_TANK_ACTIVE)!=0; } void TankActivate() { pev.spawnflags|=SF_TANK_ACTIVE; pev.nextthink=pev.ltime+0.1; m_fireLast=0; } void TankDeactivate() { pev.spawnflags&=~SF_TANK_ACTIVE; m_fireLast=0; StopRotSound(); } bool CanFire() { return(g_Engine.time-m_lastSightTime)int(gTankSpread.length())) m_spread=0; pev.oldorigin=pev.origin; } bool KeyValue(const string&in szKey,const string&in szValue) { if(szKey=="yawrate") m_yawRate=atof(szValue); else if(szKey=="yawrange") m_yawRange=atof(szValue); else if(szKey=="yawtolerance") m_yawTolerance=atof(szValue); else if(szKey=="pitchrange") m_pitchRange=atof(szValue); else if(szKey=="pitchrate") m_pitchRate=atof(szValue); else if(szKey=="pitchtolerance") m_pitchTolerance=atof(szValue); else if(szKey=="firerate") m_fireRate=atof(szValue); else if(szKey=="barrel") m_barrelPos.x=atof(szValue); else if(szKey=="barrely") m_barrelPos.y=atof(szValue); else if(szKey=="barrelz") m_barrelPos.z=atof(szValue); else if(szKey=="spritescale") m_spriteScale=atof(szValue); else if(szKey=="spritesmoke") m_iszSpriteSmoke=szValue; else if(szKey=="spriteflash") m_iszSpriteFlash=szValue; else if(szKey=="rotatesound") m_iszRotateSound=szValue; else if(szKey=="persistence") m_persist=atof(szValue); else if(szKey=="bullet") m_bulletType=atoi(szValue); else if( szKey=="bullet_damage") m_iBulletDamage=atoi(szValue); else if(szKey=="firespread") m_spread=atoi(szValue); else if(szKey=="minRange") m_minRange=atof(szValue); else if(szKey=="maxRange") m_maxRange=atof(szValue); else if(szKey=="master") m_iszMaster=szValue; else if(szKey== "classify") m_classify=atoi(szValue); else return BaseClass.KeyValue(szKey,szValue); return true; } bool StartControl(CBasePlayer@ pController) { if(m_pController.IsValid()) return false; if(m_iszMaster!=""&&!g_EntityFuncs.IsMasterTriggered(m_iszMaster,pController)) return false; @self.pev.owner=pController.edict(); CBaseEntity@ pControllEntity=g_EntityFuncs.FindEntityByString(pControllEntity,"target",self.pev.targetname); m_pControlEntity=EHandle(pControllEntity); m_pController=EHandle(pController); if(pController.m_hActiveItem.IsValid()) { cast(pController.m_hActiveItem.GetEntity()).Holster(); pController.pev.weaponmodel=0; pController.pev.viewmodel=0; pController.m_flNextAttack=g_Engine.time+9999; } pController.m_iHideHUD|=HIDEHUD_WEAPONS; m_vecControllerUsePos=pController.pev.origin; pev.nextthink=pev.ltime+0.1; return true; } void StopControl() { if(!m_pController.IsValid()) return; CBasePlayer@ pPlayer=cast(m_pController.GetEntity()); if(pPlayer.m_hActiveItem.IsValid()) cast(pPlayer.m_hActiveItem.GetEntity()).Deploy(); @self.pev.owner=null; pPlayer.m_iHideHUD&=~HIDEHUD_WEAPONS; pPlayer.m_flNextAttack=0; pev.nextthink=0; m_pController=EHandle(null); m_pControlEntity=EHandle(null); if(IsActive()) pev.nextthink=pev.ltime+1.0; } bool IsInControllerEntity(CBaseEntity@ pPlayer) { CBaseEntity@ pEntity=m_pControlEntity.GetEntity(); CBaseEntity@ pA=null; CBaseEntity@ pB=null; if(pPlayer.pev.size.Length()>pEntity.pev.size.Length()){ @pA=pEntity; @pB=pPlayer; } else{ @pA=pPlayer; @pB=pEntity; } if(pA.pev.absmin.x>pB.pev.absmax.x) return false; else if(pA.pev.absmax.xpB.pev.absmax.y) return false; else if(pA.pev.absmax.ypB.pev.absmax.z) return false; else if(pA.pev.absmax.z(m_pController.GetEntity()); if(pController.pev.button&IN_ATTACK!=0) { m_fireLast=g_Engine.time-(1/m_fireRate)-0.01; Math.MakeVectors(pev.angles); Fire(BarrelPosition(),g_Engine.v_forward,pController.pev); if(pController!is null&&pController.IsPlayer()) pController.m_iWeaponVolume=LOUD_GUN_VOLUME; pController.m_flNextAttack=g_Engine.time+9999; m_flNextAttack=g_Engine.time+(1/m_fireRate); } } void Use(CBaseEntity@ pActivator,CBaseEntity@ pCaller,USE_TYPE useType,float value) { if(pev.spawnflags&SF_TANK_CANCONTROL!=0) { if(!pActivator.IsPlayer()) return; else if(!m_pController.IsValid()&&useType!=USE_OFF) StartControl(cast(pActivator)); else StopControl(); } else { if(!self.ShouldToggle(useType,IsActive())) return; if(IsActive()) TankDeactivate(); else TankActivate(); } } bool InRange(float range) { if(range0&&range>m_maxRange) return false; return true; } void Think() { pev.avelocity=g_vecZero; TrackTarget(); if(fabs(pev.avelocity.x)>1||fabs(pev.avelocity.y)>1) StartRotSound(); else StopRotSound(); } float fabs(float inNum) { return inNum<0?-inNum : inNum; } CBaseEntity@ FindClosestEnemy(string szClassname,float fRadius) { CBaseEntity@ ent=null; CBaseEntity@ enemy=null; float iNearest=fRadius; do { @ent=g_EntityFuncs.FindEntityInSphere(ent,self.pev.origin, fRadius,szClassname,"classname"); if(ent is null||!ent.IsAlive()) continue; if(ent.entindex()==self.entindex()) continue; if(ent.edict()is pev.owner) continue; int rel=self.IRelationship(ent); if(rel==R_AL||rel==R_NO) continue; float iDist=(ent.pev.origin-self.pev.origin).Length(); if(iDist0?m_maxRange : 4096; CBaseEntity@ pEnemy=null; @pEnemy=FindClosestEnemy("player", flSearchRange); if(@pEnemy is null) @pEnemy=FindClosestEnemy("monster_*", flSearchRange); if(@pEnemy is null) { if(IsActive()) pev.nextthink=pev.ltime+2; return; } @pTarget=@pEnemy; barrelEnd=BarrelPosition(); targetPosition=pTarget.pev.origin+pTarget.pev.view_ofs; float range=(targetPosition-barrelEnd).Length(); if(!InRange(range)) return; g_Utility.TraceLine(barrelEnd,targetPosition,dont_ignore_monsters,self.edict(),tr); if(tr.flFraction==1.0) { lineOfSight=true; if(InRange(range)&&pTarget.IsAlive()) { updateTime=true; m_sightOrigin=UpdateTargetPosition(pTarget); } } direction=m_sightOrigin-pev.origin; g_EngineFuncs.VecToAngles(direction,angles); angles=AdjustAnglesForBarrel(angles,direction.Length()); } angles.x=-angles.x; angles.y=m_yawCenter+Math.AngleDistance(angles.y,m_yawCenter); angles.x=m_pitchCenter+Math.AngleDistance(angles.x,m_pitchCenter); if(angles.y>m_yawCenter+m_yawRange) { angles.y=m_yawCenter+m_yawRange; updateTime=false; } else if(angles.y<(m_yawCenter-m_yawRange)) { angles.y=(m_yawCenter-m_yawRange); updateTime=false; } if(updateTime) m_lastSightTime=g_Engine.time; float distY=Math.AngleDistance(angles.y,pev.angles.y); pev.avelocity.y=distY*10; if(pev.avelocity.y>m_yawRate) pev.avelocity.y=m_yawRate; else if(pev.avelocity.y<-m_yawRate) pev.avelocity.y=-m_yawRate; if(angles.x>m_pitchCenter+m_pitchRange) angles.x=m_pitchCenter+m_pitchRange; else if(angles.xm_pitchRate) pev.avelocity.x=m_pitchRate; else if(pev.avelocity.x<-m_pitchRate) pev.avelocity.x=-m_pitchRate; if(!m_pController.IsValid()){ if(CanFire()&&((fabs(distX)1); Math.MakeVectors(self.pev.angles); Vector vecDir=vecForward+ x*vecSpread.x*g_Engine.v_right+ y*vecSpread.y*g_Engine.v_up; Vector vecEnd=vecStart+vecDir*4096; g_Utility.TraceLine(vecStart,vecEnd,dont_ignore_monsters,self.edict(),tr); } void StartRotSound() { if(m_iszRotateSound==""||(pev.spawnflags&SF_TANK_SOUNDON)!=0) return; pev.spawnflags|=SF_TANK_SOUNDON; g_SoundSystem.EmitSound(self.edict(),CHAN_STATIC,string(m_iszRotateSound),0.85,ATTN_NORM); } void StopRotSound() { if(pev.spawnflags&SF_TANK_SOUNDON!=0&&m_iszRotateSound!="") g_SoundSystem.StopSound(self.edict(),CHAN_STATIC,string(m_iszRotateSound)); pev.spawnflags&=~SF_TANK_SOUNDON; }}class CFuncTankAthena : CFuncTank{ CBeam@ m_pLaser; float m_laserTime; CBaseEntity@ pRocket; void Fire(const Vector barrelEnd,const Vector forward,entvars_t@ pevAttacker) { if(m_fireLast!=0) { Math.MakeAimVectors(pev.angles); int bulletCount=int((g_Engine.time-m_fireLast)*m_fireRate); if(bulletCount>0) { if(@m_pLaser!is null) g_EntityFuncs.Remove(m_pLaser); TraceResult tr; TankTrace(barrelEnd,forward,gTankSpread[m_spread],tr); g_Utility.TraceLine(tr.vecEndPos,g_Engine.v_up*8102,dont_ignore_monsters,self.edict(),tr); @pRocket=g_EntityFuncs.ShootMortar(pevAttacker,tr.vecEndPos,Vector(0,0,0)); FireEffect(barrelEnd,forward,pevAttacker); } } else FireEffect(barrelEnd,forward,pevAttacker); }}class CFuncTankGun : CFuncTank{ void Fire(const Vector barrelEnd,const Vector forward,entvars_t@ pevAttacker) { int i; if(m_fireLast!=0) { Math.MakeAimVectors(pev.angles); int bulletCount=int((g_Engine.time-m_fireLast)*m_fireRate); if(bulletCount>0) { for(i=0;i(pentLaser); break; } else @pentLaser=g_EntityFuncs.FindEntityByTargetname(pentLaser,string(pev.message)); } return m_pLaser; } void Think() { if(m_pLaser!is null&&(g_Engine.time>m_laserTime)) m_pLaser.TurnOff(); Think(); } void Fire(const Vector barrelEnd,const Vector forward,entvars_t@ pevAttacker) { int i; TraceResult tr; if(m_fireLast!=0&&GetLaser()!is null) { Math.MakeAimVectors(pev.angles); int bulletCount=int((g_Engine.time-m_fireLast)*m_fireRate); if(bulletCount>0) { for(i=0;i0) { TraceResult tr; Math.MakeAimVectors(pev.angles); TankTrace(barrelEnd,forward,gTankSpread[m_spread],tr); g_EntityFuncs.CreateExplosion(tr.vecEndPos,pev.angles,self.edict(),pev.impulse,true); CFuncTank::Fire(barrelEnd,forward,pev); } } else CFuncTank::Fire(barrelEnd,forward,pev); }}class CFuncTankRocket : CFuncTank{ void Precache() { g_Game.PrecacheOther("rpg_rocket"); CFuncTank::Precache(); } void Fire(const Vector barrelEnd,const Vector forward,entvars_t@ pevAttacker) { if(m_fireLast!=0) { int bulletCount=int((g_Engine.time-m_fireLast)*m_fireRate); if(bulletCount>0) { for(int i=0;i0) { Vector vecVelocity=forward*flSprSpeed; for(int i=0;i