aboutsummaryrefslogtreecommitdiff
path: root/gamemode/npcsystem/sv_zombie.lua
blob: 7f7e49686977df8da76285f838f471bace6fa031 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
local n = nrequire("sv_npcsystem.lua")
local ncom = nrequire("sv_common.lua")
local NPC = {}
NPC.Name 			= "Zombie"
NPC.Desc 			= "The living dead, argh!"
NPC.Class 			= "Ambient" --Ambient, Agressive, Boss
NPC.Model			= "models/Zombie/Classic.mdl"
--[[
models/Zombie/Fast.mdl
models/Zombie/Poison.mdl
models/Humans/corpse1.mdl
models/Humans/Charple01.mdl
models/fallout/tunneler.mdl
models/fallout/streettrog.mdl
models/fallout/deathclaw.mdl
models/fallout/deathclaw_alphamale.mdl
models/fallout/deathclaw_baby.mdl
models/fallout/deathclaw_mother.mdl
models/fallout/gecko.mdl
models/fallout/giantrat.mdl
models/fallout/sporecarrier.mdl
]]

NPC.Stats = {
    ["Vitality"]    = 400,
    ["Speed"]       = 40,
    ["AwareDist"]   = 1000,
    ["Accel"]       = 25,
    ["Decel"]       = 40,
    ["Step"]        = 20, --Step height
    ["Hull"]        = HULL_HUMAN
}

--Some npc's like birds have diffent names for their idle sequences
NPC.IdleSequences = {
    [0] = "idle",
}

--Drops should be formated as [index]={["item name"], percent_drop} where percent_drop is a number from 0 to 100

NPC.Drops           = {
    [0] = {"Rat Meat",100},--Rats will drop at least 1 meat, and have a 50% chance of dropping 2
    [1] = {"Rat Meat",50},
}

local checkattack = function(self,ply)
    print("Checking attack")
    if not ply or not self then return -1 end
    local pp,sp = ply:GetPos(),self:GetPos()
    local isnear = (pp:Distance(sp) < 100) and (math.abs(pp.z - sp.z) < 20)
    local canattack = CurTime() - self.lastattack > 2
    if isnear and canattack then
        local tr = util.TraceLine({
            start = self:GetPos() + Vector(0,0,50),
            endpos = ply:GetPos() + Vector(0,0,50),
            filter = self,
        })
        if tr.Hit and tr.Entity == ply then
            return 2
        else
            return 0
        end
    else
        return 0
    end
end

local doattack = function(self,ply)
    print("Doing attack")
    self.lastattack = CurTime()
    self:StartActivity(ACT_MELEE_ATTACK1)
    timer.Simple(1,function() --It looks like you're hit about 1/2s after animation start
        if (not IsValid(self)) or( not IsValid(ply)) then return end --Make sure we're both still alive!
        local sp,pp = self:GetPos(),ply:GetPos()
        local cross = sp:Cross(pp)
        local fppj = cross:GetNormalized():Dot(self:GetForward())
        if math.abs(fppj) < 0.1 and sp:Distance(pp) < 75 then --If the player is still in front of us, do a trace
            local tr = util.TraceLine({
                start = sp + Vector(0,0,50),
                endpos = pp + Vector(0,0,50),
                filter = self,
            })
            if tr.Hit and tr.Entity == ply then
                ply:TakeDamage(20,self,self)
            else
                print("tr.hit was",tr.Hit,"entity was",tr.Entity)
            end
        else
            print('Player was not in front, or distance too great')
            print(fppj)
            print(sp:Distance(pp))
        end
    end)
end

--At least 1 check function must return greater than -1
local checkrun = function(self,ply)
    local isnearby = (1000 - ply:GetPos():Distance(self:GetPos()))/1000 --Zombies work on smell or something, idk, line of sight is hard to do cheaply
    --But we want attack priority to override this, so only return a max of 1
    return isnearby
end

local dorun = function(self,ply)
    if CurTime() - self.lastwalk > 3 then
        self:StartActivity(  ACT_WALK   )
        self.lastwalk = CurTime()
    end
    if not ply or not ply:IsValid() then return end
    local ppos = ply:GetPos()
    self.TargetPos = ppos
    if self.TargetPos ~= nil then
        self.loco:Approach(self.TargetPos,1)
    end
end

NPC.Attacks         = {
    [1] =   {--attack the player if they're in front of us
        [checkattack] = doattack
    },
    [2] =   {--Run at the player
        [checkrun] = dorun
    }
}

--A function that takes a position and returns true if this is an acceptable place to spawn
function NPC:SpawnLocations(pos)
    return true
end

--The entity that is this npc's current target, if it has one. Nil otherwise
NPC.Target          = nil

--All enemies that this NPC is aware of
NPC.AwareEnemies    = {}
--Attack priority is a fucntion that takes a player, and returns an int describing it's prority to attack (higher = more important) NPC will always attack the player with the highest priority
function NPC:AttackPriority(ply)
    if not ply then return 0 end
    local plypos = ply:GetPos()
    local mypos = self:GetPos()
    if not plypos then return 0 end
    local dist = plypos:Distance(mypos)
    return self.Stats["AwareDist"] - dist
end

--What to replace the ENT:RunBehaviour with
function NPC:Act(deltat)
end

--What to replace ENT:OnStuck with
function NPC:Stuck()
    --Find out what we're stuck on
    local tr = util.TraceLine({
        start = self:GetPos() + Vector(0,0,50), --Start at about waist height
        endpos =( self:GetForward()*50) + self:GetPos() + Vector(0,0,50),
        filter = self
    })
    
end

--These are just here to tell the editors/develoeprs what functions are available.. dont un-comment them out, as this could affect all the items.

function NPC:OnSpawn()
    self.lastattack = CurTime()
    self.lastwalk = CurTime()
end
/*
--If we need to do more than just reduce health on dammage
function NPC:OnDammage(ammount)
end

--If we need to do more than just drop items on death
function NPC:OnDeath()
end

--A particular spell was cast on this npc by player
function NPC:OnSpell(spell, player)
end

function NPC:OnFindEnemy(enemy)
end

--Called when the npc is attacking anything with any attack
function NPC:OnAttack(target)
end
*/

n.RegisterNPC(NPC)