· 6 years ago · Apr 22, 2019, 09:34 PM
1-- NPC Mod By Starkkz
2
3npc_class = {}
4
5npc_class.team = 0
6npc_class.health = 0
7npc_class.attackdist = 0
8npc_class.attackdelay = 0
9npc_class.movementdelay = 0
10npc_class.movementspeed = 0
11npc_class.sprite = ""
12npc_class.hitzonemode = 3
13npc_class.spritescalex = 1
14npc_class.spritescaley = 1
15npc_class.movementsleep = 0
16
17npc_class.last_attack = 0
18npc_class.last_move = 0
19
20function npc_class:init()
21end
22
23function npc_class:exists()
24 if self.id then
25 return object(self.id, "exists")
26 end
27end
28
29function npc_class:Always()
30end
31
32function npc_class:UpdateSprite()
33end
34
35function npc_class:tweenUpdateSprite(t,x,y,r)
36end
37
38function npc_class:onDie()
39 self:freeslot()
40end
41
42function npc_class:resetTarget()
43 self.lastTarget = 0
44 self.lastVisual = false
45 self.targetNPC = false
46end
47
48function npc_class:targetAlive()
49 if self.lastTarget == 0 then
50 return false
51 end
52 if self.targetNPC then
53 local Table = NPC_Tab[self.lastTarget]
54 if Table then
55 return Table.health > 0
56 end
57 else
58 return player(self.lastTarget, "health") > 0
59 end
60end
61
62function npc_class:targetInRange()
63 if self.lastTarget == 0 then
64 return 0
65 end
66 return self:distObject(self.lastTarget, self.targetNPC) < self.viewdist
67end
68
69function npc_class:onHit(attacker,wpn,dmg,isNPC)
70end
71
72function npc_class:onAttack(id,isNPC)
73end
74
75function npc_class:onUseEvent(id,range)
76end
77
78function npc_class:onMove()
79end
80
81function npc_class:walkable(x,y)
82 return tile(x, y, "walkable")
83end
84
85function npc_class:fixpixels(x,y)
86 local modx = x % 32
87 local mody = y % 32
88 local nx, ny
89 if modx <= 8 and not self:walkable(math.floor(x/32)-1, math.floor(y/32)) then
90 nx = x + 2
91 elseif modx >= 24 and not self:walkable(math.floor(x/32)+1, math.floor(y/32)) then
92 nx = x - 2
93 else
94 nx = x
95 end
96 if mody <= 8 and not self:walkable(math.floor(x/32), math.floor(y/32)-1) then
97 ny = y + 2
98 elseif mody >= 24 and not self:walkable(math.floor(x/32), math.floor(y/32)+1) then
99 ny = y - 2
100 else
101 ny = y
102 end
103 return nx, ny
104end
105
106function npc_class:onMoveEvent()
107 if self.var.path and self.var.path[self.var.pathpos] then
108 local pos = self.var.pathpos
109 local tarx
110 local tary
111 local node = self.var.path[pos]
112
113 if node.pixel then
114 tarx = node.x
115 tary = node.y
116 elseif node.x and node.y then
117 tarx = node.x*32 + 16
118 tary = node.y*32 + 16
119 else
120 return nil
121 end
122
123 if self:dist(tarx, tary) <= self.movementmax then
124 if node.pixel then
125 self.var.path = nil
126 self.var.pathpos = nil
127 else
128 self.var.pathpos = pos - 1
129 end
130 else
131 if node.dist and node.dist > 1.42 and not MapTeleporter(node.x, node.y) then
132 self.var.path = nil
133 self.var.pathpos = nil
134 else
135 local a = AngleBetween(self:x(), self:y(), tarx, tary)
136 local x = self:x() + math.sin(a) * self.movementspeed
137 local y = self:y() - math.cos(a) * self.movementspeed
138 x, y = self:fixpixels(x, y)
139
140 local allowed, rot = self:onMove(x, y, math.deg(a))
141 if not allowed then allowed = 0 end
142 if not rot then rot = math.deg(a) end
143
144 if allowed == 0 then
145 self:move(x, y, rot)
146 return true
147 end
148 end
149 end
150 end
151end
152
153function npc_class:FindPath(x,y)
154 return FindPath(self:tilex(), self:tiley(), x, y)
155end
156
157function npc_class:findTargetPath(id,isNPC)
158 local target_x = object_x(id, isNPC)
159 local target_y = object_y(id, isNPC)
160
161 local target_tx = math.floor(target_x/32)
162 local target_ty = math.floor(target_y/32)
163
164 if not self:walkable(target_tx, target_ty) then
165 return nil
166 end
167
168 if self:freeline(target_x, target_y) then
169 self.var.path = {{x = target_x,y = target_y,pixel = true}}
170 self.var.pathpos = 1
171 else
172 if self.var.path and self.var.path[self.var.pathpos] then
173 return nil
174 else
175 self.var.path = self:FindPath(target_tx, target_ty)
176 if not self.var.path then
177 self.var.pathpos = 0
178 self:resetTarget()
179 else
180 self.var.pathpos = #self.var.path
181 end
182 end
183 end
184end
185
186function npc_class:onSeeEnemy(id,isNPC)
187end
188
189function npc_class:lostVisual(id,isNPC)
190end
191
192function npc_class:find_target_player()
193 local closest
194 for _, id in pairs(player(0,"tableliving")) do
195 local dist = self:dist(player(id,"x"), player(id,"y"))
196 if not closest or dist < closest[2] then
197 if self.team ~= player(id,"team") then
198 if self:attackable(player(id,"x"), player(id,"y")) then
199 closest = {id, dist}
200 end
201 end
202 end
203 end
204 if closest then
205 return closest[1], closest[2]
206 end
207end
208
209function npc_class:find_target_npc()
210 local closest
211 for id, t in pairs(NPC_Tab) do
212 if id ~= self.id and t ~= self and t.health > 0 then
213 local dist = self:dist(t:x(), t:y())
214 if not closest or dist < closest[2] then
215 if self.team ~= t.team then
216 if self:attackable(t:x(), t:y()) then
217 closest = {id, dist}
218 end
219 end
220 end
221 end
222 end
223 if closest then
224 return closest[1], closest[2]
225 end
226end
227
228function npc_class:find_target()
229 if self:targetAlive() and self:targetInRange() then
230 return self.lastTarget, self.targetNPC
231 end
232
233 local target_player, player_dist = self:find_target_player()
234 local target_npc, npc_dist = self:find_target_npc()
235
236 if target_player and not target_npc then
237 return target_player, false
238 elseif target_npc and not target_player then
239 return target_npc, true
240 elseif not target_player and not target_npc then
241 return nil
242 end
243
244 if player_dist <= npc_dist then
245 return target_player, false
246 end
247 return target_npc, true
248end
249
250function npc_class:checkVisual(x,y)
251 return self:dist(x, y) < self.viewdist
252end
253
254function npc_class:freeslot()
255 if self:exists() then
256 NPC_Tab[self.id] = nil
257 if object(self.id, "exists") then
258 freeimage(self.id)
259 end
260 end
261end
262
263function npc_class:move(x,y,rot,speed)
264 if self:exists() then
265 local comp_x = x or self:x()
266 local comp_y = y or self:y()
267 local comp_rot = rot or self:rot()
268 local spd = speed or self.movementdelay
269
270 if comp_x ~= self:x() or comp_y ~= self:y() or comp_rot ~= self:rot() then
271 if spd == 0 then
272 imagepos(self.id, comp_x, comp_y, comp_rot)
273 self:UpdateSprite()
274 else
275 tween_move(self.id, spd, comp_x, comp_y, comp_rot)
276 self:tweenUpdateSprite(spd,comp_x,comp_y,comp_rot)
277 end
278 end
279 end
280end
281
282function npc_class:setpos(x,y,rot)
283 if self:exists() then
284 local comp_x = x or self:x()
285 local comp_y = y or self:y()
286 local comp_rot = rot or self:rot()
287
288 if comp_x ~= self:x() or comp_y ~= self:y() or comp_rot ~= self:rot() then
289 imagepos(self.id, comp_x, comp_y, comp_rot)
290 self:UpdateSprite()
291 end
292 end
293end
294
295function npc_class:moveAvail()
296 return Millisecs() - self.last_move >= self.movementdelay and Millisecs() - self.last_move >= self.movementsleep
297end
298
299function ClosestTargets(id, dist, areNPCs)
300 local targets = {}
301 if areNPCs then
302 local t = NPC_Tab[id]
303 for _, p in pairs(player(0,"tableliving")) do
304 if t:dist(player(p,"x"), player(p,"y")) < dist then
305 table.insert(targets, {p, false})
306 end
307 end
308
309 for n, tb in pairs(NPC_Tab) do
310 if n ~= t.id and n ~= id and t:dist(tb:x(), tb:y()) < dist then
311 table.insert(targets, {n, true})
312 end
313 end
314 else
315 for _, p in pairs(player(0,"tableliving")) do
316 if p ~= id and DistBetween(player(id,"x"), player(id,"y"), player(p,"x"), player(p,"y")) < dist then
317 table.insert(targets, {p, false})
318 end
319 end
320
321 for n, t in pairs(NPC_Tab) do
322 if t:dist(player(id,"x"), player(id,"y")) < dist then
323 table.insert(targets, {n, false})
324 end
325 end
326 end
327 return targets
328end
329
330function npc_class:ClosestTargets(dist)
331 return ClosestTargets(self.id, dist, true)
332end
333
334function npc_class:AddTimer(delay,func,...)
335 table.insert(self.timer, {Millisecs() + delay,func,{...}})
336end
337
338function npc_class:dist(x,y)
339 if x and y then
340 return DistBetween(self:x(), self:y(), x, y)
341 end
342end
343
344function npc_class:distObject(id, isNPC)
345 local x, y
346 if isNPC then
347 x, y = object(id, "x"), object(id, "y")
348 else
349 x, y = player(id, "x"), player(id, "y")
350 end
351 if x and y then
352 return DistBetween(self:x(), self:y(), x, y)
353 end
354 return 0
355end
356
357function npc_class:angle(x,y)
358 return AngleBetween(self:x(), self:y(), x, y)
359end
360
361function npc_class:aim(x,y)
362 imagepos(self.id, self:x(), self:y(), math.deg(self:angle(x, y)))
363end
364
365function npc_class:x()
366 if self:exists() then return object(self.id, "x") end
367end
368
369function npc_class:y()
370 if self:exists() then return object(self.id, "y") end
371end
372
373function npc_class:tilex()
374 return math.floor(self:x()/32)
375end
376
377function npc_class:tiley()
378 return math.floor(self:y()/32)
379end
380
381function npc_class:rot()
382 if self:exists() then return object(self.id, "rot") end
383end
384
385function npc_class:sound3(f,radius)
386 Sound3(f, self:x(), self:y(), radius)
387end
388
389function npc_class:attackable(x,y)
390 return attackable(self:x(), self:y(), x, y)
391end
392
393function npc_class:freeline(...)
394 if #arg < 2 then return nil end
395 local sx, sy = self:x(), self:y()
396 local Dist = DistBetween(self:x(), self:y(), arg[1], arg[2])
397 local Angle = AngleBetween(self:x(), self:y(), arg[1], arg[2])
398 for i = 1, Dist, 4 do
399 sx = sx + math.sin(Angle) * 4
400 sy = sy - math.cos(Angle) * 4
401 if not self:walkable(math.floor(sx/32), math.floor(sy/32)) then
402 return false
403 end
404 end
405 return true
406end
407
408function npc_class:new()
409 local t = {}
410 setmetatable(t, {__index = self})
411 return t
412end
413
414function Millisecs()
415 return os.clock() * 1000
416end
417
418function table.find(tab,var)
419 for k, v in pairs(tab) do
420 if v == var then return k end
421 end
422 return false
423end
424
425function Sound3(file, x, y, radius)
426 for _, id in pairs(player(0,"table")) do
427 if DistBetween(x, y, player(id,"x"), player(id,"y")) < radius then
428 parse("sv_sound2 "..id.." "..file)
429 end
430 end
431end
432
433function CalcDamage(h,a,d)
434 if not h or not a or not d then return nil end
435
436 local d = math.floor(d * game("mp_damagefactor"))
437 if a >= 0 and a <= 200 then
438 local _a = a - d
439 local _h = h - d*(1-game("mp_kevlar"))
440 if _a < 0 then
441 _h = _h + _a
442 _a = 0
443 end
444 return math.floor(_h), math.floor(_a)
445 elseif a == 201 then
446 local _h = h - d*0.75
447 return math.floor(_h), a
448 elseif a == 202 or a == 204 then
449 local _h = h - d*0.5
450 return math.floor(_h), a
451 elseif a == 203 then
452 local _h = h - d*0.25
453 return math.floor(_h), a
454 elseif a == 205 then
455 local _h = h - d*0.05
456 return math.floor(_h), a
457 elseif a == 206 then
458 local _h = h - d
459 return math.floor(_h), a
460 end
461end
462
463NPC_Tab = {}
464NPC_Info = {}
465
466function RegisterNPC(name,info)
467 NPC_Info[name] = info
468end
469
470function NewNPC(name)
471 local t = NPC_Info[name]
472 if t then
473 while type(t) == "string" do
474 t = _G[t]
475 end
476 if type(t) == "table" then
477 return t:new()
478 end
479 end
480end
481
482function SpawnNPC(name,x,y,rot)
483 if NPC_Info[name] then
484 local npc = NewNPC(name)
485
486 npc.id = image(npc.sprite, 0, 1, npc.spritemode or 1)
487 npc:setpos(x, y, rot)
488 npc.lastVisual = false
489 npc.lastTarget = 0
490 npc.targetNPC = false
491 npc.width = npc.width or 32
492 npc.height = npc.height or 32
493 npc.var = {}
494
495 if npc.id then
496 imagescale(npc.id, npc.spritescalex, npc.spritescaley)
497 imagehitzone(npc.id, npc.hitzonemode or 3, -npc.width/2, -npc.height/2, npc.width, npc.height)
498 npc:init()
499
500 NPC_Tab[npc.id] = npc
501 return npc
502 end
503 return false, "Failed to create NPC, no image id"
504 end
505 return false, "NPC Class does not exist"
506end
507
508function attackable(...)
509 if #arg < 4 then return nil end
510 local x, y = arg[1], arg[2]
511 local Dist = DistBetween(arg[1], arg[2], arg[3], arg[4])
512 local Angle = AngleBetween(arg[1], arg[2], arg[3], arg[4])
513 for i = 1, Dist, 4 do
514 x = x + math.sin(Angle) * 4
515 y = y - math.cos(Angle) * 4
516 if tile(math.floor(x/32),math.floor(y/32),"wall") then
517 return false
518 end
519 end
520 return true
521end
522
523function PathMap(x,y)
524 if tile(x,y,"walkable") then
525 return 0
526 end
527 return 1
528end
529
530function MapTeleporter(x,y)
531 if entity(x, y, "exists") and entity(x, y, "typename") == "Func_Teleport" then
532 if entity(x, y, "state") then
533 return entity(x, y, "int0"), entity(x, y, "int1")
534 end
535 end
536end
537
538function FindPath(fx,fy,tx,ty,Map)
539 if Map == nil then Map = PathMap end
540
541 if Map(fx,fy) == 1 or Map(tx,ty) == 1 then
542 return nil, "The start or the goal is not walkable"
543 end
544
545 local Node = {}
546 local curbase = {x = fx,y = fy}
547 local openlist = {{x = fx,y = fy}}
548
549 local function Euclidean(fx,fy,tx,ty)
550 return math.sqrt((fx-tx)^2 + (fy-ty)^2)
551 end
552
553 function CreateNodeConfig(x,y,open)
554 if not Node[x] then Node[x] = {} end
555 if not Node[x][y] then
556 if open == nil then open = false end
557 local n = {
558 Open = open,
559 Closed = false,
560 parent = {}
561 }
562 n.G = 0
563 n.H = Euclidean(x,y,tx,ty)
564 n.F = n.H
565 Node[x][y] = n
566 end
567 end
568
569 CreateNodeConfig(fx,fy,1)
570
571 local function FixedPath()
572 local i = {x = tx,y = ty}
573 local path = {}
574 while Node[i.x][i.y].parent.x and Node[i.x][i.y].parent.y do
575 local parent = Node[i.x][i.y].parent
576 local Details = {
577 x = i.x,
578 y = i.y,
579 dist = math.sqrt((i.x - parent.x)^2 + (i.y - parent.y)^2)
580 }
581 table.insert(path, Details)
582 i = parent
583 end
584 return path, #path, -1
585 end
586
587 local function CheckNode(l,x,y,p)
588 CreateNodeConfig(x,y)
589 if not Node[x][y].Closed and Map(x,y) == 0 then
590 local t = {x = x,y = y}
591 if p then t.parent = p end
592 table.insert(l, t)
593
594 local nx, ny = MapTeleporter(x, y)
595 if nx and ny then
596 CheckNode(l, nx, ny, t)
597 end
598 end
599 end
600
601 local function AddNode(v,p)
602 local score = Node[p.x][p.y].G + math.sqrt((v.x-p.x)^2 + (v.y-p.y)^2)*32
603 if not Node[v.x][v.y].Open then
604 local pos = #openlist+1
605 openlist[pos] = {x = v.x,y = v.y}
606 Node[v.x][v.y].Open = pos
607 Node[v.x][v.y].parent = p
608 Node[v.x][v.y].G = score
609 Node[v.x][v.y].F = score + Node[v.x][v.y].H
610 elseif score <= Node[v.x][v.y].G then
611 Node[v.x][v.y].parent = p
612 Node[v.x][v.y].G = score
613 Node[v.x][v.y].F = Node[v.x][v.y].G + Node[v.x][v.y].H
614 end
615 end
616
617 local function LowestNode()
618 local lVal, lID
619 for k, v in pairs(openlist) do
620 if not lVal or Node[v.x][v.y].F < Node[lVal.x][lVal.y].F then
621 lVal = v
622 lID = k
623 end
624 end
625 return lVal, lID
626 end
627
628 local function OpenListEmpty()
629 for k, v in pairs(openlist) do
630 return false
631 end
632 return true
633 end
634
635 while not OpenListEmpty() do
636 local lW, lWID = LowestNode()
637
638 if not lW or not lWID then
639 return nil, "Failed to find path"
640 else
641 Node[lW.x][lW.y].Closed = true
642 Node[lW.x][lW.y].Open = false
643 openlist[lWID] = nil
644 curbase = lW
645 end
646
647 if curbase.x == tx and curbase.y == ty then
648 return FixedPath()
649 end
650
651 local NearNodes = {}
652 CheckNode(NearNodes,curbase.x,curbase.y+1)
653 CheckNode(NearNodes,curbase.x+1,curbase.y)
654 CheckNode(NearNodes,curbase.x,curbase.y-1)
655 CheckNode(NearNodes,curbase.x-1,curbase.y)
656 if Map(curbase.x+1,curbase.y) == 0 and Map(curbase.x,curbase.y+1) == 0 then CheckNode(NearNodes,curbase.x+1,curbase.y+1) end
657 if Map(curbase.x+1,curbase.y) == 0 and Map(curbase.x,curbase.y-1)== 0 then CheckNode(NearNodes,curbase.x+1,curbase.y-1) end
658 if Map(curbase.x-1,curbase.y) == 0 and Map(curbase.x,curbase.y+1) == 0 then CheckNode(NearNodes,curbase.x-1,curbase.y+1) end
659 if Map(curbase.x-1,curbase.y) == 0 and Map(curbase.x,curbase.y-1) == 0 then CheckNode(NearNodes,curbase.x-1,curbase.y-1) end
660 for i = 1, #NearNodes do
661 AddNode(NearNodes[i], NearNodes[i].parent or curbase)
662 end
663 end
664 return nil, "Couldn't find the path"
665end
666
667function PathWalkable(path)
668 for k, v in pairs(path) do
669 if not tile(v.x,v.y,"walkable") then
670 return false
671 end
672 end
673 return true
674end
675
676function AngleBetween(...)
677 if #arg < 4 then return nil end
678 local Angle = math.atan2(arg[2] - arg[4],arg[1] - arg[3]) - math.pi/2
679 if Angle < -math.pi then
680 Angle = Angle + (math.pi*2)
681 end
682 return Angle
683end
684
685function DistBetween(a, b, x, y)
686 return math.sqrt((a - x)^2 + (b - y)^2)
687end
688
689function FixRot(angle)
690 while angle < -180 do angle = angle + 360 end
691 while angle > 180 do angle = angle - 360 end
692 return angle
693end
694
695addhook("use","npc_onUse")
696function npc_onUse(id)
697 for k, npc in pairs(NPC_Tab) do
698 npc:onUseEvent(id, v:dist(player(id,"x"), player(id,"y")))
699 end
700end
701
702addhook("hitzone","npc_hit")
703function npc_hit(id,p,o,w,x,y)
704 local npc = NPC_Tab[id]
705 if npc then
706 local dmg = itemtype(w, "dmg")
707 if dmg then
708 npc:onHit(p, w, dmg, false)
709 end
710 end
711end
712
713addhook("always","npc_Always")
714function npc_Always()
715 for k, npc in pairs(NPC_Tab) do
716 if object(k, "exists") then
717 for timer_id = 1, #npc.timer, 1 do
718 if Millisecs() - npc.timer[i][1] >= 0 then
719 npc.timer[i][2](unpack(npc.timer[i][3]))
720 npc.timer[i] = nil
721 end
722 end
723
724 npc:Always()
725
726 if npc:moveAvail() then
727 if npc:onMoveEvent() then
728 npc.last_move = Millisecs()
729 end
730 end
731
732 local id, isNPC = npc:find_target()
733 if id then
734 if npc:checkVisual(object_x(id, isNPC), object_y(id, isNPC)) then
735 npc:onSeeEnemy(id, isNPC)
736 npc.lastTarget = id
737 npc.lastVisual = true
738 npc.targetNPC = isNPC
739 end
740 end
741
742 if npc.lastTarget > 0 then
743 local targetID = npc.lastTarget
744 local targetNPC = npc.targetNPC
745 local lastVisual = npc.lastVisual
746
747 local target_x = object_x(targetID, targetNPC)
748 local target_y = object_y(targetID, targetNPC)
749 local target_health = object_health(targetID, targetNPC)
750 local target_exists = target_x and target_y and target_health
751
752 npc.targetx = target_x
753 npc.targety = target_y
754 npc.targetAttackable = npc:attackable(npc.targetx, npc.targety)
755 npc.targetLine = npc:freeline(npc.targetx, npc.targety)
756
757 if target_exists and target_health > 0 and npc:checkVisual(target_x, target_y) then
758 local dist = npc:dist(target_x, target_y)
759 if dist <= npc.attackdist and npc.targetAttackable then
760 if npc.attackmindist and dist > npc.attackmindist then
761 npc:findTargetPath(targetID, targetNPC)
762 end
763
764 if Millisecs() - npc.last_attack >= npc.attackdelay then
765 npc.last_attack = Millisecs()
766 npc:onAttack(targetID, targetNPC)
767 end
768 else
769 npc:findTargetPath(targetID, targetNPC)
770 end
771 npc:aim(target_x, target_y)
772 else
773 npc:lostVisual(targetID, targetNPC)
774 if target_exists and target_health > 0 then
775 if npc:checkVisual(target_x, target_y) then
776 npc:findTargetPath(targetID, targetNPC)
777 end
778 end
779 end
780 end
781
782 if npc.health <= 0 then
783 -- Anti death bug
784 npc:onDie()
785 end
786 end
787 end
788end
789
790addhook("parse","npc_onparse")
791function npc_onparse(cmd)
792 local s = {}
793 for word in cmd:gmatch("[^%s]+") do table.insert(s, word) end
794 if s[1] == "spawnlnpc" then
795 local name,x,y,rot = s[2],tonumber(s[3]),tonumber(s[4]),tonumber(s[5])
796 if name and x and y and rot then
797 local b, e = SpawnNPC(name, x*32+16, y*32+16,rot)
798 if not b then
799 print("NPC Error: "..e)
800 end
801 elseif not name then
802 print("Missing NPC name")
803 elseif not x then
804 print("Missing X coordinate")
805 elseif not y then
806 print("Missing Y coordinate")
807 elseif not rot then
808 print("Missing rotation")
809 end
810 return 1
811 end
812end
813
814addhook("startround","onStart")
815function onStart()
816 for k, v in pairs(NPC_Tab) do
817 NPC_Tab[k] = nil
818 end
819end
820
821function TileDirt(x,y)
822 return tile(x,y,"property") == 10
823end
824
825function TileSnow(x,y)
826 return tile(x,y,"property") == 11
827end
828
829function TileStep(x,y)
830 return tile(x,y,"property") == 12
831end
832
833function TileTile(x,y)
834 return tile(x,y,"property") == 13
835end
836
837function TileWater(x,y)
838 return tile(x,y,"property") == 14
839end
840
841function TileMetal(x,y)
842 return tile(x,y,"property") == 15
843end
844
845function TileWood(x,y)
846 return tile(x,y,"property") == 16
847end
848
849function object_x(id,isNPC)
850 if isNPC and NPC_Tab[id] then
851 return NPC_Tab[id]:x()
852 elseif player(id,"exists") then
853 return player(id,"x")
854 end
855end
856
857function object_y(id,isNPC)
858 if isNPC and NPC_Tab[id] then
859 return NPC_Tab[id]:y()
860 elseif player(id,"exists") then
861 return player(id,"y")
862 end
863end
864
865function object_health(id,isNPC)
866 if isNPC and NPC_Tab[id] then
867 return NPC_Tab[id].health
868 elseif player(id,"exists") then
869 return player(id,"health")
870 end
871end
872
873dofile("sys/lua/NPC_Mod/npcscripts/zombie.lua")
874dofile("sys/lua/NPC_Mod/npcscripts/hl2_strider.lua")
875dofile("sys/lua/NPC_Mod/npcscripts/hl_headcrab.lua")
876dofile("sys/lua/NPC_Mod/npcscripts/hl_houndeye.lua")
877dofile("sys/lua/NPC_Mod/npcscripts/hl_agrunt.lua")
878dofile("sys/lua/NPC_Mod/npcscripts/hl_bullsquid.lua")