AddCSLuaFile( "cl_init.lua" ) AddCSLuaFile( "shared.lua" ) include('shared.lua') ENT.Alerted = false ENT.bleeds = 1 ENT.Grenades = 2 ENT.MeleeAttacking = false ENT.StartHealth = 76 ENT.PlayerFriendly = 0 ENT.hurtsound1 = "soviet/hurt1.wav" ENT.hurtsound2 = "soviet/hurt2.wav" ENT.hurtsound3 = "soviet/hurt3.wav" ENT.hurtsound4 = "soviet/hurt4.wav" ENT.alert1 = "soviet/alert1.wav"// ENT.idle1 = "soviet/idle1.wav" ENT.idle2 = "soviet/spreadout.wav" ENT.idle3 = "soviet/areaclear.wav" ENT.idle4 = "soviet/areasecure.wav" ENT.attack1 = "soviet/attack1.wav" ENT.attack2 = "soviet/attack2.wav" ENT.attack3 = "soviet/attack3.wav" ENT.attack4 = "soviet/attack4.wav" ENT.attack5 = "soviet/attack5.wav" ENT.attack6 = "soviet/attack6.wav" ENT.die1 = "soviet/die1.wav" ENT.die2 = "soviet/die2.wav" ENT.die3 = "soviet/die3.wav" ENT.cover = "soviet/cover.wav" ENT.grenade1 = "soviet/grenade1" ENT.grenade2 = "soviet/grenade2" ENT.seen_grenade = true ENT.TakingCover = false ENT.TakenCover = false ENT.CanSeeEnemy = false ENT.TimeToTakeCover = 0 ENT.OutOfAmmo = false ENT.GotACloseOne = false ENT.dead = false ENT.speaktime = 0 function ENT:Initialize() if self:GetActiveWeapon() == nil then self:GetOwner():PrintMessage( HUD_PRINTNOTIFY, "This entity needs a weapon!" ) self:Give("weapon_smg1") end local randommodel = math.random(1,6) self:SetModel( "models/soviet/soviet_soldier"..randommodel..".mdl" ) self:SetHullType( HULL_HUMAN ) self:SetHullSizeNormal(); self:SetSolid( SOLID_BBOX ) self:SetMoveType( MOVETYPE_STEP ) self:CapabilitiesAdd( CAP_MOVE_GROUND | CAP_OPEN_DOORS | CAP_SQUAD | CAP_ANIMATEDFACE | CAP_USE_WEAPONS | CAP_SQUAD | CAP_DUCK | CAP_MOVE_SHOOT | CAP_TURN_HEAD | CAP_USE_SHOT_REGULATOR | CAP_AIM_GUN ) self:SetMaxYawSpeed( 5000 ) self.Friends = {""} self.Scary_Things = { "npc_combinedropship", "npc_combinegunship", "npc_helicopter", "npc_strider", "npc_sniper" } //Sets the entity values self:SetHealth(self.StartHealth) self:SetEnemy(NULL) self:Fire("setsquad","SovietPowerSupreme",0) end function ENT:OnTakeDamage(dmg) if (self.TakingCover == false) then self:SetSchedule(SCHED_SMALL_FLINCH) end self:SpawnBlood(dmg) self:SetHealth(self:Health() - dmg:GetDamage()) //if math.random(4) == 1 then if math.random(4) == 1 then print("Got Hurt!!!") self:StopSpeechSounds() local sound_seed = math.random(1,7) if sound_seed == 1 then self:EmitSound( self.hurtsound1) elseif sound_seed == 2 then self:EmitSound( self.hurtsound2) elseif sound_seed == 3 then self:EmitSound( self.hurtsound3) elseif sound_seed == 4 then self:EmitSound( self.hurtsound4) end //self:SetSchedule(SCHED_ALERT_FACE) end if dmg:GetAttacker():GetClass() != self:GetClass() && math.random(1,7) == 1 then self:ResetEnemy() self:AddEntityRelationship( dmg:GetAttacker(), 1, 10 ) self:SetEnemy(dmg:GetAttacker()) self:CallForHelp() end if (self.TakingCover == false) || self.Alerted == false then self.TakingCover = true print( "Take Cover, they shot me!" ); self:SetSchedule(SCHED_TAKE_COVER_FROM_ENEMY) end self.Alerted = true if self:Health() <= 0 && self.dead == false then //run on death print("DIED!!!") self.dead = true; self:KilledDan() end end function ENT:Think() local function setmeleefalse() self.MeleeAttacking = false end local function Attack_Melee() local entstoattack = ents.FindInSphere(self:GetPos() + self:GetForward()*75,74) if entstoattack != nil then self:EmitSound( "physics/body/body_medium_impact_hard"..math.random(1,6)..".wav", 400, 100) for _,v in pairs(entstoattack) do if ( (v:IsNPC() || ( v:IsPlayer() && v:Alive())) && (v != self) || (v:GetClass() == "prop_physics")) then v:TakeDamage( 12, self ) if v:IsPlayer() then v:ViewPunch(Angle(math.random(-1,1)*10,math.random(-1,1)*10,math.random(-1,1)*10)) end end end else self:EmitSound( "zombie/claw_miss1.wav", 300, 100) //add miss stuff here end timer.Create( "melee_done_timer" .. self.Entity:EntIndex( ), 0.25, 1, setmeleefalse ) end //print(self.TakingCover) if self:Health() > 0 then //print( "Think start" ); //Get all the npc's and other entities. local enttable = ents.FindByClass("npc_*") local monstertable = ents.FindByClass("monster_*") table.Add(monstertable,enttable)//merge //sort through each ent. for _, x in pairs(monstertable) do if (!ents) then print( "No Entities!" ); return end if (x:GetClass() != self:GetClass() && x:GetClass() != "npc_grenade_frag" && x:IsNPC()) then x:AddEntityRelationship( self, 1, 10 ) end end //print( "Think end" ); //self:AddRelationship("player D_HT 10") if self.TakingCover == false then self:GetBoomers()//grenades are top priority. if(math.random(1,20) == 1) then self:FindCloseEnemies()//get guys close to me end end //Hit them. if self:GetEnemy() != nil then if (self:GetEnemy():GetPos():Distance(self:GetPos()) < 70) then if self.MeleeAttacking == false then self:SetSchedule( SCHED_MELEE_ATTACK1 ) timer.Create( "melee_attack_timer" .. self.Entity:EntIndex( ), 0.25, 1, Attack_Melee ) self.MeleeAttacking = true; end else self.MeleeAttacking = false end end end end function ENT:SelectSchedule() if self:Health() > 0 then //makes it never run out of ammo... :D //self:GetActiveWeapon():SetClip1(45) local haslos = self:HasLOS() local distance = 0 local enemy_pos = 0 if self:GetEnemy() == nil then//no enemy self:FindEnemyDan() //print( "No Enemy!" ); self:SetSchedule(SCHED_COMBAT_PATROL)//patrol# self.TakingCover = false //play idle sounds every now and then local random_s = math.random(1,80) if random_s == 1 then self:StopSpeechSounds() self:EmitSound( self.idle1) elseif random_s == 2 then self:StopSpeechSounds() self:EmitSound( self.idle2) elseif random_s == 3 then self:StopSpeechSounds() self:EmitSound( self.idle3) elseif random_s == 4 then self:StopSpeechSounds() self:EmitSound( self.idle4) end else //print( "Enemy!" ); //print(self:GetEnemy()) enemy_pos = self:GetEnemy():GetPos() distance = self:GetPos():Distance(enemy_pos) //distance = 4000 if distance > 4000 then//if too far away print( "Find him!" ); self:SetSchedule(SCHED_CHASE_ENEMY)//move to enemy elseif distance < 4000 && distance > 400 then//if in reasonable distance if self:Health() < (self.StartHealth*0.25) then//if damaged > 75% and not in cover self.TakingCover = true print( "Take Cover, I'm hurt!" ); self:SetSchedule(SCHED_TAKE_COVER_FROM_ENEMY)//take cover else self.TakingCover = false if CurTime() > self.speaktime then self.speaktime = CurTime() + 6 local randomsound = math.random(1,8) if randomsound == 1 then self:StopSpeechSounds() self:EmitSound( self.attack1) elseif randomsound == 2 then self:StopSpeechSounds() self:EmitSound( self.attack2) elseif randomsound == 3 then self:StopSpeechSounds() self:EmitSound( self.attack3) elseif randomsound == 4 then self:StopSpeechSounds() self:EmitSound( self.attack4) elseif randomsound == 5 then self:StopSpeechSounds() self:EmitSound( self.attack5) elseif randomsound == 6 then self:StopSpeechSounds() self:EmitSound( self.attack6) end end if haslos then //&& distance > 1000 then self:SetSchedule(SCHED_COMBAT_STAND) else if math.random(1,2) == 1 then self:SetSchedule(SCHED_ESTABLISH_LINE_OF_FIRE)//move to shoot enemy else self:SetSchedule(SCHED_CHASE_ENEMY)//otherwise go to them. end end if math.random(1,80) < 3 then print("Reloading") self:SetSchedule(SCHED_RELOAD) //give the ILLUSION of reloading. :D end //self:SetSchedule(SCHED_RANGE_ATTACK1) end else//if too close if (haslos == true) then if self.TakingCover == false then self.TakingCover = true self:SetSchedule( SCHED_TAKE_COVER_FROM_ENEMY )//avoid melee attack else //self.TakingCover = false self:SetSchedule(SCHED_COMBAT_STAND ) end else self.TakingCover = false self:SetSchedule(SCHED_CHASE_ENEMY)//move to shoot enemy end end end end end function ENT:FindEnemyDan() local MyNearbyTargets = ents.FindInCone(self:GetPos(),self:GetForward(),7000,75) //local ClosestDistance = 3000 if (!MyNearbyTargets) then print( "No Targets!" ); return end for k,v in pairs(MyNearbyTargets) do if v:Disposition(self) == 1 || v:IsPlayer() then //if (v:GetClass() == "npc_*" || v:GetClass() == "monster_*") && v:GetClass() != self:GetClass() then print(v:GetClass()) self:StopSpeechSounds() self:ResetEnemy() self:AddEntityRelationship( v, 1, 10 ) self:SetEnemy(v) local distance = self:GetPos():Distance(v:GetPos()) local randomsound = math.random(1,5) //self:SetSchedule(SCHED_ALERT_FACE) //alerted if self.Alerted == false then if (distance > 270) then if randomsound == 1 then self:EmitSound( self.alert1) end end end self.Alerted = true return end end //if ClosestDistance == 4000 then self:SetEnemy(NULL) //end end function ENT:StopSpeechSounds() self:StopSound(self.alert1) self:StopSound(self.idle1) self:StopSound(self.idle2) self:StopSound(self.idle3) self:StopSound(self.idle4) self:StopSound(self.attack1) self:StopSound(self.attack2) self:StopSound(self.attack3) self:StopSound(self.attack4) self:StopSound(self.attack5) self:StopSound(self.attack6) self:StopSound(self.cover) end function ENT:StopHurtSounds() self:StopSound(self.hurtsound1) self:StopSound(self.hurtsound2) self:StopSound(self.hurtsound3) self:StopSound(self.hurtsound4) end function ENT:SpawnBlood(dmg) if (self.bleeds > 0) then local bloodeffect = ents.Create( "info_particle_system" ) bloodeffect:SetKeyValue( "effect_name", "blood_impact_red_01" ) bloodeffect:SetPos( dmg:GetDamagePosition() ) bloodeffect:Spawn() bloodeffect:Activate() bloodeffect:Fire( "Start", "", 0 ) bloodeffect:Fire( "Kill", "", 0.1 ) end end function ENT:GetBoomers() local nearbygrenades = ents.FindByClass("npc_grenade_frag") for k,v in pairs(nearbygrenades) do if self:GetPos():Distance(v:GetPos()) < 400 then self:StopSpeechSounds() self:ResetEnemy() self:AddEntityRelationship( v, 3, 10 ) //self:SetEnemy(v) local randomsound = math.random(1,2) if randomsound == 1 then self:EmitSound( self.grenade1) else self:EmitSound( self.grenade2) end self.seen_grenade = true self.TakingCover = true self.TakenCover = true self:SetSchedule(SCHED_HIDE_AND_RELOAD) return end end end function ENT:KilledDan() /*I Took some of silverlan's code for ragdolling, cause I didn't want to recode it :P*/ //emit cry of death self:StopSpeechSounds() self:StopHurtSounds() local deathseed = math.random(1,3) if deathseed == 1 then self:EmitSound( self.die1) elseif deathseed == 2 then self:EmitSound( self.die2) elseif deathseed == 3 then self:EmitSound( self.die3) end //create ragdoll local ragdoll = ents.Create( "prop_ragdoll" ) ragdoll:SetModel( self:GetModel() ) ragdoll:SetPos( self:GetPos() ) ragdoll:SetAngles( self:GetAngles() ) ragdoll:Spawn() ragdoll:SetSkin( self:GetSkin() ) ragdoll:SetColor( self:GetColor() ) ragdoll:SetMaterial( self:GetMaterial() ) cleanup.ReplaceEntity(self,ragdoll) undo.ReplaceEntity(self,ragdoll) //ignight ragdoll if on fire. if self:IsOnFire() then ragdoll:Ignite( math.Rand( 8, 10 ), 0 ) end //position bones the same way. for i=1,128 do local bone = ragdoll:GetPhysicsObjectNum( i ) if ValidEntity( bone ) then local bonepos, boneang = self:GetBonePosition( ragdoll:TranslatePhysBoneToBone( i ) ) bone:SetPos( bonepos ) bone:SetAngle( boneang ) end end if( GetConVarNumber("ai_keepragdolls") == 0 ) then ragdoll:SetCollisionGroup( 1 )//COLLISION_GROUP_DEBRIS ) ragdoll:Fire( "FadeAndRemove", "", 7 ) end self:Remove() end function ENT:CallForHelp() local AllOfMyFriends = ents.FindByClass(self:GetClass()) for _,x in pairs(AllOfMyFriends) do if self:GetPos():Distance(x:GetPos()) < 1000 then if x.Alerted == false then x:ResetEnemy() x:AddEntityRelationship( self:GetEnemy(), 1, 10 ) x:SetEnemy(self:GetEnemy()) x:SetSchedule(SCHED_ALERT_FACE) end end end local chance = math.random(1,100) if chance == 1 then self:EmitSound("soviet/paintalk.wav") elseif chance == 2 then self:EmitSound(self.cover) elseif chance == 3 then self:EmitSound("soviet/backup.wav") end end function ENT:ResetEnemy() end function ENT:FindCloseEnemies() local MyNearbyTargets = ents.FindInCone(self:GetPos(),self:GetForward(),300,85) //local ClosestDistance = 3000 if (!MyNearbyTargets) then print( "No Targets!" ); return end for k,v in pairs(MyNearbyTargets) do if v:Disposition(self) == 1 || v:IsPlayer() then print(v:GetClass()) self:StopSpeechSounds() self:ResetEnemy() self:AddEntityRelationship( v, 1, 10 ) self:SetEnemy(v) //if (self.TakingCover == false) || self.Alerted == false then // self.TakingCover = true // self:SetSchedule(SCHED_TAKE_COVER_FROM_ENEMY) //end self.Alerted = true return end end end function ENT:OnRemove() timer.Remove("melee_attack_timer" .. self.Entity:EntIndex( )) timer.Remove("melee_done_timer" .. self.Entity:EntIndex( )) end function ENT:HasLOS() if self:GetEnemy() != nil then //local shootpos = self:GetAimVector()*(self:GetPos():Distance(self:GetEnemy():GetPos())) + self:GetPos() //local shootpos = self:GetEnemy():GetPos() local tracedata = {} tracedata.start = self:GetPos() tracedata.endpos = self:GetEnemy():GetPos() tracedata.filter = self local trace = util.TraceLine(tracedata) if trace.HitWorld == false then print("returned true!") return true else return false end end print ("no enemy!") return false end