Guest User

Untitled

a guest
Aug 28th, 2014
213
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 23.34 KB | None | 0 0
  1. -- Custom NPCs script by Crystal Rain
  2. -- Version: 1.0
  3. -- Release date: 30.08.2013
  4.  
  5. -- The script might be a little bit complicated. It's recommended not to change anything.
  6. -- In order to add/modify NPCs you have to edit 'sys/lua/cnpc/list.lua' file.
  7.  
  8. -- Credits: EngiN33R -> Helped me to solve a problems with angels and grammar.
  9.  
  10. -- Setting up a global table
  11. cnpc = {
  12.     -- Table for spawned NPCs
  13.     spawnedNPCs = {};
  14.    
  15.     -- Table for non-hooked functions
  16.     funcs = {
  17.         -- Table for NPC based functions
  18.         npc = {
  19.             -- Function to spawn an NPC
  20.             -- type - Type id of an NPC
  21.             -- x    - X spawn position on the map (in pixels)
  22.             -- y    - Y spawn position on the map (in pixels)
  23.             -- rot  - Rotation to spawn with
  24.             spawn = function(type, x, y, rot, health)
  25.                 if type == nil then print('\169255000000Error in function \'cnpc.funcs.npc.spawn\': \'type\' paramater is not specified!') return end
  26.                 if x == nil then print('\169255000000Error in function \'cnpc.funcs.npc.spawn\': \'x\' paramater is not specified!') return end
  27.                 if y == nil then print('\169255000000Error in function \'cnpc.funcs.npc.spawn\': \'y\' paramater is not specified!') return end
  28.                 if rot == nil then print('\169255000000Error in function \'cnpc.funcs.npc.spawn\': \'rot\' paramater is not specified!') return end
  29.                 if not cnpc.list[type] then if id == nil then print('\169255000000Error in function \'cnpc.funcs.npc.spawn\': NPC with type '.. type ..' does not exist!') return end return end
  30.                
  31.                 local npcData = cnpc.list[type]
  32.                 local npc = {
  33.                     x = x;
  34.                     y = y;
  35.                     rot = rot;
  36.                     type = type;
  37.                     image = image(npcData.imagePath, 0, 0, 1);
  38.                    
  39.                     name = npcData.name;
  40.                     speed = npcData.speed;
  41.                     rotSpeed = npcData.rotationSpeed;
  42.                     behaviorType = npcData.behaviorType;
  43.                     attackCoolDown = npcData.attackCoolDown;
  44.                     health = health or npcData.health;
  45.                     damage = npcData.damage;
  46.                     data = npcData;
  47.  
  48.                     lastAttack = os.clock();
  49.                     closestPlayer = 0;
  50.                     closestPlayerLastSeen = false;
  51.                     timerParams = false;
  52.                 }
  53.                 imagepos(npc.image, x, y, rot)
  54.                 imagehitzone(npc.image, 3, -npcData.hitbox/2, -npcData.hitbox/2, npcData.hitbox, npcData.hitbox)
  55.                 table.insert(cnpc.spawnedNPCs, npc)
  56.             end;
  57.            
  58.             -- Function that removes/despawns the NPC
  59.             -- id - The ID of spawned NPC (from cnpc.spawnedNPCs table)
  60.             remove = function(id)
  61.                 if id == nil then print('\169255000000Error in function \'cnpc.funcs.npc.remove\': \'id\' paramater is not specified!') return end
  62.                 if not cnpc.spawnedNPCs[id] then print('\169255000000Error in function \'cnpc.funcs.npc.remove\': NPC with ID '.. id ..' does not exist!') return end
  63.                
  64.                 local npc = cnpc.spawnedNPCs[id]
  65.                 freeimage(npc.image)
  66.                 if npc.timerParams ~= false then freetimer(npc.timerParams[1], npc.timerParams[2]) npc.timerParams = false end
  67.                 cnpc.spawnedNPCs[id] = nil
  68.             end;
  69.            
  70.             -- Function that forces NPC to attack
  71.             -- id - The ID of spawned NPC (from cncp.spawnedNPCs table)
  72.             -- NOTE: TO USE THIS FUNCTION, NPC HAS TO HAVE THE CLOSEST PLAYER!
  73.             attack = function(id)
  74.                 if id == nil then print('\169255000000Error in function \'cnpc.funcs.npc.shoot\': \'id\' paramater is not specified!') return end
  75.                 if not cnpc.spawnedNPCs[id] then print('\169255000000Error in function \'cnpc.funcs.npc.shoot\': NPC with ID '.. id ..' does not exist!') return end
  76.                
  77.                 local npc = cnpc.spawnedNPCs[id]
  78.                 npc.lastAttack = os.clock()
  79.                 if npc.behaviorType == 0 then
  80.                     local health, armor = cnpc.funcs.math.calculateDamage(player(npc.closestPlayer, 'health'), player(npc.closestPlayer, 'armor'), npc.damage)
  81.                     local slashImage = image('gfx/knifeslash.bmp', 0, 0, 1)
  82.                    
  83.                     tween_rotate(npc.image, 62.5, npc.rot+35)
  84.                     timer(62.5, 'parse', 'lua "tween_rotate('.. npc.image ..', '.. (npc.attackCoolDown-0.0625)*1000 ..', '.. npc.rot ..')"')
  85.                    
  86.                     imagepos(slashImage, npc.x, npc.y, npc.rot)
  87.                     imageblend(slashImage, 1)
  88.                     tween_alpha(slashImage, 250, 0)
  89.                     timer(250, 'freeimage', slashImage)
  90.                    
  91.                     if health <= 0 then
  92.                         parse('customkill 0 "'.. npc.name ..'" '.. npc.closestPlayer)
  93.                     else
  94.                         parse('sethealth '.. npc.closestPlayer ..' '.. health)
  95.                         parse('setarmor '.. npc.closestPlayer ..' '.. armor)
  96.                     end
  97.                    
  98.                     for _, pl in pairs(player(0, 'tableliving')) do
  99.                         local x, y = player(pl, 'x'), player(pl, 'y')
  100.                         if x >= npc.x - 320 and y >= npc.y - 240 and x <= npc.x + 320 and y <= npc.y + 240 then
  101.                             parse('sv_sound2 '.. pl ..' "'.. npc.data.slashSound ..'"')
  102.                             parse('sv_sound2 '.. pl ..' "player/hit'.. math.random(1, 3) ..'.wav"')
  103.                         end
  104.                     end
  105.                 elseif npc.behaviorType == 1 then
  106.                     local rot = npc.rot + math.random(-npc.data.bulletSpreading, npc.data.bulletSpreading)
  107.                     local startX, startY = cnpc.funcs.math.extendPosition(npc.x, npc.y, rot, npc.data.bulletOffset)
  108.                     local endX, endY = cnpc.funcs.math.extendPosition(startX, startY, rot, npc.data.bulletLength)
  109.                     local wallX, wallY = cnpc.funcs.math.wallOnLine(startX, startY, endX, endY)
  110.                    
  111.                     local bulletShot = {}
  112.                     local bulletFlash = image('gfx/sprites/flare3.bmp', startX, startY, 1)
  113.                     local distance
  114.                     if wallX == -1 then
  115.                         distance = cnpc.funcs.math.distance(startX, startY, endX, endY)
  116.                     else
  117.                         distance = cnpc.funcs.math.distance(startX, startY, wallX, wallY)
  118.                     end
  119.                    
  120.                     local x1, y1 = cnpc.funcs.math.extendPosition(startX, startY, rot, distance / 3)
  121.                     local x2, y2 = cnpc.funcs.math.extendPosition(startX, startY, rot, (distance / 3)*2)
  122.                     local x3, y3 = cnpc.funcs.math.extendPosition(startX, startY, rot, distance)
  123.                     bulletShot = {
  124.                         cnpc.funcs.draw.line(startX, startY, x1, y1);
  125.                         cnpc.funcs.draw.line(x1, y1, x2, y2);
  126.                         cnpc.funcs.draw.line(x2, y2, x3, y3);
  127.                     }
  128.                    
  129.                     for k, v in pairs(bulletShot) do
  130.                         imagealpha(v, (4-k)*0.22)
  131.                         imagecolor(v, 255, 255, 0)
  132.                         tween_alpha(v, 125, 0)
  133.                         timer(125, 'freeimage', v)
  134.                     end
  135.                    
  136.                     imageblend(bulletFlash, 1)
  137.                     imagecolor(bulletFlash, 255, 255, 0)
  138.                     imagealpha(bulletFlash, 0.25)
  139.                     tween_alpha(bulletFlash, 125, 0)
  140.                     timer(125, 'freeimage', bulletFlash)
  141.                    
  142.                     for _, pl in pairs(player(0, 'tableliving')) do
  143.                         local x, y = player(pl, 'x'), player(pl, 'y')
  144.                         if x >= npc.x - 320 and y >= npc.y - 240 and x <= npc.x + 320 and y <= npc.y + 240 then
  145.                             parse('sv_sound2 '.. pl ..' "'.. npc.data.bulletSound ..'"')
  146.                         end
  147.                        
  148.                         local lx, ly = npc.x, npc.y
  149.                         local ex, ey = math.sin(math.rad(npc.rot)), -math.cos(math.rad(npc.rot))
  150.                         for i = 0, distance do
  151.                             lx, ly = lx + ex, ly + ey
  152.                             if x >= lx - 6 and y >= ly - 6 and x <= lx + 6 and y <= ly + 6 then
  153.                                 local health, armor = cnpc.funcs.math.calculateDamage(player(pl, 'health'), player(pl, 'armor'), npc.damage)
  154.                                 if health <= 0 then
  155.                                     parse('customkill 0 "'.. npc.name ..'" '.. npc.closestPlayer)
  156.                                 else
  157.                                     parse('sethealth '.. npc.closestPlayer ..' '.. health)
  158.                                     parse('setarmor '.. npc.closestPlayer ..' '.. armor)
  159.                                 end
  160.                                 break
  161.                             end
  162.                         end
  163.                     end
  164.                 end
  165.             end;
  166.         };
  167.        
  168.         -- Table for math based function
  169.         math = {
  170.             -- Function that returns distance between two points (in pixels)
  171.             -- x1 - X position of the first point
  172.             -- y1 - Y position of the first point
  173.             -- x2 - X position of the second point
  174.             -- y2 - Y position of the second point
  175.             distance = function(x1, y1, x2, y2)
  176.                 return math.sqrt((y1 - y2)^2 + (x1 - x2)^2)
  177.             end;
  178.  
  179.             -- Function that returns an angle between first and second point
  180.             -- x1 - X position of the first point
  181.             -- y1 - Y position of the first point
  182.             -- x2 - X position of the second point
  183.             -- y2 - Y position of the second point
  184.             getAngle = function(x1, y1, x2, y2)
  185.                 return -math.deg(math.atan2(x1 - x2, y1 - y2))
  186.             end;
  187.  
  188.             -- Function that returns an extended position by dist pixels
  189.             -- x    - X position
  190.             -- x    - Y position
  191.             -- dir  - Direction in which the position should be extended
  192.             -- dist - Distance by which the position should be extended
  193.             extendPosition = function(x, y, dir, dist)
  194.                 return x + math.sin(math.rad(dir)) * dist, y - math.cos(math.rad(dir)) * dist
  195.             end;
  196.  
  197.             -- Function that returns calculated health and armor when player has got hit
  198.             -- health - Player's health
  199.             -- armor  - Player's armor
  200.             -- damage - Damage by which the player got hit
  201.             calculateDamage = function(health, armor, damage)
  202.                 damage = (damage < 1 and 1 or damage)
  203.                 local coveredDamage, uncoveredDamage
  204.                 local returnHealth, returnArmor
  205.                
  206.                 if armor > 200 then
  207.                     if armor == 201 then
  208.                         return math.floor(health-(damage*(1-0.25))), armor
  209.                     elseif armor == 202 or armor == 204 then
  210.                         return math.floor(health-(damage*(1-0.5))), armor
  211.                     elseif armor == 203 then
  212.                         return math.floor(health-(damage*(1-0.75))), armor
  213.                     elseif armor == 205 then
  214.                         return math.floor(health-(damage*(1-0.95))), armor
  215.                     end
  216.                 end
  217.                
  218.                 if damage >= armor then
  219.                     uncoveredDamage = damage - armor
  220.                     coveredDamage = armor
  221.                 else
  222.                     uncoveredDamage = 0
  223.                     coveredDamage = damage
  224.                 end
  225.                 returnHealth = health-(coveredDamage*(1.0-tonumber(game('mp_kevlar'))))-uncoveredDamage
  226.                 returnArmor = armor - coveredDamage
  227.  
  228.                 return math.floor(returnHealth), returnArmor
  229.             end;
  230.  
  231.             -- Function that returns the position of the closest wall from first point to second point
  232.             -- Returns -1, -1 if there is no wall
  233.             -- x1 - X position of the first point
  234.             -- y1 - Y position of the first point
  235.             -- x2 - X position of the second point
  236.             -- y2 - Y position of the second point
  237.             wallOnLine = function(x1, y1, x2, y2)
  238.                 local angle = cnpc.funcs.math.getAngle(x1, y1, x2, y2)
  239.                 local distance = math.floor(cnpc.funcs.math.distance(x1, y1, x2, y2))
  240.                 local increaseX, increaseY = cnpc.funcs.math.extendPosition(x1, y1, angle, 1)
  241.                 for i = 1, distance do
  242.                     x1, y1 = cnpc.funcs.math.extendPosition(x1, y1, angle, 1)
  243.                     if tile(math.floor(x1/32), math.floor(y1/32), 'wall') then
  244.                         return x1, y1
  245.                     end
  246.                 end
  247.                 return -1, -1
  248.             end;
  249.         };
  250.  
  251.         draw = {
  252.             -- Draws a line
  253.             -- x1 - Starting X position
  254.             -- y1 - Starting Y position
  255.             -- x2 - Ending X position
  256.             -- y2 - Ending Y position
  257.             line = function(x1, y1, x2, y2, mode)
  258.                 mode = mode or 1
  259.                 local line = image('gfx/cnpc/1x1.png', 0, 0, mode)
  260.                 local angle, distance = cnpc.funcs.math.getAngle(x1, y1, x2, y2), cnpc.funcs.math.distance(x1, y1, x2, y2)
  261.                 local x, y = cnpc.funcs.math.extendPosition(x1, y1, angle, distance/2)
  262.                 imagepos(line, x, y, angle)
  263.                 imagescale(line, 1, distance)
  264.                 return line
  265.             end
  266.         }
  267.     };
  268.    
  269.     -- Table for hooked functions
  270.     hooks = {
  271.         -- Always hook
  272.         always = function()
  273.             -- Scripting NPC's behavior
  274.             for npcID, npc in pairs(cnpc.spawnedNPCs) do
  275.                 local lastClosest = npc.closestPlayer
  276.                 npc.closestPlayer = 0
  277.                 local lastDist = 240
  278.                 for _, pl in pairs(player(0, 'tableliving')) do
  279.                     local wallX, wallY = cnpc.funcs.math.wallOnLine(npc.x, npc.y, player(pl, 'x'), player(pl, 'y'))
  280.                     if wallX == -1 then
  281.                         local distance = cnpc.funcs.math.distance(npc.x, npc.y, player(pl, 'x'), player(pl, 'y'))
  282.                         if distance < lastDist then
  283.                             npc.closestPlayer = pl
  284.                             lastDist = distance
  285.                         end
  286.                     end
  287.                 end
  288.                 if npc.closestPlayer ~= 0 then
  289.                     if lastClosest ~= npc.closestPlayer then
  290.                         npc.closestPlayerLastSeen = {player(npc.closestPlayer, 'x'), player(npc.closestPlayer, 'y')}
  291.                     end
  292.                 end
  293.            
  294.                 if npc.closestPlayer > 0 then
  295.                     local angle = math.floor(cnpc.funcs.math.getAngle(npc.x, npc.y, npc.closestPlayerLastSeen[1], npc.closestPlayerLastSeen[2]))
  296.                     if (npc.lastAttack + npc.attackCoolDown < os.clock() and npc.behaviorType == 0) or (npc.behaviorType > 0) then
  297.                         if not (npc.rot <= angle + npc.rotSpeed and npc.rot >= angle - npc.rotSpeed) then
  298.                             if npc.rot > angle then
  299.                                 if math.abs(angle - npc.rot) % 360 > 180 then
  300.                                     npc.rot = npc.rot + npc.rotSpeed
  301.                                 else
  302.                                     npc.rot = npc.rot - npc.rotSpeed
  303.                                 end
  304.                             else
  305.                                 if math.abs(angle - npc.rot) % 360 > 180 then
  306.                                     npc.rot = npc.rot - npc.rotSpeed
  307.                                 else
  308.                                     npc.rot = npc.rot + npc.rotSpeed
  309.                                 end
  310.                             end
  311.                             if angle == -180 and npc.rot == 180 then npc.rot = -180 end -- This will prevent NPCs from freezing
  312.                             if npc.rot > 180 then npc.rot = npc.rot - 360 end
  313.                             if npc.rot < -180 then npc.rot = npc.rot + 360 end
  314.                             imagepos(npc.image, npc.x, npc.y, npc.rot)
  315.                         else
  316.                             if npc.timerParams == false then
  317.                                 npc.timerParams = {'parse', 'lua "cnpc.spawnedNPCs['.. npcID ..'].closestPlayerLastSeen = {'.. player(npc.closestPlayer, 'x') ..', '.. player(npc.closestPlayer, 'y') ..'} cnpc.spawnedNPCs['.. npcID ..'].timerParams = false"'}
  318.                                 timer(62.5, 'parse', npc.timerParams[2])
  319.                             end
  320.                         end
  321.                     end
  322.                    
  323.                     if (npc.rot <= angle + npc.rotSpeed and npc.rot >= angle - npc.rotSpeed) then
  324.                         if not npc.rot == angle then
  325.                             npc.rot = angle
  326.                             imagepos(npc.image, npc.x, npc.y, npc.rot)
  327.                         end
  328.                         local distance = cnpc.funcs.math.distance(npc.x, npc.y, player(npc.closestPlayer, 'x'), player(npc.closestPlayer, 'y'))
  329.                         if npc.lastAttack + npc.attackCoolDown < os.clock() then
  330.                             if npc.behaviorType == 0 and not (distance < 20) then
  331.                                 npc.x, npc.y = cnpc.funcs.math.extendPosition(npc.x, npc.y, npc.rot, npc.speed)
  332.                                 imagepos(npc.image, npc.x, npc.y, npc.rot)
  333.                             elseif npc.behaviorType == 0 and (distance < 20) then
  334.                                 cnpc.funcs.npc.attack(npcID)
  335.                             elseif npc.behaviorType == 1 and not (distance < 20) and npc.closestPlayer > 0 then
  336.                                 cnpc.funcs.npc.attack(npcID)
  337.                             end
  338.                         end
  339.                     end
  340.                 elseif npc.closestPlayer == 0 and lastClosest == 0 then
  341.                     if npc.closestPlayerLastSeen ~= false then
  342.                         if not (math.floor(npc.x/32) == math.floor(npc.closestPlayerLastSeen[1]/32) and math.floor(npc.y/32) == math.floor(npc.closestPlayerLastSeen[2]/32)) then  
  343.                             local angle = math.floor(cnpc.funcs.math.getAngle(npc.x, npc.y, npc.closestPlayerLastSeen[1], npc.closestPlayerLastSeen[2]))
  344.                             if not (npc.rot <= angle + npc.rotSpeed and npc.rot >= angle - npc.rotSpeed) then
  345.                                 if npc.rot > angle then
  346.                                     if math.abs(angle - npc.rot) % 360 > 180 then
  347.                                         npc.rot = npc.rot + npc.rotSpeed
  348.                                     else
  349.                                         npc.rot = npc.rot - npc.rotSpeed
  350.                                     end
  351.                                 else
  352.                                     if math.abs(angle - npc.rot) % 360 > 180 then
  353.                                         npc.rot = npc.rot - npc.rotSpeed
  354.                                     else
  355.                                         npc.rot = npc.rot + npc.rotSpeed
  356.                                     end
  357.                                 end
  358.                                 if angle == -180 and npc.rot == 180 then npc.rot = -180 end -- This will prevent NPCs from freezing
  359.                                 if npc.rot > 180 then npc.rot = npc.rot - 360 end
  360.                                 if npc.rot < -180 then npc.rot = npc.rot + 360 end
  361.                                 imagepos(npc.image, npc.x, npc.y, npc.rot)
  362.                             else
  363.                                 if not npc.rot == angle then
  364.                                     npc.rot = angle
  365.                                     imagepos(npc.image, npc.x, npc.y, npc.rot)
  366.                                 end
  367.                                
  368.                                 local x, y = cnpc.funcs.math.extendPosition(npc.x, npc.y, npc.rot, npc.speed)
  369.                                 if tile(math.floor((x-6)/ 32), math.floor((y-6) / 32), 'walkable') and tile(math.floor((x+6)/ 32), math.floor((y+6) / 32), 'walkable') and tile(math.floor((x-6) / 32), math.floor((y+6) / 32), 'walkable') and tile(math.floor((x+6) / 32), math.floor((y-6) / 32), 'walkable') then
  370.                                     npc.x, npc.y = cnpc.funcs.math.extendPosition(npc.x, npc.y, npc.rot, npc.speed)
  371.                                     imagepos(npc.image, npc.x, npc.y, npc.rot)
  372.                                 end
  373.                             end
  374.                         end
  375.                     end
  376.                 end
  377.             end
  378.         end;
  379.        
  380.         -- Leave hook
  381.         leave = function(id)
  382.             -- Removing timer when closest player leaves the server
  383.             for _, npc in pairs(cnpc.spawnedNPCs) do
  384.                 if npc.closestPlayer == id then
  385.                     if npc.timerParams ~= false then
  386.                         freetimer(npc.timeParams[1], npc.timeParams[2])
  387.                         npc.timerParams = false
  388.                     end
  389.                 end
  390.             end
  391.         end;
  392.        
  393.         -- Hitzone hook
  394.         hitzone = function(imageid, playerid, objectid, weapon, impactx, impacty)
  395.             -- NPC getting hit
  396.             local npc, npcID
  397.             for k, v in pairs(cnpc.spawnedNPCs) do
  398.                 if v.image == imageid then
  399.                     npc = v
  400.                     npcID = k
  401.                     break
  402.                 end
  403.             end
  404.            
  405.             npc.health = npc.health - itemtype(player(playerid, 'weapontype'), 'dmg')
  406.             if npc.health <= 0 then
  407.                 cnpc.funcs.npc.remove(npcID)
  408.                 for _, pl in pairs(player(0, 'tableliving')) do
  409.                     local x, y = player(pl, 'x'), player(pl, 'y')
  410.                     if x >= npc.x - 320 and y >= npc.y - 240 and x <= npc.x + 320 and y <= npc.y + 240 then
  411.                         parse('sv_sound2 '.. pl ..' "'.. npc.data.deathSound ..'"')
  412.                     end
  413.                 end
  414.             end
  415.         end;
  416.        
  417.         -- Trigger hook
  418.         trigger = function(trigger, source)
  419.             -- Spawning NPCs on trigger
  420.             for x = 0, map('xsize') do
  421.                 for y = 0, map('ysize') do
  422.                     if entity(x, y, 'name') == trigger and entity(x, y, 'typename') == 'Env_Item' then
  423.                         local wordTable = {}
  424.                         for word in string.gmatch(entity(x, y, 'trigger'), '[^%s]+') do
  425.                             table.insert(wordTable, word)
  426.                         end
  427.                         if wordTable[1] == 'cnpc' then
  428.                             local id, health, rot, spawn = tonumber(wordTable[2]), tonumber(wordTable[3]), tonumber(wordTable[4]), tonumber(wordTable[5])
  429.                             local error = false
  430.                            
  431.                             -- Checking entity for the errors
  432.                             local parameters = {'id', 'health', 'rot', 'spawn'}
  433.                             for k, v in pairs(parameters) do
  434.                                 if not wordTable[k+1] then
  435.                                     print(k+1)
  436.                                     error = '\169255000000Unable to spawn NPC using entity on tile \''.. x ..'|'.. y ..'\': \''.. v ..'\' parameter is not specified!'
  437.                                 end
  438.                             end
  439.                             if not error then
  440.                                 if not cnpc.list[id] then
  441.                                     error = '\169255000000Unable to spawn NPC using entity on tile \''.. x ..'|'.. y ..'\': NPC with type '.. id ..' does not exist!'
  442.                                 end
  443.                             end
  444.                            
  445.                             if not error then
  446.                                 if spawn == 1 then
  447.                                     cnpc.funcs.npc.spawn(id, x*32+16, y*32+16, rot, health == 0 and nil or health)
  448.                                 end
  449.                             else
  450.                                 print(error)
  451.                             end
  452.                         end
  453.                     end
  454.                 end
  455.             end
  456.         end;
  457.        
  458.         -- Startround hook
  459.         startround = function()
  460.             -- Despawning all the NPCs from the last round and spawning new
  461.             freetimer()
  462.             cnpc.spawnedNPCs = {}
  463.            
  464.             for x = 0, map('xsize') do
  465.                 for y = 0, map('ysize') do
  466.                     if entity(x, y, 'typename') == 'Env_Item' then
  467.                         local wordTable = {}
  468.                         for word in string.gmatch(entity(x, y, 'trigger'), '[^%s]+') do
  469.                             table.insert(wordTable, word)
  470.                         end
  471.                        
  472.                         if wordTable[1] == 'cnpc' then
  473.                             local id, health, rot, spawn = tonumber(wordTable[2]), tonumber(wordTable[3]), tonumber(wordTable[4]), tonumber(wordTable[5])
  474.                             local error = false
  475.                            
  476.                             -- Checking entity for the errors
  477.                             local parameters = {'id', 'health', 'rot', 'spawn'}
  478.                             for k, v in pairs(parameters) do
  479.                                 if not wordTable[k+1] then
  480.                                     error = '\169255000000Unable to spawn NPC using entity on tile \''.. x ..'|'.. y ..'\': \''.. v ..'\' parameter is not specified!'
  481.                                 end
  482.                             end
  483.                             if not error then
  484.                                 if not cnpc.list[id] then
  485.                                     error = '\169255000000Unable to spawn NPC using entity on tile \''.. x ..'|'.. y ..'\': NPC with type '.. id ..' does not exist!'
  486.                                 end
  487.                             end
  488.                            
  489.                             if not error then
  490.                                 if spawn == 1 then
  491.                                     cnpc.funcs.npc.spawn(id, x*32+16, y*32+16, rot, health == 0 and nil or health)
  492.                                 end
  493.                             else
  494.                                 print(error)
  495.                             end
  496.                         end
  497.                     end
  498.                 end
  499.             end
  500.         end;
  501.        
  502.         -- Parse hook
  503.         parse = function(cmd)
  504.             -- Creating console commands
  505.             local wordTable = {}
  506.             for word in string.gmatch(cmd, '[^%s]+') do
  507.                 table.insert(wordTable, word)
  508.             end
  509.            
  510.             local parameters, error, successFunction, identifier
  511.             if wordTable[1] == 'cnpc_spawn' then
  512.                 parameters = {'type', 'x', 'y', 'rot'}
  513.                 identifier = 'type'
  514.                 successFunction = function()
  515.                     cnpc.funcs.npc.spawn(tonumber(wordTable[2]), tonumber(wordTable[3]), tonumber(wordTable[4]), tonumber(wordTable[5]))
  516.                 end
  517.             elseif wordTable[1] == 'cnpc_damage' then
  518.                 parameters = {'id', 'damage'}
  519.                 identifier = 'id'
  520.                 successFunction = function()
  521.                     local npc = cnpc.spawnedNPCs[tonumber(wordTable[2])]
  522.                     npc.health = npc.health - tonumber(wordTable[3])
  523.                     if npc.health <= 0 then
  524.                         cnpc.funcs.npc.remove(tonumber(wordTable[2]))
  525.                         for _, pl in pairs(player(0, 'tableliving')) do
  526.                             local x, y = player(pl, 'x'), player(pl, 'y')
  527.                             if x >= npc.x - 320 and y >= npc.y - 240 and x <= npc.x + 320 and y <= npc.y + 240 then
  528.                                 parse('sv_sound2 '.. pl ..' "'.. npc.data.deathSound ..'"')
  529.                             end
  530.                         end
  531.                     end
  532.                 end
  533.             elseif wordTable[1] == 'cnpc_despawn' then
  534.                 parameters = {'id'}
  535.                 identifier = 'id'
  536.                 successFunction = function()
  537.                     cnpc.funcs.npc.remove(tonumber(wordTable[2]))
  538.                 end
  539.             end
  540.            
  541.             if parameters then
  542.                 for k, v in pairs(parameters) do
  543.                     if not wordTable[k+1] then
  544.                         error = '\169255000000Unable to execute \''.. wordTable[1] ..'\' command: \''.. v ..'\' parameter is not specified!'
  545.                     end
  546.                 end
  547.                 if not error then
  548.                     local i = tonumber(wordTable[2])
  549.                     if identifier == 'type' then
  550.                         if not cnpc.list[i] then
  551.                             error = '\169255000000Unable to execute \''.. wordTable[1] ..'\' command: NPC with type '.. i ..' does not exist!'
  552.                         end
  553.                     else
  554.                         if not cnpc.spawnedNPCs[i] then
  555.                             error = '\169255000000Unable to execute \''.. wordTable[1] ..'\' command: NPC with id '.. i ..' does not exist!'
  556.                         end
  557.                     end
  558.                 end
  559.                
  560.                 if not error then
  561.                     successFunction()
  562.                 else
  563.                     print(error)
  564.                 end
  565.                 return 2
  566.             end
  567.         end;
  568.     };
  569. }
  570.  
  571. -- Adding hooks
  572. addhook('always', 'cnpc.hooks.always')
  573. addhook('leave', 'cnpc.hooks.leave')
  574. addhook('hitzone', 'cnpc.hooks.hitzone')
  575. addhook('trigger', 'cnpc.hooks.trigger')
  576. addhook('startround', 'cnpc.hooks.startround')
  577. addhook('parse', 'cnpc.hooks.parse')
  578.  
  579. -- Loading up a custom NPC list
  580. dofile('sys/lua/cnpc/list.lua')
  581.  
  582. -- Checking NPC list for the errors
  583. print('\169255255255Checking NPC list for critical errors...')
  584. local errors = 0
  585. for npcType, npc in pairs(cnpc.list) do
  586.     local error = false
  587.     for _, value in pairs({'name', 'imagePath', 'deathSound', 'speed', 'rotationSpeed', 'behaviorType', 'attackCoolDown', 'health', 'damage', 'hitbox'}) do
  588.         if npc[value] == nil then
  589.             print('\169255000000Error in type '.. npcType ..': Value \''.. value ..'\' is not specified! Excluding the NPC from the list.')
  590.             cnpc.list[npcType] = nil
  591.             error = true
  592.             errors = errors + 1
  593.             break
  594.         end
  595.     end
  596.     if not error then
  597.         local parameters =  {[0] = {'slashSound'}, [1] = {'bulletLength', 'bulletSpreading', 'bulletOffset', 'bulletSound'}}
  598.         for _, value in pairs(parameters[npc.behaviorType]) do
  599.             if npc[value] == nil then
  600.                 print('\169255000000Error in checking type '.. npcType ..': Value \''.. value ..'\' is not specified! Excluding the NPC from the list.')
  601.                 cnpc.list[npcType] = nil
  602.                 error = true
  603.                 errors = errors + 1
  604.                 break
  605.             end
  606.         end
  607.     end
  608. end
  609. print(errors == 0 and '\169255255255No errors was found in the NPC list.' or '\169255000000'.. errors ..' error(s) have occured during the check! See messages above for more information!')
  610.  
  611. -- Executing "startround" hook
  612. cnpc.hooks.startround()
Add Comment
Please, Sign In to add comment