{"id":445527,"date":"2025-01-20T09:01:29","date_gmt":"2025-01-20T09:01:29","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=445527"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2025-01-20T09:01:29","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=445527","title":{"rendered":"<span>\u042f \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c Dota 2 \u0438 Plants Vs Zombies \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043c\u043e\u0434\u0430 \u0434\u043b\u044f GTA San Andreas \u043d\u0430 Lua \u0438 \u0432\u043e\u0442 \u0447\u0442\u043e \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u0448\u043b\u043e<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>&#171;\u041c\u043e\u0434\u0443\u043b\u044c\u043d\u043e\u0441\u0442\u044c&#187; \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 SA:MP<\/h2>\n<p>\u042d\u0442\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u043f\u0435\u0440\u0432\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0434\u043b\u044f GTA:SA \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0437\u0431\u0438\u0442 \u043d\u0430 \u043c\u043e\u0434\u0443\u043b\u0438. \u0421\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u044f \u0434\u0430\u0436\u0435 \u043f\u0438\u0441\u0430\u043b \u0441\u0432\u043e\u0439 \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u043b\u0443\u0430 \u0431\u0430\u043d\u0434\u043b\u0435\u0440 &#8212; LuBu (<a href=\"https:\/\/github.com\/chaposcripts\/lubu\" rel=\"noopener noreferrer nofollow\">GitHub<\/a>). \u0412\u0430\u043c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0447\u0442\u043e \u044d\u0442\u043e \u043a\u0430\u043a\u043e\u0439 \u0442\u043e \u0431\u0440\u0435\u0434, \u043d\u043e \u0432 \u043d\u0435 \u0441\u0442\u043e\u043b\u044c \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435 lua-\u0441\u043a\u0440\u0438\u043f\u0442\u0435\u0440\u043e\u0432 GTA:SA \u043f\u043e\u0447\u0435\u043c\u0443-\u0442\u043e \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u0435\u0441\u044c \u043a\u043e\u0434 \u0432 \u043e\u0434\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043e\u043d \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0442\u044b\u0441\u044f\u0447\u0438 \u0438\u043b\u0438 \u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u0442\u044b\u0441\u044f\u0447 \u0441\u0442\u0440\u043e\u043a. \u0412\u0435\u0440\u043e\u044f\u0442\u043d\u043e, \u044d\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043e \u0441 \u0430\u0443\u0434\u0438\u0442\u043e\u0440\u0438\u0435\u0439 \u044d\u0442\u043e\u0439 \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e\u0439 \u0438\u0433\u0440\u044b, \u0432\u0435\u0434\u044c \u043a\u043e\u0433\u0434\u0430 \u0434\u0432\u0435\u043d\u0430\u0434\u0446\u0430\u0442\u0438\u043b\u0435\u0442\u043d\u0438\u0439 \u0412\u043e\u0432\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043c\u0435\u0433\u0430-\u0441\u0443\u043f\u0435\u0440-\u043f\u0443\u043f\u0435\u0440 \u0447\u0438\u0442, \u0442\u043e \u0435\u0433\u043e \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u043d\u0435 \u0432\u043e\u043b\u043d\u0443\u0435\u0442 \u0447\u0438\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438 \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u043e \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430. <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0435 \u0436\u0430\u043b\u043a\u043e \u0432\u0430\u0448\u0443 \u043f\u0441\u0438\u0445\u0438\u043a\u0443, \u0442\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0443\u0436\u0430\u0441\u043d\u044b\u0445, \u0438, \u0432 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 &#8212; <a href=\"https:\/\/www.blast.hk\/threads\/89343\/\" rel=\"noopener noreferrer nofollow\">Mono Tools<\/a> (\u043a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0430\u0432\u0442\u043e\u0440 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0440\u0435\u0448\u0438\u043b \u0437\u0430\u0431\u0440\u043e\u0441\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442\u0438\u043d\u0433). \u0421\u043a\u0440\u0438\u043f\u0442 \u0432\u0435\u0441\u0438\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u043e\u043b\u0443\u0442\u043e\u0440\u0430 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442\u0430, \u0442\u0430\u043a \u0447\u0442\u043e \u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0441\u0442\u0430\u0432\u043b\u044e \u0437\u0434\u0435\u0441\u044c \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430 \u043a\u043e\u0434\u0430<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u0435\u043a\u0441\u0442<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/845\/e24\/e4a\/845e24e4aa9e799ea705cb9e54715941.png\" width=\"1880\" height=\"957\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/845\/e24\/e4a\/845e24e4aa9e799ea705cb9e54715941.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418\u0442\u0430\u043a, \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043a &#171;\u0438\u0433\u0440\u0430\u043c&#187;.<\/p>\n<h2>Defense Of The Ghetto<\/h2>\n<p><a href=\"https:\/\/github.com\/chaposcripts\/Defense-Of-The-Ghetto\" rel=\"noopener noreferrer nofollow\">\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 (\u0441\u0442\u0430\u0440\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f)<\/a> (\u043f\u0440\u043e\u0448\u0443 \u043e\u0442\u043d\u0435\u0441\u0442\u0438\u0441\u044c \u043a \u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0437\u043e\u0440\u0443 \u0441 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435\u043c)<\/p>\n<p>\u041e\u043a\u043e\u043b\u043e \u0434\u0432\u0443\u0445 \u043b\u0435\u0442 \u043d\u0430\u0437\u0430\u0434, \u0448\u0443\u0442\u043a\u0438 \u0440\u0430\u0434\u0438, \u044f \u043d\u0430\u0447\u0430\u043b \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c Defense Of The Ghetto \u043d\u0430 \u0431\u0430\u0437\u0435 GTA:SA \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e MoonLoader, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b\u043b \u043f\u0430\u0440\u043e\u0434\u0438\u0435\u0439 \u043d\u0430 \u043e\u0434\u043d\u0443 \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0438\u0433\u0440 &#8212; Defense Of The Ancients 2 (Dota2). \u0417\u0430 \u043d\u0435\u0434\u0435\u043b\u044e \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u043a\u043e\u0440\u044f\u0432\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f, \u0432 \u043d\u0435\u043c \u0431\u044b\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b: \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0438 \u0438 \u0438\u0445 \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u0438, \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u044b, \u043a\u0440\u0438\u043f\u044b, \u0431\u0430\u0448\u043d\u0438, \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0430\u0442\u0430\u043a\u0438, \u043d\u0430\u043d\u0435\u0441\u0435\u043d\u0438\u0435 \u0443\u0440\u043e\u043d\u0430 \u0438 \u043f\u0440\u043e\u0447\u0435\u0435. \u0418\u0437-\u0437\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u0431\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u0441\u0442\u0432 \u044f \u0431\u044b\u043b \u0432\u044b\u043d\u0443\u0436\u0434\u0435\u043d \u0437\u0430\u0431\u0440\u043e\u0441\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0432\u0440\u0435\u043c\u044f. \u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u0435\u043a\u0442 \u044f \u043f\u043e\u043d\u044f\u043b \u0447\u0442\u043e \u0441\u0442\u0430\u0440\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u0436\u0430\u0441\u0435\u043d \u0438 \u043d\u0435\u0443\u0434\u043e\u0431\u0435\u043d, \u0438\u0437-\u0437\u0430 \u0447\u0435\u0433\u043e \u044f \u043d\u0430\u0447\u0430\u043b \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0441 \u043d\u0443\u043b\u044f. <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0441\u0442\u0430\u0440\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0431\u044b\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0431\u044b\u043b\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 .lua \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0438 \u0437\u0430\u043a\u0438\u043d\u0443\u0442\u044c \u0435\u0433\u043e \u0432 \u043f\u0430\u043f\u043a\u0443 <code>DOTA\\heroes<\/code> , \u0432\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 Shadow Fiend:<\/p>\n<pre><code class=\"lua\">local AbilityType = require('dota.types').AbilityType; local Map = require('dota.map');  local function coil(range)     clearCharTasksImmediately(PLAYER_PED);     if not hasAnimationLoaded('carry') then         requestAnimation('carry');     end     clearCharTasksImmediately(PLAYER_PED)     taskPlayAnim(PLAYER_PED, 'putdwn105', 'carry', 0, false, true, true, true, 10000)      local x, y, z = Map.getPosFromCharVector(range);     local smoke = createObject(18686, x, y, z - 1);     Map.dealDamageToPoint(Vector3D(x, y, z));     wait(3000);     deleteObject(smoke); end  local abilities = {} for i = 3, 9, 3 do     table.insert(abilities, {         name = ('Coil (%d)'):format(i),         manaRequired = 50,         cooldown = 10,         useThread = true,         type = AbilityType.INSTANT,         onUse = function()             coil(i);         end     }); end table.insert(abilities, {     name = 'ULT',     manaRequired = 50,     cooldown = 10,     useThread = true,     type = AbilityType.INSTANT,     onUse = function()         local start = os.clock()         local ultimate_objects = {}                  for i = 0, 360, 30 do             local angle = math.rad(i) + math.pi \/ 2             local posX, posY, posZ = getCharCoordinates(PLAYER_PED)              local start = Vector3D(1 * math.cos(angle) + posX, 1 * math.sin(angle) + posY, posZ - 1)             local stop = Vector3D(20 * math.cos(angle) + posX, 20 * math.sin(angle) + posY, posZ - 1)             local handle = createObject(18686, start.x, start.y, start.z)             ultimate_objects[handle] = {                 start = start,                 stop = stop             }                      end          -- create object         while start + 4 - os.clock() &gt; 0 do             wait(0)             for handle, data in pairs(ultimate_objects) do                 if doesObjectExist(handle) then                     slideObject(handle, data.stop.x, data.stop.y, data.stop.z, 0.5, 0.5, 0.5, false)                     local result, x, y, z = getObjectCoordinates(handle);                     if result then                         Map.dealDamageToPoint(Vector3D(x, y, z), 55);                     end                 end             end         end         for handle, data in pairs(ultimate_objects) do             if doesObjectExist(handle) then                 deleteObject(handle)                 ultimate_objects[handle] = nil             end         end     end });  ---@type Hero local shadow_fiend = {     type = require('dota.types').HeroType,     name = 'Shadow Fiend',     model = 5,     abilities = abilities,     stats = {         maxHealth = 1300,         maxMana = 200,         healthRegen = 2,         manaRegen = 3,         damage = 10,         attackSpeed = 10,         speed = 0,         attackRange = 1,     } };  return shadow_fiend;<\/code><\/pre>\n<p>\u041f\u043e\u0434\u0433\u0440\u0443\u0437\u043a\u0430 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439 \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u0430 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"lua\">---@meta local Utils = require('dota.utils'); local mimgui = require('mimgui'); local ffi = require('ffi');  local PLACEHOLDER_IMAGE = ''; local Heroes = {     basePath = getWorkingDirectory() .. '\\\\dota\\\\heroes',     list = {} };  --- Load heroes images (avatars) and abilities icons --- CALL IN mimgui.OnInitialize function Heroes.loadImages()     for codename, data in pairs(Heroes.list) do         local imageBase85 = data.imageBase85 or PLACEHOLDER_IMAGE;         Heroes.list[codename].image = imgui.CreateTextureFromFileInMemory(imgui.new('const char*', imageBase85), #imageBase85);          --\/\/ abilities         for abilityCodename, ability in pairs(data.abilities) do             local imageBase85 = data.imageBase85 or PLACEHOLDER_IMAGE;             Heroes.list[codename].abilities[abilityCodename] = imgui.CreateTextureFromFileInMemory(imgui.new('const char*', imageBase85), #imageBase85);         end     end end  --- Load heroes list in &lt;HEROES&gt;.list function Heroes.init()     for _, fileName in pairs(Utils.getFilesInPath(Heroes.basePath, '*.lua')) do         if (fileName ~= 'init.lua') then             print(fileName);             local codeName = fileName:gsub('.lua', '');             Heroes.list[codeName] = require('dota.heroes.' .. codeName);             print('hero loaded', codeName);         end     end end  return Heroes;<\/code><\/pre>\n<p>\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e (\u0438\u043b\u0438 \u043a \u0441\u0447\u0430\u0441\u0442\u044c\u044e), \u043f\u0440\u043e\u0435\u043a\u0442 \u0431\u044b\u043b \u0437\u0430\u0431\u0440\u043e\u0448\u0435\u043d \u0432 \u0441\u0432\u044f\u0437\u0438 \u0441 \u043e\u0441\u0435\u043d\u043d\u0438\u043c \u043f\u0440\u0438\u0437\u044b\u0432\u043e\u043c, \u0430 \u0441\u043f\u0443\u0441\u0442\u044f \u0433\u043e\u0434 \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u044d\u0442\u043e\u0439 \u0438\u0434\u0435\u0435. \u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0431\u044b\u043b \u0443\u0442\u0435\u0440\u044f\u043d.<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/678944e8bfebf17680855696\" data-style=\"\" id=\"678944e8bfebf17680855696\" width=\"\"><\/div>\n<h2>Plants Vs Zombies<\/h2>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 GitHub: <a href=\"https:\/\/github.com\/chaposcripts\/gta-sa-plants-vs-zombies\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/chaposcripts\/gta-sa-plants-vs-zombies<\/a>.<\/p>\n<h3>\u041a\u0440\u0430\u0442\u043a\u0430\u044f \u043f\u0440\u0435\u0434\u044b\u0441\u0442\u043e\u0440\u0438\u044f<\/h3>\n<p>\u0412\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0441\u0440\u043e\u0447\u043a\u0438, \u043f\u0440\u0435\u0440\u0432\u0430\u0432\u0448\u0435\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 DOTG \u0443 \u043c\u0435\u043d\u044f \u0431\u044b\u043b\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043f\u043e\u0434\u0443\u043c\u0430\u0442\u044c, \u0442\u0430\u043a \u0438 \u043f\u0440\u0438\u0448\u043b\u0430 \u0432 \u0433\u043e\u043b\u043e\u0432\u0443 \u0438\u0434\u0435\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u043e\u0435 &#171;\u0447\u0443\u0434\u043e&#187;. \u0418\u043c\u0435\u044f \u043f\u0440\u0438 \u0441\u0435\u0431\u0435 \u0431\u043b\u043e\u043a\u043d\u043e\u0442 \u0438 \u043a\u0430\u0440\u0430\u043d\u0434\u0430\u0448 \u044f \u0443\u0436\u0435 \u0442\u043e\u0433\u0434\u0430 \u043d\u0430\u0447\u0430\u043b \u043d\u0430\u043a\u0438\u0434\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u043a \u0441\u043b\u043e\u0432\u0443, \u043d\u0438 \u043e\u0434\u043d\u0430 \u0438\u0437 \u043d\u0438\u0445 \u043d\u0435 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u043b\u0430\u0441\u044c. <\/p>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0434\u0430\u043d\u043d\u0443\u044e \u0438\u0434\u0435\u044e \u044f \u0431\u0435\u0440\u0435\u0433 \u043d\u0430 \u043a\u043e\u043d\u043a\u0443\u0440\u0441, \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u043c \u0444\u043e\u0440\u0443\u043c\u0435 \u0432 \u0441\u0444\u0435\u0440\u0435 SA:MP, \u043e\u0434\u043d\u0430\u043a\u043e \u0438\u0437-\u0437\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u0431\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u0441\u0442\u0432 \u043a\u043e\u043d\u043a\u0443\u0440\u0441 \u0432 2024 \u0433\u043e\u0434\u0443 \u0431\u044b\u043b \u043e\u0442\u043c\u0435\u043d\u0435\u043d. \u0412\u0430\u043c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0447\u0442\u043e \u044d\u0442\u0430 \u0438\u0434\u0435\u044f \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u043b\u0430\u0431\u0430 \u0434\u043b\u044f \u0443\u0447\u0430\u0441\u0442\u0438\u044f \u0432 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u043a\u043e\u043d\u043a\u0443\u0440\u0441\u0430\u0445, \u043e\u0434\u043d\u0430\u043a\u043e \u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0446\u0438\u044f \u0442\u0430\u043c \u043d\u0435 \u0432\u0435\u043b\u0438\u043a\u0430, \u0441\u0443\u043c\u043c\u0430 \u043f\u0440\u0438\u0437\u043e\u0432\u044b\u0445 \u0432 2023 \u0433\u043e\u0434\u0443 \u0434\u043e\u0441\u0442\u0438\u0433\u043b\u0430 \u0431\u043e\u043b\u0435\u0435 500.000 \u0440\u0443\u0431\u043b\u0435\u0439, \u0430 \u0432 2022 \u0433\u043e\u0434\u0443 \u044f \u0437\u0430\u043d\u044f\u043b \u043f\u0440\u0438\u0437\u043e\u0432\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u0432 <a href=\"https:\/\/www.blast.hk\/threads\/154592\/\" rel=\"noopener noreferrer nofollow\">Subway-CJ<\/a> &#8212; \u043f\u0430\u0440\u043e\u0434\u0438\u044e \u043d\u0430 \u0438\u0433\u0440\u0443 Subway Surfers \u0432 GTA:SA.<\/p>\n<h3>\u041a\u043b\u0430\u0441\u0441\u044b \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439<\/h3>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a MoonLoader API \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u043d\u0435 \u0434\u0440\u0443\u0436\u0438\u0442 \u0441 \u041e\u041e\u041f, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043d\u0430\u0447\u0430\u0442\u044c \u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0441\u0435\u0432\u0434\u043e\u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 \u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430\u043c\u0438. \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u0438 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"lua\">Object object = createObject(Model modelId, float atX, float atY, float atZ)  -- 0107 setObjectHeading(Object object, float angle)  -- 0177 setObjectRotation(Object object, float rotationX, float rotationY, float rotationZ)  -- 0453 setObjectPathSpeed(int int1, int int2)  -- 049E setObjectPathPosition(int int1, float float2)  -- 049F setObjectScale(Object object, float scale)  -- 08D2 bool result = setObjectCoordinates(Object object, float atX, float atY, float atZ)  -- 01BC setObjectVelocity(Object object, float velocityInDirectionX, float velocityInDirectionY, float velocityInDirectionZ)  -- 0381 setObjectCollision(Object object, bool collision)  -- 0382<\/code><\/pre>\n<p>\u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u0430\u0442\u0430\u0431\u043b\u0438\u0446 \u044f \u0441\u043e\u0437\u0434\u0430\u043b &#171;\u043a\u043b\u0430\u0441\u0441&#187; Object, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u043d\u0435 \u0441\u0442\u0430\u043b\u043e \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u043f\u0440\u043e\u0449\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438<\/p>\n<details class=\"spoiler\">\n<summary>object.lua<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"lua\">local Vector3D = require('vector3d'); local Object = {}; local pool = {};  addEventHandler('onScriptTerminate', function(scr)     if (scr == thisScript()) then         for k, v in ipairs(pool) do             v:destroy();         end     end end);  ---@class Object ---@field handle number ---@field tag string ---@field setCollision fun(self: Object, collision: boolean) ---@field destroy fun(self: Object) ---@field setScale fun(self: Object, scale: number) ---@field setRotation fun(self: Object, rotation: Vector3D) ---@field setPosition fun(self: Object, position: Vector3D)  setmetatable(Object, {__call = function(t, ...)     return t:new(...) end});  function Object:setCollision(bool)     self.collision = bool;     setObjectCollision(self.handle, bool); end  function Object:setRotation(rotation)     self.rotation = rotation;     setObjectRotation(self.handle, rotation.x, rotation.y, rotation.z); end  function Object:setPosition(pos)     self.pos = pos;     setObjectCoordinates(self.handle, pos.x, pos.y, pos.z); end  function Object:destroy()     deleteObject(self.handle);     print('Object:destroy(), handle =', self.handle);     for index, handle in ipairs(pool) do         if (handle == self.handle) then             table.remove(pool, index);         end     end end  function Object:setScale(scale)     self.scale = scale;     setObjectScale(self.handle, scale); end  function Object:new(model, pos, rotation, collision, scale, tag)     local handle = createObject(model, pos.x, pos.y, pos.z)     assert(doesObjectExist(handle), 'Error creating object.');     if (rotation) then         setObjectRotation(handle, rotation.x, rotation.y, rotation.z);     end     setObjectCollision(handle, collision);     setObjectScale(handle, scale or 1);     print('Object:new(), handle = ', handle);     local instance = {         handle = handle,         tag = tag or '',         scale = scale or 1,         collision = collision,         rotation = rotation or Vector3D(0, 0, 0)     };     local meta = setmetatable(instance, {__index = self})     table.insert(pool, meta);     return meta; end  return Object;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0437\u0436\u0435 \u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0432 &#171;\u043c\u043e\u0434\u0443\u043b\u0435&#187; Map, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043a\u0430\u0440\u0442\u043e\u0439.<\/p>\n<pre><code class=\"lua\">local Object = require('object'); ... function Map.destroy()     ...     print('deleting all objects, count:', #Map.pool);     for _, object in pairs(Map.pool) do         print('deleting obj', object.handle);         object:destroy();     end end  function Map.init()     -- Create ground (grass)     table.insert(Map.pool, Object:new(19550, Map.pos, Vector3D(0, 0, 0), true, 1, 'floor'));          -- Create house     table.insert(Map.pool, Object:new(3639, Vector3D(Map.pos.x - 15, Map.pos.y + 10, Map.pos.z), Vector3D(0, 0, 90), true, 1, 'house'));      -- Create grid     for line = 1, 5 do         for section = 1, 9 do             if ((line % 2 == 0 and section % 2 == 0) or (line % 2 == 1 and section % 2 == 1)) then -- (line % 2 == section % 2) then                 table.insert(                     Map.pool,                     Object:new(                         19790,                         Vector3D(Map.pos.x + GRID_SIZE * (section - 1), Map.pos.y + GRID_SIZE * (line - 1), Map.pos.z - 4.9),                         Vector3D(0, 0, 0),                         false,                         1,                         'floor' .. line .. section                     )                 );             end         end     end end ...<\/code><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/61c\/3d0\/efd\/61c3d0efdd448d84413ca36cb242b869.png\" width=\"1280\" height=\"719\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/61c\/3d0\/efd\/61c3d0efdd448d84413ca36cb242b869.png\"\/><\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u044f \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043b \u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 Enemy, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u043b \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0432\u0440\u0430\u0433\u0430\u043c\u0438.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u0431\u044b\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u0430, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0430\u044f \u043f\u0435\u0440\u0435\u0447\u0435\u043d\u044c \u0432\u0441\u0435\u0445 &#171;\u0432\u0440\u0430\u0433\u043e\u0432&#187; \u0438 \u0438\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a: \u0438\u043c\u044f, \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u0435, \u0430\u0439\u0434\u0438 \u043c\u043e\u0434\u0435\u043b\u0438, \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0430\u0442\u0430\u043a\u0438, \u043e\u0440\u0443\u0436\u0438\u0435 \u0438 \u0442.\u0434. <\/p>\n<pre><code class=\"lua\">---@enum EnemyType local EnemyType = {     Default = 1 };  ---@class EnemyData ---@field name string ---@field model number ---@field maxHealth number ---@field attackAnimation? Animation ---@field attackInterval? number ---@field weapon? number ---@field animationSpeed? number ---@field lastAttackTime? number  ---@type table&lt;EnemyType, EnemyData&gt; local EnemyData = {     [EnemyType.Default] = {         model = 267,         name = 'placeholder',         maxHealth = 100     } };<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u043c\u0435\u0442\u043e\u0434 <code>init<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434\u0433\u0440\u0443\u0436\u0430\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439 \u0438 \u043e\u0440\u0443\u0436\u0438\u044f, \u0430 \u0442\u0430\u043a \u0436\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438. \u0422\u0430\u043a \u0436\u0435 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 <code>init<\/code> \u0431\u044b\u043b \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439 \u0435\u0441\u043b\u0438 \u0441\u043a\u0440\u0438\u043f\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u0441\u044f \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 \u0438\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0431\u044b\u043b \u0432\u044b\u0433\u0440\u0443\u0436\u0435\u043d. \u0412\u0435\u0440\u043e\u044f\u0442\u043d\u043e, \u0431\u043e\u043b\u0435\u0435 \u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0431\u044b\u043b\u043e \u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>destroy()<\/code>, \u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0437\u0430\u043f\u0438\u0445\u043d\u0443\u0442\u044c \u0432 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043e\u0434\u043d\u0430\u043a\u043e \u044d\u0442\u0430 \u0438\u0434\u0435\u044f \u043f\u0440\u0438\u0448\u043b\u0430 \u043c\u043d\u0435 \u0432 \u0433\u043e\u043b\u043e\u0432\u0443 \u043f\u043e\u0441\u043b\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. <\/p>\n<pre><code class=\"lua\">function Enemies.init()     for _, v in pairs(EnemyData) do         if (not hasModelLoaded(v.model)) then             requestModel(v.model);             loadAllModelsNow();             print('Model', v.model, 'was loaded.');         end     end      addEventHandler('onScriptTerminate', function(scr)         if (scr == thisScript()) then             for _, v in ipairs(Enemies.pool) do                 v:destroy();                 print('Destroyed enemy', v.handle);             end         end     end); end<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u044f \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043b \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e &#171;\u043a\u043b\u0430\u0441\u0441\u0430&#187; <code>Enemies.Enemy<\/code>. \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u0431\u044b\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u044b \u0442\u0430\u043a\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u0430\u043a:<\/p>\n<ul>\n<li>\n<p><code>new()<\/code> &#8212; \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e &#171;\u0432\u0440\u0430\u0433\u0430&#187;<\/p>\n<pre><code class=\"lua\">---@param type EnemyType ---@param line number ---@param disableMovement? boolean function Enemies.Enemy:new(type, line, disableMovement)     assert(EnemyData[type], 'Unknown enemy type: ' .. type);     local instance = Utils.copyTable(EnemyData[type]);     local spawnPos = Map.getGridPos(line, 10);     spawnPos.z = spawnPos.z + 1;     local ped = createChar(4, instance.model, spawnPos.x, spawnPos.y, spawnPos.z - 2); ---@diagnostic disable-line     freezeCharPosition(ped, false);     -- taskWanderStandard(ped);     clearCharTasksImmediately(ped);     setCharCoordinates(ped, getCharCoordinates(ped));     setCharHeading(ped, 90);     instance.x = spawnPos.x;     instance.lastXUpdate = os.clock();     instance.health = instance.maxHealth;     instance.handle = ped; ---@diagnostic disable-line     instance.line = line;     instance.lastAttack = os.clock();     instance.route = {         from = spawnPos,         to = Map.getGridPos(line, 0)     };     instance.grid = {         line = line     };     instance.spawnedAt = os.clock();     instance.disableProcess = disableMovement;     -- instance.startDist = self:getDistanceToFinish();     if (not disableMovement) then         -- taskCharSlideToCoord(ped, 0, 0, 0, 0, 1);     end     local newMeta = setmetatable(instance, {__index = self});     newMeta.startDist = newMeta:getDistanceToFinish();     table.insert(Enemies.pool, newMeta);     Utils.msg('new enemy spawned, pool len:', #Enemies.pool);     return newMeta; end<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p><code>destroy()<\/code> &#8212; \u043f\u043e\u043b\u043d\u043e\u0435 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430<\/p>\n<pre><code class=\"lua\">function Enemies.Enemy:destroy()     if (doesCharExist(self.handle)) then         deleteChar(self.handle);         print('Enemy was destroyed, handle = ', self.handle);     end end<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p><code>process()<\/code> &#8212; \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043b\u043e\u0433\u0438\u043a\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 (\u0445\u043e\u0434\u044c\u0431\u0430, \u043f\u043e\u0438\u0441\u043a \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0439 \u0446\u0435\u043b\u0438, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u0438 \u0442.\u0434.)<\/p>\n<pre><code class=\"lua\">function Enemies.Enemy:process()     local newPos, changed = Utils.bringVec3To(self.route.from, self.route.to, self.spawnedAt, 5);     self:setCoordinates(newPos);     if (not changed) then print('Enemies.Enemy:process()', newPos) end     -- Some logic here end<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p><code>death()<\/code> &#8212; \u0441\u043a\u0440\u044b\u0442\u0438\u0435 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u044b \u044d\u043a\u0440\u0430\u043d\u0430 \u0438\u0433\u0440\u043e\u043a\u0430 \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0433\u043e \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f<\/p>\n<pre><code class=\"lua\">function Enemies.Enemy:death()     setCharCoordinates(self.handle, 0, 0, -100);     ... end<\/code><\/pre>\n<\/p>\n<\/li>\n<li>\n<p><code>setCoordinates()<\/code> &#8212; \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u0434\u043b\u044f \u0438\u043c\u0438\u0442\u0430\u0446\u0438\u0438 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f. \u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0430\u043a \u043a\u0430\u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a SA:MP &#171;\u0432\u044b\u043a\u043b\u044e\u0447\u0438\u043b \u043c\u043e\u0437\u0433\u0438&#187; \u0432\u0441\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u043c NPC. \u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>setCharCoordinates<\/code> \u043f\u0440\u0438 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0435 \u0441\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0439 \u043c\u0435\u0442\u043e\u0434 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430 \u0431\u044b\u043b \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0431\u043e\u043b\u0435\u0435-\u043c\u0435\u043d\u0435\u0435 \u0430\u0434\u0435\u043a\u0432\u0430\u0442\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b<\/p>\n<pre><code class=\"lua\">---@param pos Vector3D function Enemies.Enemy:setCoordinates(pos)     pos.z = Map.pos.z + 1;     local ptr = getCharPointer(self.handle);     if (not ptr) then         return print('WARNING, unable to set entity coordinates, ptr == nil, handle =', self.handle);     end      local matrixPtr = readMemory(ptr + 0x14, 4, false);     if (matrixPtr == 0) then         return print('WARNING, unable to set entity coordinates, matrix pointer == nil, handle =', self.handle);     end          local posPtr = matrixPtr + 0x30;     writeMemory(posPtr + 0, 4, representFloatAsInt(pos.x), false);     writeMemory(posPtr + 4, 4, representFloatAsInt(pos.y), false);     writeMemory(posPtr + 8, 4, representFloatAsInt(pos.z), false); end<\/code><\/pre>\n<\/p>\n<\/li>\n<\/ul>\n<h3>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 GUI<\/h3>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0431\u044b\u043b\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <a href=\"https:\/\/www.blast.hk\/threads\/66959\/\" rel=\"noopener noreferrer nofollow\">mimgui <\/a>&#8212; \u043b\u0443\u0430 \u0431\u0438\u043d\u0434\u0438\u043d\u0433\u0438 \u0432\u0441\u0435\u043c \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\u0433\u043e <a href=\"https:\/\/github.com\/ocornut\/imgui\" rel=\"noopener noreferrer nofollow\">Dear ImGui<\/a>.<\/p>\n<p>\u0412 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0431\u044b\u043b\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 mimgui \u0438 \u0441\u043e\u0437\u0434\u0430\u043d \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 &#171;\u0444\u0440\u0435\u0439\u043c&#187;, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0434\u0430\u043b\u0435\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u0441\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b:<\/p>\n<pre><code class=\"lua\">imgui.OnInitialize(function()     imgui.GetIO().IniFilename = nil;     uiComponents.logo.texture = imgui.CreateTextureFromFileInMemory(imgui.new('const char*', uiComponents.logo.base85), #uiComponents.logo.base85);      Heroes.loadTextures();      local style = imgui.GetStyle();     style.WindowBorderSize = 5;     style.WindowRounding = 10;     style.FrameRounding = 5;      local colors = style.Colors;     colors[imgui.Col.Border] = imgui.ImVec4(0.57, 0.26, 0.11, 1);     colors[imgui.Col.WindowBg] = imgui.ImVec4(0.35, 0.16, 0.06, 1);     colors[imgui.Col.ChildBg] = imgui.ImVec4(0.95, 0.94, 0.89, 1); end);  imgui.OnFrame(     function() return Game.state ~= GameState.None end,     function(thisWindow)         thisWindow.HideCursor = true;          table.foreach(Enemies.pool, function(k, v)             uiComponents.healthBar(v, true);         end);         table.foreach(Heroes.pool, function(k, v)             uiComponents.healthBar(v, false);         end);                  local res = imgui.ImVec2(getScreenResolution());         local style = imgui.GetStyle();         if (Game.state == GameState.Menu) then             uiComponents.mainMenu(res, style, uiComponents.logo.texture, { ---@diagnostic disable-line                 onExit = function()                     Game.state = GameState.None;                 end,                 onPlay = function()                     Game.start();                 end             });         elseif (Game.state == GameState.Playing) then             uiComponents.gameInterface(                 res,                 style, ---@diagnostic disable-line                 Heroes.list,                 Game.money,                 function(heroIndex)                     Utils.msg('clicked');                     local hero = Heroes.list[heroIndex];                     if (not hero) then                         return Utils.msg('Error, invalid hero index!');                     end                     if (Game.money &gt;= hero.price) then                         Game.heroToPlace = hero;                         Utils.msg('Place hero to any grid section. Click RMB to cancel.');                     else                         sampAddChatMessage('Dear Retard, you have not enough money to purchase this hero!', -1);                     end                 end             );         end     end );<\/code><\/pre>\n<p>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u044f \u0440\u0435\u0448\u0438\u043b \u0440\u0430\u0441\u043f\u0438\u0445\u0430\u0442\u044c \u043f\u043e \u0440\u0430\u0437\u043d\u044b\u043c \u043c\u043e\u0434\u0443\u043b\u044f\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b <code>ui\\game-interface.lua<\/code> &#8212; \u043c\u043e\u0434\u0443\u043b\u044c \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430. \u041e\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043b\u0430: \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430, \u0441\u0442\u0438\u043b\u044c ImGui, \u0441\u043f\u0438\u0441\u043e\u043a \u0433\u0435\u0440\u043e\u0435\u0432, \u0434\u0435\u043d\u044c\u0433\u0438 \u0438\u0433\u0440\u043e\u043a\u0430 \u0438 \u043a\u043e\u043b\u043b\u0431\u0435\u043a-\u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u0430\u0441\u044c \u043f\u0440\u0438 \u0432\u044b\u0431\u043e\u0440\u0435 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430.<\/p>\n<pre><code class=\"lua\">local imgui = require('mimgui');  ---@param res ImVec2 ---@param style imgui.Style ---@param heroes any return function(res, style, heroes, money, cb)     local heroIconSize = imgui.ImVec2(75, 75);     imgui.SetNextWindowPos(imgui.ImVec2(res.x \/ 2, 100), imgui.Cond.Always, imgui.ImVec2(0.5, 0));     if (imgui.Begin('plants-vs-zombies-gui', nil, imgui.WindowFlags.NoDecoration + imgui.WindowFlags.AlwaysAutoResize)) then         local fgdl = imgui.GetForegroundDrawList();         local heroInfoSize = imgui.ImVec2(75, 100);          imgui.PushStyleVarVec2(imgui.StyleVar.WindowPadding, imgui.ImVec2(0, 0));         imgui.PushStyleColor(imgui.Col.ChildBg, style.Colors[imgui.Col.WindowBg]);         if (imgui.BeginChild('money', heroInfoSize, true)) then             local dl = imgui.GetWindowDrawList();             local cursorPos = imgui.GetCursorScreenPos();             fgdl:AddCircleFilled(cursorPos + imgui.ImVec2(heroInfoSize.x \/ 2, heroInfoSize.y \/ 2 - 15), 30, imgui.GetColorU32Vec4(style.Colors[imgui.Col.Border]), 50);             fgdl:AddRectFilled(cursorPos + imgui.ImVec2(0, 75), cursorPos + imgui.ImVec2(heroInfoSize.x, 75 + 25), 0xFFffffff, 5);             local moneySize = imgui.CalcTextSize(tostring(money));             fgdl:AddText(cursorPos + imgui.ImVec2(heroInfoSize.x \/ 2 - moneySize.x \/ 2, 80), 0xFF000000, tostring(money));         end         imgui.EndChild();         imgui.PopStyleColor();          for index, hero in pairs(heroes) do             imgui.SameLine();             local pStart = imgui.GetCursorScreenPos();             if (imgui.BeginChild('hero-' .. index, imgui.ImVec2(75, 100), true)) then                 local dl = imgui.GetWindowDrawList();                 local p = imgui.GetCursorScreenPos();                 dl:AddImage(hero.texture, p, p + imgui.ImVec2(75, 75));                 local color = imgui.GetColorU32Vec4(style.Colors[imgui.Col.ChildBg]);                 dl:AddRectFilledMultiColor(p + imgui.ImVec2(0, 60), p + imgui.ImVec2(75, 100), 0x00ffffff, 0x00ffffff, color, color);                 local nameSize = imgui.CalcTextSize(hero.name);                 dl:AddText(p + imgui.ImVec2(75 \/ 2 - nameSize.x \/ 2, 65), 0xFF000000, hero.name);                 local priceSize = imgui.CalcTextSize(tostring(hero.price));                 dl:AddText(p + imgui.ImVec2(75 \/ 2 - priceSize.x \/ 2, 80), 0xFF000000, tostring(hero.price));             end             imgui.EndChild();             if (imgui.IsMouseClicked(0) and imgui.IsMouseHoveringRect(pStart, pStart + imgui.ImVec2(75, 100))) then                 cb(index);             end         end         imgui.PopStyleVar();     end     imgui.EndChild(); end <\/code><\/pre>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043b\u043e\u0433\u043e\u0442\u0438\u043f \u0434\u043b\u044f \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044e \u044f &#171;\u0441\u0436\u0430\u043b&#187; \u0432 base85 \u0438 \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u043b \u0432 <code>resource<\/code>. <\/p>\n<figure class=\"bordered\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/680\/1d6\/149\/6801d614959c6b2a4510581569c8f956.png\" alt=\"\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u043c\u0435\u043d\u044e\" title=\"\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u043c\u0435\u043d\u044e\" width=\"437\" height=\"238\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/680\/1d6\/149\/6801d614959c6b2a4510581569c8f956.png\"\/><\/p>\n<div><figcaption>\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u043c\u0435\u043d\u044e<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b3a\/5ed\/08b\/b3a5ed08b7b0f7beb325e2d0ae9a9d3e.png\" alt=\"\u041c\u0435\u043d\u044e \u0432\u044b\u0431\u043e\u0440\u0430 \u0440\u0430\u0441\u0442\u0435\u043d\u0438\u044f\" title=\"\u041c\u0435\u043d\u044e \u0432\u044b\u0431\u043e\u0440\u0430 \u0440\u0430\u0441\u0442\u0435\u043d\u0438\u044f\" width=\"526\" height=\"138\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b3a\/5ed\/08b\/b3a5ed08b7b0f7beb325e2d0ae9a9d3e.png\"\/><\/p>\n<div><figcaption>\u041c\u0435\u043d\u044e \u0432\u044b\u0431\u043e\u0440\u0430 \u0440\u0430\u0441\u0442\u0435\u043d\u0438\u044f<\/figcaption><\/div>\n<\/figure>\n<h3>&#171;\u0420\u0430\u0441\u0442\u0435\u043d\u0438\u044f&#187;<\/h3>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u00ab\u0440\u0430\u0441\u0442\u0435\u043d\u0438\u0439\u00bb (\u0434\u0430\u043b\u0435\u0435 \u044f \u0431\u0443\u0434\u0443 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0445 \u00ab\u0433\u0435\u0440\u043e\u044f\u043c\u0438\u00bb \u0438\u043b\u0438 \u00ab\u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430\u043c\u0438\u00bb) \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0443, \u043f\u043e\u0434\u043e\u0431\u043d\u0443\u044e \u0442\u043e\u0439, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u044f \u043f\u0438\u0441\u0430\u043b \u043f\u0440\u0438\u00a0\u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0435 DOTG.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c <code>heroes.lua<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u044f \u043f\u043e\u043c\u0435\u0449\u0443 \u043a\u043b\u0430\u0441\u0441 <code>Hero<\/code>. \u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u0438\u043c\u0435\u0435\u0442 \u0442\u0430\u043a\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043a\u0430\u043a: <\/p>\n<ul>\n<li>\n<p><code>init()<\/code> &#8212; \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0432\u0441\u0435\u0445 \u0433\u0435\u0440\u043e\u0435\u0432<\/p>\n<\/li>\n<li>\n<p><code>loadTextures()<\/code> &#8212; \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0442\u0435\u043a\u0441\u0442\u0443\u0440 \u0433\u0435\u0440\u043e\u0435\u0432 \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 ImGui. \u0412\u0441\u0435 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0431\u044b\u043b\u0438 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432 Base85 \u0438 \u0432\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0432 \u043f\u043e\u043b\u0435 <code>hero.imageBase85<\/code> <\/p>\n<\/li>\n<li>\n<p><code>process()<\/code> &#8212; \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u043d\u0430 \u0431\u0430\u0437\u043e\u0432\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0433\u0435\u0440\u043e\u0435\u0432, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u043e\u0438\u0441\u043a \u0446\u0435\u043b\u0438 \u0434\u043b\u044f \u0430\u0442\u0430\u043a\u0438, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0430\u0442\u0430\u043a\u0438, \u0432\u044b\u0437\u043e\u0432 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 <code>hero.onAttack()<\/code>)<\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u043b\u0430\u0441\u0441 <code>Heroes.Hero<\/code> \u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0438 \u043f\u043e\u043b\u044f:<\/p>\n<pre><code class=\"lua\">---@class Hero ---@field name string ---@field maxHealth number ---@field handle number ---@field price number ---@field health? number ---@field attackAnimation? Animation ---@field attackInterval? number ---@field lastAttack? number ---@field noTargetRequired? boolean ---@field onTick? fun() ---@field onTargetFound? fun(self: Hero, target: Enemy) ---@field onDamageReceived? fun(self: Hero, damage: number, from: Enemy) ---@field onDeath? fun(self: Hero, damage: number, enemy: Enemy) ---@field findTarget fun(self: Hero, targets: {target: Enemy, distance: number}[]) ---@field drawDebugInfo fun(self: Hero) ---@field destroy fun(self: Hero) ---@field die fun(self: Hero) ---@field dealDamage fun(self: Hero, damage: number, from: Enemy) ---@field storage? table&lt;any, any&gt;<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u044b \u043c\u043e\u0433\u043b\u0438 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u043c\u043d\u043e\u0433\u0438\u0435 \u043f\u043e\u043b\u044f \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c\u0438, \u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u043e\u043f\u0440\u043e\u0441\u0442\u0443 \u043d\u0435 \u043d\u0443\u0436\u043d\u044b \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440  \u043c\u0435\u0442\u043e\u0434 <code>onDamageReceived<\/code> \u043c\u043d\u0435 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u043b\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 &#171;\u043e\u0440\u0435\u0445&#187;, \u0447\u0442\u043e \u0431\u044b \u043e\u043d \u0441\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u043b \u0431\u0440\u043e\u043d\u0435\u0436\u0438\u043b\u0435\u0442 \u0435\u0441\u043b\u0438 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0435\u0433\u043e \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u044f &lt; 50% (\u0432 \u0438\u0433\u0440\u0435 2 \u043c\u043e\u0434\u0435\u043b\u044c\u043a\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0438 \u0442\u043e\u0433\u043e \u0436\u0435 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430, \u043e\u0434\u043d\u0430 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0432 \u0431\u0440\u043e\u043d\u0435):<\/p>\n<pre><code class=\"lua\">local ffi = require('ffi'); local hero = {     ...     attackInterval = math.huge     ... };  local CPed_SetModelIndex = ffi.cast('void(__thiscall *)(void*, unsigned int)', 0x5E4880);  function setCharModel(ped, model)     assert(doesCharExist(ped), 'invalid ped');     if (not hasModelLoaded(model)) then         requestModel(model);         loadAllModelsNow();     end     CPed_SetModelIndex(ffi.cast('void*', getCharPointer(ped)), ffi.cast('unsigned int', model)); end  function hero:onDamageReceived(damage, from)     if (self.health &lt;= self.maxHealth \/ 2) then        setCharModel(self.handle, 269);     end end  return hero;<\/code><\/pre>\n<p>\u0410 \u044d\u0442\u043e \u043f\u043e\u0434\u0441\u043e\u043b\u043d\u0443\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043c\u0435\u0441\u0442\u043e \u0430\u0442\u0430\u043a\u0438 \u0432\u0440\u0430\u0433\u043e\u0432 \u043f\u043b\u044e\u0435\u0442 \u0438\u0433\u0440\u043e\u0432\u044b\u043c\u0438 \u043c\u043e\u043d\u0435\u0442\u0430\u043c\u0438 \u043a\u0430\u0436\u0434\u044b\u0435 15 \u0441\u0435\u043a\u0443\u043d\u0434.<\/p>\n<pre><code class=\"lua\">... local sunflower = {     attackInterval = 15,     ...     damage = 0 };  function sunflower:onAttack(wasAnimationPlayed)     local x, y, z = getCharCoordinates(self.handle);     Object:new(1247, Vector3D(x, y, z + 2), nil, true, 1, 'sunflower'); end ...<\/code><\/pre>\n<p>\u0427\u0442\u043e \u0431\u044b \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e<\/p>\n<pre><code class=\"lua\">function Heroes.Hero:call(fn, ...)     return type(self[fn]) == 'function' and self[fn](self, ...) or nil; end<\/code><\/pre>\n<h2>\u041f\u043e\u0438\u0441\u043a \u0446\u0435\u043b\u0435\u0439 \u0434\u043b\u044f \u0430\u0442\u0430\u043a\u0438<\/h2>\n<p>\u041f\u043e\u0440\u0430 \u0431\u044b \u0443\u0436\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043b\u043e\u0433\u0438\u043a\u0438 \u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043c\u0435\u0445\u0430\u043d\u0438\u043a. \u041d\u0430\u0447\u0430\u043b \u044f \u0441 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043f\u043e\u0438\u0441\u043a\u0430 \u0446\u0435\u043b\u0438 \u0434\u043b\u044f &#171;\u0440\u0430\u0441\u0442\u0435\u043d\u0438\u0439&#187;. \u0421\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u043d\u0435 \u0442\u0430\u043a \u0441\u043b\u043e\u0436\u043d\u043e, \u0442\u0430\u043a \u043a\u0430\u043a \u0438\u0433\u0440\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0441\u0435\u0442\u043a\u0438, \u0440\u0430\u0437\u043c\u0435\u0440 \u044f\u0447\u0435\u0435\u043a \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0440\u0430\u0432\u0435\u043d 5 \u043d\u0430 5 \u043c\u0435\u0442\u0440\u043e\u0432. \u0412 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u043e\u043b\u0435 <code>grid<\/code>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 <code>line<\/code> &#8212; \u0443\u0441\u043b\u043e\u0432\u043d\u0430\u044f &#171;\u0441\u0442\u0440\u043e\u043a\u0430&#187; \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435, \u0438 <code>index<\/code> &#8212; \u043d\u043e\u043c\u0435\u0440 \u044f\u0447\u0435\u0439\u043a\u0438 \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435. \u041e\u0447\u0435\u0432\u0438\u0434\u043d\u043e \u0447\u0442\u043e \u0446\u0435\u043b\u044c \u0434\u043e\u043b\u0436\u043d\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0434 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u043c, \u0442\u0430\u043a \u0447\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u043c\u0441\u044f \u0446\u0438\u043a\u043b\u043e\u043c &#171;\u044f\u0447\u0435\u0439\u043a\u0430\u043c&#187;, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u043c\u0441\u044f \u0432 \u043f\u043e\u043b\u0435 \u0437\u0440\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u043e\u043a\u0430, \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0435, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430\u0448 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u0441\u0435\u0445 NPC \u0432 \u044f\u0447\u0435\u0439\u043a\u0435,<\/p>\n<pre><code class=\"lua\">function Map.findPedsInGrid(line, index)     local peds = {};     local pos = Map.getGridPos(line, index);     for k, v in ipairs(getAllChars()) do         local x, y, z = getCharCoordinates(v);         if (x &gt;= pos.x - 2.5 and x &lt;= pos.x + 2.5 and y &gt;= pos.y - 2.5 and y &lt;= pos.y + 2.5) then             table.insert(peds, v);         end     end     return peds; end<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0435\u043c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043f\u043e\u0438\u0441\u043a\u0443 \u0446\u0435\u043b\u0438.  \u0412 \u0441\u0430\u043c\u043e\u043c \u043d\u0430\u0447\u0430\u043b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 &#171;\u043e\u0431\u043d\u0443\u043b\u044f\u0435\u043c&#187; \u0446\u0435\u043b\u044c \u0434\u043b\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 (\u0442\u0430\u043a \u043a\u0430\u043a \u043f\u043e\u0438\u0441\u043a \u0446\u0435\u043b\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e), \u0437\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043c\u0430\u0441\u0441\u0438\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0445\u0435\u043d\u0434\u043b\u044b (\u0432\u043d\u0443\u0442\u0440\u0438\u0438\u0433\u0440\u043e\u0432\u044b\u0435 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b NPC). \u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u0441\u0435\u0445 NPC \u0432 \u044f\u0447\u0435\u0439\u043a\u0435, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0447\u0442\u043e NPC != &#171;\u0440\u0430\u0441\u0442\u0435\u043d\u0438\u044e&#187;, \u0437\u0430\u0442\u0435\u043c \u0441\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0439 \u0446\u0435\u043b\u0438.<\/p>\n<pre><code class=\"lua\">function Heroes.isHero(entity)     for k, v in ipairs(Heroes.pool) do         if (v.handle == entity.handle) then             return true;         end     end end  function Heroes.Hero:updateTarget()     local heroX, heroY, heroZ = getCharCoordinates(self.handle);     self.target = nil;     local enemies = {};     for index = self.grid.index, 9 do         local pos = Map.getGridPos(self.grid.line, index);          if (DEV) then             local x, y = convert3DCoordsToScreen(pos.x, pos.y, pos.z);             renderDrawPolygon(x, y, 10, 10, 10, 10, 0xFFff00ff);         end          local peds = Map.findPedsInGrid(self.grid.line, index);         if (#peds &gt; 0) then             for _, ped in ipairs(peds) do                 if (not Heroes.isHero(ped) and ped ~= self.handle and ped ~= PLAYER_PED) then                     table.insert(enemies, {                         handle = ped,                         dist = getDistanceBetweenCoords3d(heroX, heroY, heroZ, getCharCoordinates(ped))                     });                 end             end         end     end     pcall(table.sort, enemies, function(a, b)         return a.dist &lt; b.dist;     end);     local target = #enemies &gt; 0 and enemies[1] or nil;     if (target) then         self.target = target.dist &lt;= (self.attackDistance or 100) and target.handle or nil;     end     return enemies; end<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0448\u0435 &#171;\u0440\u0430\u0441\u0442\u0435\u043d\u0438\u0435&#187; \u0432\u0438\u0434\u0438\u0442 \u0432\u0440\u0430\u0433\u043e\u0432.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b1e\/9b3\/98f\/b1e9b398f013110511bfee39cb00eee0.png\" width=\"969\" height=\"275\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b1e\/9b3\/98f\/b1e9b398f013110511bfee39cb00eee0.png\"\/><\/figure>\n<h3>\u041e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u044f<\/h3>\n<div class=\"floating-image\">\n<figure class=\"float\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9f1\/a3d\/e43\/9f1a3de43aec5132d0784b678a53b402.png\" width=\"135\" height=\"142\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9f1\/a3d\/e43\/9f1a3de43aec5132d0784b678a53b402.png\"\/><\/figure>\n<p>\u0422\u0430\u043a \u0436\u0435 \u044f \u0440\u0435\u0448\u0438\u043b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u044f \u043d\u0430\u0434 \u043a\u0430\u0436\u0434\u044b\u043c \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u043c \u0438 \u0432\u0440\u0430\u0433\u043e\u043c. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u043c\u043e\u0434\u0443\u043b\u044c <code>ui.health-bar<\/code>, \u0412 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u044d\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0430.<\/p>\n<\/div>\n<pre><code class=\"lua\">local imgui = require('mimgui'); local GUI_BAR_SIZE = imgui.ImVec2(50, 5);  ---@type Hero | Enemy return function(entity, isEnemy)     local BGDL = imgui.GetBackgroundDrawList();     local x, y, z = getCharCoordinates(entity.handle);     local pos = imgui.ImVec2(convert3DCoordsToScreen(x, y, z + 1.5));     BGDL:AddRectFilled(         pos - imgui.ImVec2(GUI_BAR_SIZE.x \/ 2, 0),         pos + imgui.ImVec2(GUI_BAR_SIZE.x \/ 2, GUI_BAR_SIZE.y),         0xCC000000,         2     );     local healthPercent = entity.health \/ entity.maxHealth;     pos.x = pos.x - GUI_BAR_SIZE.x \/ 2;     BGDL:AddRectFilled(         pos + imgui.ImVec2(1, 1),         pos + imgui.ImVec2(GUI_BAR_SIZE.x * healthPercent - 1, GUI_BAR_SIZE.y - 1),         isEnemy and 0xFF4242db or 0xFF21b82e,         2     );     BGDL:AddText(pos + imgui.ImVec2(GUI_BAR_SIZE.x + 5, -7), 0xFFFFFFFF, tostring(entity.health)); end<\/code><\/pre>\n<p><a class=\"anchor\" name=\"zombie\" id=\"zombie\"><\/a><\/p>\n<h3>&#171;\u0417\u043e\u043c\u0431\u0438&#187;<\/h3>\n<p>\u0412\u0441\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0432\u0440\u0430\u0433\u0430\u043c\u0438 \u044f \u0442\u0430\u043a\u00a0\u0436\u0435 \u0432\u044b\u043d\u0435\u0441 \u0432\u00a0\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u00ab\u043a\u043b\u0430\u0441\u0441\u00bb. \u042f \u043c\u043e\u0433\u00a0\u0431\u044b \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439, \u043e\u0434\u043d\u0430\u043a\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u0447\u0442\u043e\u00a0\u0432\u00a0\u0438\u0433\u0440\u0435 \u0445\u0432\u0430\u0442\u0438\u0442 \u0432\u0441\u0435\u0433\u043e \u0434\u0432\u0443\u0445 \u0432\u0438\u0434\u043e\u0432 \u0432\u0440\u0430\u0433\u043e\u0432: \u043e\u0431\u044b\u0447\u043d\u044b\u0435, \u0438\u043c\u0435\u044e\u0449\u0438\u0435 100\u00a0\u0435\u0434\u0438\u043d\u0438\u0446 \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u044f \u0438 \u0441\u0438\u043b\u044c\u043d\u044b\u0445, \u0441 300\u00a0\u0445\u043f. <\/p>\n<p>\u0414\u043b\u044f\u00a0\u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u00ab\u043c\u043e\u0437\u0433\u043e\u0432\u00bb \u0432\u0440\u0430\u0433\u043e\u0432 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u043d\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f\u00a0\u043f\u043e\u0438\u0441\u043a\u0430 \u0446\u0435\u043b\u0438 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435\u00a0\u0438\u0434\u0435\u0442 \u043f\u043e\u0438\u0441\u043a \u043f\u043e\u00a0\u044f\u0447\u0435\u0439\u043a\u0430\u043c, \u0432\u043c\u0435\u0441\u0442\u043e \u043d\u0435\u0433\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c\u00a0\u043b\u0438\u043d\u0438\u044e \u043e\u0442\u00a0\u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u0440\u0430\u0433\u0430 \u0434\u043e\u00a0\u043f\u0435\u0440\u0432\u043e\u0439 \u044f\u0447\u0435\u0439\u043a\u0438 \u043a\u0430\u0440\u0442\u044b. \u0415\u0441\u043b\u0438\u00a0\u0431\u044b\u043b\u0430 \u043d\u0430\u0439\u0434\u0435\u043d\u0430 \u0442\u043e\u0447\u043a\u0430 \u0441\u043e\u043f\u0440\u0438\u043a\u043e\u0441\u043d\u043e\u0432\u0435\u043d\u0438\u044f, \u0438 \u044d\u0442\u043e\u0439 \u0442\u043e\u0447\u043a\u043e\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f NPC, \u044f \u043f\u043e\u043b\u0443\u0447\u0430\u043b \u0434\u0438\u0441\u0442\u0430\u043d\u0446\u0438\u044e \u043e\u0442\u00a0NPC \u0434\u043e \u00ab\u0437\u043e\u043c\u0431\u0438\u00bb. \u0421\u0438\u0441\u0442\u0435\u043c\u044b \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0430 \u0430\u0442\u0430\u043a\u0438, \u043d\u0430\u043d\u0435\u0441\u0435\u043d\u0438\u044f \u0443\u0440\u043e\u043d\u0430, \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0430\u0442\u0430\u043a\u0438 \u0438\u00a0\u0442.\u00a0\u0434. \u043e\u0441\u0442\u0430\u043b\u0430\u0441\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u0430 \u0442\u043e\u0439, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0434\u043b\u044f\u00a0\u043b\u043e\u0433\u0438\u043a\u0438 \u0440\u0430\u0441\u0442\u0435\u043d\u0438\u0439.<\/p>\n<pre><code class=\"lua\">function Enemies.Enemy:process(heroPool)     -- print('Processing enemy', self.handle);     if (not self.disableProcess) then         local currentPos = Vector3D(getCharCoordinates(self.handle));                  local targetEndGrid = Map.getGridPos(self.line, 0);          targetEndGrid.z = targetEndGrid.z + 1;         local isPlantFound, colpoint = processLineOfSight(currentPos.x, currentPos.y, currentPos.z, targetEndGrid.x, targetEndGrid.y, targetEndGrid.z, false, false, true, false, false, false, false, false);         local distanceToTarget = colpoint == nil and -1 or getDistanceBetweenCoords3d(currentPos.x, currentPos.y, currentPos.z, colpoint.pos[1], colpoint.pos[2], colpoint.pos[3]);          if (not isPlantFound or distanceToTarget &gt; 1.5) then             -- taskCharSlideToCoord(self.handle, 0, 0, 0, 0, 1);             if (os.clock() - self.lastXUpdate &gt; ENEMY_X_UPDATE_SPEED) then                 self:setCoordinates(Vector3D(currentPos.x - (DEV and 0.01 or 0.01), currentPos.y, currentPos.z));                 self.lastXUpdate = os.clock();             end         else             if (colpoint.entityType == 3) then                 local targetHandle = getCharPointerHandle(colpoint.entity);                 if (not doesCharExist(targetHandle)) then                     return print('ERROR: cannot get target handle for enemy!');                 end                                  -- Deal damage to target                 local timeSinceLastAttack = os.clock() - self.lastAttack;                 if (timeSinceLastAttack &gt; self.attackInterval) then                     for _, v in pairs(heroPool) do                         if (v.handle == targetHandle) then                             v:dealDamage(self.damage, self);                             v:call('onDamageReceived', self.damage, self);                             if (self.attackAnimation and hasAnimationLoaded(self.attackAnimation.file)) then                                 clearCharTasksImmediately(self.handle);                                 taskPlayAnim(self.handle, self.attackAnimation.name, self.attackAnimation.file, 4.0, false, true, true, true, 0);                             else                                 print('WARNING: Missing animation for enemy!');                             end                             self.lastAttack = os.clock();                             break;                         end                     end                 end             end         end          if (DEV) then             local x, y = convert3DCoordsToScreen(currentPos.x, currentPos.y, currentPos.z);             local x2, y2 = convert3DCoordsToScreen(targetEndGrid.x, targetEndGrid.y, targetEndGrid.z);             renderDrawLine(x, y, x2, y2, 1, isPlantFound and 0xFFffff00 or 0xFF00ffff);             renderFontDrawText(font, ('HP: %s\\nTarget: %s\\nDist: %0.2f\\nDist to end: %0.2f\\nX: %s'):format(tostring(self.health), tostring(isPlantFound), distanceToTarget, self:getDistanceToFinish(), self.x), x, y, 0xFFffffff, false);         end     end end<\/code><\/pre>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7d6\/920\/af9\/7d6920af94e0d145afa8ec9d9cf3d189.png\" alt=\"\u0422\u0435\u043f\u0435\u0440\u044c \u0438 \u0432\u0440\u0430\u0433\u0438 \u0432\u0438\u0434\u044f\u0442 \u043d\u0430\u0441\" title=\"\u0422\u0435\u043f\u0435\u0440\u044c \u0438 \u0432\u0440\u0430\u0433\u0438 \u0432\u0438\u0434\u044f\u0442 \u043d\u0430\u0441\" width=\"508\" height=\"273\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7d6\/920\/af9\/7d6920af94e0d145afa8ec9d9cf3d189.png\"\/><\/p>\n<div><figcaption>\u0422\u0435\u043f\u0435\u0440\u044c \u0438 \u0432\u0440\u0430\u0433\u0438 \u0432\u0438\u0434\u044f\u0442 \u043d\u0430\u0441<\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u044f \u043d\u0430\u0448\u0435\u043b \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u0438\u044f\u0442\u043d\u044b\u0439 \u0431\u0430\u0433: \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u00ab\u0437\u043e\u043c\u0431\u0438\u00bb \u0443\u0431\u0438\u043b \u00ab\u0440\u0430\u0441\u0442\u0435\u043d\u0438\u0435\u00bb, \u00ab\u0437\u043e\u043c\u0431\u0438\u00bb \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f \u0432\u043f\u0435\u0440\u0435\u0434, \u043d\u0430\u00a0\u0442\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0433\u0434\u0435 \u043e\u043d\u00a0\u0431\u044b\u043b\u00a0\u0431\u044b \u0435\u0441\u043b\u0438\u00a0\u0431\u044b \u043d\u0435\u00a0\u043d\u0430\u0448\u0435\u043b \u0446\u0435\u043b\u044c. \u0414\u0430\u043d\u043d\u044b\u0439 \u0431\u0430\u0433 \u0432\u043e\u0437\u043d\u0438\u043a \u0438\u0437\u2011\u0437\u0430 \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u00a0\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0432\u0440\u0430\u0433\u0430 \u0437\u0430\u0432\u0438\u0441\u044f\u0442 \u043e\u0442\u00a0\u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0438 \u043f\u043b\u0430\u0432\u043d\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044f\u0442 \u043e\u0442\u00a0\u0442\u043e\u0447\u043a\u0438 \u0441\u043f\u0430\u0432\u043d\u0430 \u0434\u043e\u00a0\u043d\u0430\u0447\u0430\u043b\u0430 \u043a\u0430\u0440\u0442\u044b. \u0424\u0443\u043d\u043a\u0446\u0438\u044f, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u0430 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a, \u043f\u043e\u0437\u0434\u043d\u0435\u0435 \u044f \u0438\u0437\u0431\u0430\u0432\u043b\u044e\u0441\u044c \u043e\u0442\u00a0\u043d\u0435\u0435:<\/p>\n<pre><code class=\"lua\">function Utils.bringVec3To(from, to, start_time, duration)     local timer = os.clock() - start_time     if timer &gt;= 0.00 and timer &lt;= duration then         local count = timer \/ (duration \/ 100)         return Vector3D(             from.x + (count * (to.x - from.x) \/ 100),             from.y + (count * (to.y - from.y) \/ 100),             from.z + (count * (to.z - from.z) \/ 100)         ), true     end     return (timer &gt; duration) and to or from, false end<\/code><\/pre>\n<p>\u0427\u0442\u043e \u0431\u044b \u043f\u043e\u0444\u0438\u043a\u0441\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u0431\u0430\u0433 \u043c\u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u044f <code>x<\/code> \u0438 <code>lastXUpdate<\/code>. \u0412 <code>x<\/code> \u0445\u0440\u0430\u043d\u0438\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e \u043e\u0441\u0438 X, \u0430 \u0432 <code>lastXUpdate<\/code> \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u0430\u043b\u0435\u0435 \u0432 <code>Enemy:process()<\/code> \u0431\u044b\u043b \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"lua\">... if (not isPlantFound or distanceToTarget &gt; 1.5) then     if (os.clock() - self.lastXUpdate &gt; ENEMY_X_UPDATE_SPEED) then         self:setCoordinates(Vector3D(currentPos.x - 0.01, currentPos.y, currentPos.z));         self.lastXUpdate = os.clock();     end else ...<\/code><\/pre>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a65\/fce\/a66\/a65fcea668f954ce8d48714fd980d195.png\" alt=\"\u0414\u0440\u0430\u043a\u0430 \u043d\u0430 \u043f\u043e\u043b\u044f\u043d\u0435\" title=\"\u0414\u0440\u0430\u043a\u0430 \u043d\u0430 \u043f\u043e\u043b\u044f\u043d\u0435\" width=\"515\" height=\"343\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a65\/fce\/a66\/a65fcea668f954ce8d48714fd980d195.png\"\/><\/p>\n<div><figcaption>\u0414\u0440\u0430\u043a\u0430 \u043d\u0430 \u043f\u043e\u043b\u044f\u043d\u0435<\/figcaption><\/div>\n<\/figure>\n<h3>\u0421\u043f\u0430\u0432\u043d \u0437\u043e\u043c\u0431\u0438<\/h3>\n<div class=\"floating-image\">\n<figure class=\"float\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c0c\/62a\/ef9\/c0c62aef958b879fa069712ae460eda8.png\" alt=\"\u0414\u0435\u0431\u0430\u0433 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e\" title=\"\u0414\u0435\u0431\u0430\u0433 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e\" width=\"358\" height=\"427\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c0c\/62a\/ef9\/c0c62aef958b879fa069712ae460eda8.png\"\/><\/p>\n<div><figcaption>\u0414\u0435\u0431\u0430\u0433 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e<\/figcaption><\/div>\n<\/figure>\n<p>\u0421\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u044f \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u0441 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u044b\u043c \u0431\u0430\u0433\u043e\u043c: \u043f\u043e\u0447\u0435\u043c\u0443-\u0442\u043e, \u043b\u043e\u0433\u0438\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u0440\u0430\u0433\u0430. \u0414\u0430\u043d\u043d\u044b\u0439 \u0431\u0430\u0433 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u043b \u0438\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e \u0447\u0442\u043e \u043f\u0440\u0438 \u0441\u043f\u0430\u0432\u043d\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0432\u0440\u0430\u0433\u0430 \u0445\u0435\u043d\u0434\u043b\u044b \u0432\u0441\u0435\u0445 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u043c\u0435\u043d\u044f\u043b\u0438\u0441\u044c \u043d\u0430 \u0445\u0435\u043d\u0434\u043b \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0433\u043e. \u041f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b\u043e \u044d\u0442\u043e \u0438\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e \u0447\u0442\u043e \u0433\u0440\u0443\u0431\u043e \u0433\u043e\u0432\u043e\u0440\u044f \u044f \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043b \u043d\u0435 \u0441\u0430\u043c\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u0430 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u043d\u0435\u0435. \u041e\u0448\u0438\u0431\u043a\u0443 \u044f \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u043b \u043e\u0431\u0435\u0440\u043d\u0443\u0432<code>EnemyData[type]<\/code> \u0432 <code>Utils.copyTable()<\/code> .<\/p>\n<\/div>\n<h3>&#171;\u041e\u0431\u0445\u043e\u0434&#187; \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0433\u043e \u0430\u043d\u0442\u0438\u0447\u0438\u0442\u0430<\/h3>\n<p>\u0418\u0433\u0440\u0430 \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u043a\u0430\u043a\u043e\u0433\u043e-\u043b\u0438\u0431\u043e \u0447\u0438\u0442\u0435\u0440\u0441\u043a\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430, \u043e\u0434\u043d\u0430\u043a\u043e, \u043a\u0430\u0440\u0442\u0430 \u0438\u0433\u0440\u044b \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0432 \u043d\u0435\u0431\u0435, \u043a\u0443\u0434\u0430 \u0438 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0438\u0433\u0440\u043e\u043a \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435. \u0414\u0430\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043a\u0438\u043a\u0430 \u043e\u0442 \u0430\u043d\u0442\u0438\u0447\u0438\u0442\u0430 \u0431\u044b\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043c\u043e\u0434\u0443\u043b\u044c \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u043b \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 RPC \u0438 \u043f\u0430\u043a\u0435\u0442\u044b. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u043e\u0441\u043b\u0435 \u0441\u0442\u0430\u0440\u0442\u0430 \u0438\u0433\u0440\u044b \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u0438\u0445 \u0438\u0433\u0440\u043e\u043a\u043e\u0432 \u0432\u044b \u043e\u0441\u0442\u0430\u0435\u0442\u0435\u0441\u044c \u043d\u0430 \u0441\u0442\u0430\u0440\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0435\u0441\u044c \u0432 AFK. \u0422\u0430\u043a \u0436\u0435 \u043f\u0435\u0440\u0435\u0434 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u0435\u0439 \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u0443\u044e \u043a\u0430\u0440\u0442\u0443 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0438\u0433\u0440\u043e\u043a\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f, \u0430 \u043f\u0440\u0438 \u0432\u044b\u0445\u043e\u0434\u0435 \u0438\u0437 \u043c\u0438\u043d\u0438-\u0438\u0433\u0440\u044b \u0438 \u043f\u0435\u0440\u0435\u0434 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u0442\u0430\u0440\u044b\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b. <\/p>\n<pre><code class=\"lua\">local RakNet = {     nop = false };  function RakNet.init()     for _, event in ipairs({ 'onSendPacket', 'onReceivePacket', 'onSendRpc', 'onReceiveRpc' }) do         addEventHandler(event, function()             return RakNet.nop;         end);     end end  return RakNet;<\/code><\/pre>\n<h2>\u0413\u0430\u0437\u043e\u043d\u043e\u043a\u043e\u0441\u0438\u043b\u043a\u0438<\/h2>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u044f \u043d\u0435 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043b \u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0433\u0430\u0437\u043e\u043d\u043e\u043a\u043e\u0441\u0438\u043b\u043e\u043a, \u043d\u043e \u043f\u043e\u0437\u0436\u0435 \u0441\u0442\u0430\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u0447\u0442\u043e \u0441 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438 \u0431\u0443\u0434\u0435\u0442 \u043c\u0435\u043d\u044c\u0448\u0435 \u0433\u0435\u043c\u043e\u0440\u0430.<\/p>\n<p>\u041a\u043b\u0430\u0441\u0441 <code>Vehicle<\/code> \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432\u0441\u0435\u0433\u043e \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043f\u043e\u043b\u0435\u0439:<\/p>\n<ul>\n<li>\n<p><code>handle<\/code> &#8212; \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440<\/p>\n<\/li>\n<li>\n<p><code>movementStartTime<\/code> &#8212; \u043d\u0430\u0447\u0430\u043b\u043e \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f<\/p>\n<\/li>\n<li>\n<p><code>spawnPos<\/code> &#8212; \u0442\u043e\u0447\u043a\u0430 \u0441\u043f\u0430\u0432\u043d\u0430<\/p>\n<\/li>\n<li>\n<p><code>endX<\/code> &#8212; \u0442\u043e\u0447\u043a\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0433\u0430\u0437\u043e\u043d\u043e\u043a\u043e\u0441\u0438\u043b\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0443\u0434\u0430\u043b\u044f\u0442\u044c\u0441\u044f<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0435 \u043f\u043e\u0434\u043e\u0448\u043b\u0430 \u043f\u043e\u0434 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u0432\u0440\u0430\u0433\u0430. \u0422\u0443\u0442 \u043e\u043d\u0430 \u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u043a\u0430\u043a \u043d\u0435\u043b\u044c\u0437\u044f \u043a\u0441\u0442\u0430\u0442\u0438, \u0432\u0435\u0434\u044c \u0441 \u043f\u0440\u043e\u0448\u043b\u044b\u043c \u0431\u0430\u0433\u043e\u043c \u043c\u044b \u0442\u043e\u0447\u043d\u043e \u043d\u0435 \u0441\u0442\u043e\u043b\u043a\u043d\u0435\u043c\u0441\u044f, \u0442\u0430\u043a \u043a\u0430\u043a \u0433\u0430\u0437\u043e\u043d\u043e\u043a\u043e\u0441\u0438\u043b\u043a\u0430 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f. \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u044f \u0445\u043e\u0442\u0435\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 GTA:SA, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a <code>carGotoCoordinates(Vehicle car, float driveToX, float driveToY, float driveToZ)<\/code>  \u0438\u043b\u0438 <code>setCarForwardSpeed(Vehicle car, float speed)<\/code> , \u043d\u043e \u043e\u043d\u0438 \u043c\u043d\u0435 \u043d\u0435 \u043f\u043e\u0434\u043e\u0448\u043b\u0438. \u041f\u0435\u0440\u0432\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442 \u0435\u0445\u0430\u0442\u044c \u043a \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0435 \u0438 \u043e\u0431\u044a\u0435\u0437\u0436\u0430\u0442\u044c \u0432\u0441\u0435 \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043a\u0430\u043a \u0440\u0430\u0437 \u0438 \u0441\u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f NPC, \u0442\u0430\u043a \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0433\u0430\u0437\u043e\u043d\u043e\u043a\u043e\u0441\u0438\u043b\u043a\u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u044a\u0435\u0437\u0436\u0430\u043b\u0430 \u0432\u0440\u0430\u0433\u043e\u0432. \u0412\u0442\u043e\u0440\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0435 \u043f\u043e\u0434\u043e\u0448\u043b\u0430 \u0438\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e \u0447\u0442\u043e \u0433\u0430\u0437\u043e\u043d\u043e\u043a\u043e\u0441\u0438\u043b\u043a\u0430 \u0441\u0431\u0438\u0432\u0430\u043b\u0430\u0441\u044c \u0441 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430 \u0438\u0437-\u0437\u0430 \u0441\u0442\u043e\u043b\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u0441 NPC, \u0430 \u043f\u0440\u0438 \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043a\u043e\u043b\u043b\u0438\u0437\u0438\u0438 \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430 \u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u043a\u0430\u0441\u0430\u043d\u0438\u0435, \u0438, \u043a\u0430\u043a \u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0435, NPC \u0431\u044b \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043b\u0438 \u0443\u043c\u0438\u0440\u0430\u0442\u044c. \u041a\u043e\u043d\u0435\u0447\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"lua\">function Vehicles.process(enemyPool, heroPool)     for index, vehicle in ipairs(Vehicles.pool) do         vehicle:process(enemyPool, heroPool);     end end  function Vehicles.Vehicle:process(enemyPool, heroPool)     print(#enemyPool)     if (self.movementStartTime) then         local newX = Utils.bringFloatTo(self.startX, self.endX, self.movementStartTime, 5);         setCarCoordinates(self.handle, newX, self.spawnPos.y, self.spawnPos.z);         if (newX &gt;= self.endX) then             self.movementStartTime = nil;             self:destroy();             return;         end     end          local x, y, z = getCarCoordinates(self.handle);     local sx, sy = convert3DCoordsToScreen(x, y, z);     for _, entity in ipairs(Utils.mergeTable(enemyPool, heroPool)) do         if (DEV) then             local ex, ey = convert3DCoordsToScreen(getCharCoordinates(entity.handle));             renderDrawLine(sx, sy, ex, ey, 1, 0xFF0000ff);         end         if (getDistanceBetweenCoords3d(x, y, z, getCharCoordinates(entity.handle)) &lt;= 1) then             Utils.msg('ped tounching veh, ped', entity.handle, 'veh', self.handle);             if (not self.movementStartTime) then                 self.movementStartTime = os.clock();             end             entity:kill();         end     end      if (DEV) then         renderFontDrawText(font, ('Handle: %d\\nX: %0.2f'):format(self.handle, x), sx, sy, 0xFFffffff, false);     end end<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/cd0\/b86\/648\/cd0b86648284061fd648c728766f4dc7.png\" width=\"1239\" height=\"498\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/cd0\/b86\/648\/cd0b86648284061fd648c728766f4dc7.png\"\/><\/figure>\n<h2>\u0421\u0431\u043e\u0440\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>DEV<\/code>, \u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0435\u043b\u043e \u043e\u0442 \u0442\u043e\u0433\u043e, \u0441\u043e\u0431\u0440\u0430\u043d \u043b\u0438 \u043f\u0440\u043e\u0435\u043a\u0442 (\u0431\u0430\u043d\u0434\u043b\u0435\u0440 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>LUBU_BUNDLED<\/code>).<\/p>\n<pre><code class=\"lua\">DEV = LUBU_BUNDLED == nil; ---@diagnostic disable-line BASE_PATH = DEV and 'X:\\\\Games\\\\GTASA\\\\moonly\\\\pvz\\\\src\\\\' or getWorkingDirectory();<\/code><\/pre>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<pre><code class=\"lua\">require('moonloader'); local imgui = require('mimgui'); local Vector3D = require('vector3d'); local Map = require('map'); local Camera = require('camera'); local Utils = require('utils'); local Heroes = require('heroes'); local Enemies = require('enemy'); local uiComponents = {     mainMenu = require('ui.main-menu'),     gameInterface = require('ui.game-interface') };<\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043e\u0431 \u0438\u0433\u0440\u043e\u043a\u0435<\/p>\n<pre><code class=\"lua\">local Game = {     saved = {         heading = 0,         pos = Vector3D(0, 0, 0)     },     state = GameState.Menu,     money = 9999,     heroToPlace = nil };  function Game.destroy()     Heroes.destroy();     Enemies.destroy();     Map.destroy();     Game.state = GameState.Menu;     setCharCoordinates(PLAYER_PED, Game.saved.pos.x, Game.saved.pos.y, Game.saved.pos.z);     Camera.restore();     RakNet.nop = false; end  function Game.start()     Game.saved = {         heading = getCharHeading(PLAYER_PED),         pos = Vector3D(getCharCoordinates(PLAYER_PED))     };              Map.init();     Enemies.init();     Camera.init(Vector3D(Map.pos.x + 17, Map.pos.y - 1, Map.pos.z + 20), Vector3D(Map.pos.x + 17, Map.pos.y + 11, Map.pos.z));     Camera.update();     setCharCoordinates(PLAYER_PED, Map.pedPos.x, Map.pedPos.y, Map.pedPos.z);     setCharHeading(PLAYER_PED, Map.pedHeading);     Game.state = GameState.Playing;     RakNet.nop = true; end<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0443\u044e \u0438\u0433\u0440\u043e\u0432\u043e\u0435 \u043c\u0435\u043d\u044e \u0432 \u0447\u0430\u0442\u0435:<\/p>\n<pre><code class=\"lua\">    sampRegisterChatCommand('pvz', function()         if (Game.state == GameState.Playing) then             Game.state = GameState.Menu;             Game.destroy();         elseif (Game.state == GameState.Menu) then             Game.state = GameState.None;         elseif (Game.state == GameState.None) then             Game.state = GameState.Menu;         end         Utils.msg('Game state was changed to:', Game.state);     end);<\/code><\/pre>\n<p>\u0417\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0446\u0438\u043a\u043b, \u0442\u0430\u043c \u043c\u044b \u0431\u0443\u0434\u0435\u043c:<\/p>\n<ul>\n<li>\n<p>\u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044f <code>process<\/code> \u0443 \u0432\u0441\u0435\u0445 \u0440\u0430\u0441\u0442\u0435\u043d\u0438\u0439 \u0438 \u0432\u0440\u0430\u0433\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u0430\u0441\u0442\u0435\u043d\u0438\u044f<\/p>\n<\/li>\n<li>\n<p>\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0432\u043e\u0434\u043a\u0443 \u0443 \u044f\u0447\u0435\u0439\u043a\u0438 \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0430\u0432\u0435\u0434\u0435\u043d \u043a\u0443\u0440\u0441\u043e\u0440 \u0438\u0433\u0440\u043e\u043a\u0430<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"lua\">while (true) do         wait(0);         if (Game.state == GameState.Playing) then             -- Draw hovered grid outline             if (Game.heroToPlace) then                 local line, index, pos = Map.getGridForCoord(Map.getPointerPos(nil));                 if (line ~= -1 and pos) then                     local x1, y1 = convert3DCoordsToScreen(pos.x - 2.5, pos.y - 2.5, pos.z);                     local x2, y2 = convert3DCoordsToScreen(pos.x + 2.5, pos.y + 2.5, pos.z);                     local x3, y3 = convert3DCoordsToScreen(pos.x - 2.5, pos.y + 2.5, pos.z);                     local x4, y4 = convert3DCoordsToScreen(pos.x + 2.5, pos.y - 2.5, pos.z);                     renderDrawLine(x1, y1, x3, y3, 2, 0xFFffffff);                     renderDrawLine(x1, y1, x4, y4, 2, 0xFFffffff);                     renderDrawLine(x2, y2, x4, y4, 2, 0xFFffffff);                     renderDrawLine(x3, y3, x2, y2, 2, 0xFFffffff);                 end                 if (wasKeyPressed(VK_LBUTTON)) then                     sampAddChatMessage(('Placed hero with type \"%s\" to (%d:%d)'):format(Game.heroToPlace, line, index), 0xFF00ff00);                     Heroes.Hero:new(Game.heroToPlace, line, index)                     Game.money = Game.money - Game.heroToPlace.price;                     Game.heroToPlace = nil;                 elseif (wasKeyPressed(VK_RBUTTON)) then                     Game.heroToPlace = nil;                 end             end              -- Processing             Heroes.process(Enemies.pool);             Enemies.process(Enemies.pool, Heroes.pool);             Map.process(Enemies.pool, {                 onSunTaked = function()                     Game.money = Game.money + 50;                     printStringNow('~y~+50', 1250);                 end,                 spawnEnemy = function(type)                     math.randomseed(os.time() * math.random(1, 10));                     local type = math.random(1, 1);                     math.randomseed(os.time() * math.random(1, 10));                     local line = math.random(1, 5);                     Utils.msg('Spawning enemy with type', type, 'on line', line);                     Enemies.Enemy:new(type, line);                     Map.lastEnemySpawned = os.clock();                 end             });         end     end<\/code><\/pre>\n<h2>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/h2>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/678bc8315d5079d77e34c6b0\" data-style=\"\" id=\"678bc8315d5079d77e34c6b0\" width=\"\"><\/div>\n<h2>\u0421\u0431\u043e\u0440\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u0414\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432 1 \u0441\u043a\u0440\u0438\u043f\u0442 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0431\u0430\u043d\u0434\u043b\u0435\u0440 &#8212; LuBu (<a href=\"https:\/\/github.com\/chaposcripts\/lubu\" rel=\"noopener noreferrer nofollow\">GitHub<\/a>). \u0414\u0430\u043d\u043d\u044b\u0439 \u0431\u0430\u043d\u0434\u043b\u0435\u0440 \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0434\u043b\u044f \u043b\u0438\u0447\u043d\u044b\u0445 \u043d\u0443\u0436\u0434 \u0438 \u0434\u043b\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u0432 Go. \u0421\u0431\u043e\u0440\u043a\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u043e\u0439 \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 &#8212; <code>.\/lubu.exe bundle-config.json<\/code><\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u041f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u043c\u0435\u0448\u0430\u043d\u043d\u044b\u0435 \u0447\u0443\u0432\u0441\u0442\u0432\u0430, \u0432\u0440\u043e\u0434\u0435 \u0431\u044b \u0434\u0435\u043b\u0430\u0435\u0448\u044c \u0447\u0442\u043e-\u0442\u043e \u043f\u0440\u0438\u043a\u043e\u043b\u044c\u043d\u043e\u0435, \u043d\u043e \u0432 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0448\u044c \u0447\u0442\u043e \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u044e\u0437\u043b\u0435\u0441\u0441 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u043f\u0440\u0438\u043d\u0435\u0441\u0443\u0442 \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u043f\u043e\u043b\u044c\u0437\u044b.<\/p>\n<p><strong>P.S<\/strong> \u041f\u0440\u0435\u0434\u0447\u0443\u0432\u0441\u0442\u0432\u0443\u044e \u0433\u043d\u0435\u0432\u043d\u044b\u0435 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u043d\u0430\u00a0\u0441\u0447\u0435\u0442 \u043a\u043e\u0434\u0441\u0442\u0430\u0439\u043b\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435\u00a0\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043e\u0431\u0449\u0435\u043f\u0440\u0438\u043d\u044f\u0442\u043e\u043c\u0443 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0443 Lua. CamelCase\u00a0\u0431\u044b\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d \u0434\u043b\u044f \u00ab\u044d\u0441\u0442\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e\u00bb \u0443\u0434\u043e\u0432\u043e\u043b\u044c\u0441\u0442\u0432\u0438\u044f, \u0442\u0430\u043a \u043a\u0430\u043a\u00a0MoonLoader API \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0438\u043c\u0435\u043d\u043d\u043e \u0435\u0433\u043e, \u0438,\u00a0\u0431\u044b\u043b\u043e\u00a0\u0431\u044b \u0441\u0442\u0440\u0430\u043d\u043d\u043e \u043c\u0438\u043a\u0441\u043e\u0432\u0430\u0442\u044c snake_case \u0438 camelCase, \u0430\u00a0\u0441\u0435\u043c\u0438\u043a\u043e\u043b\u043e\u043d\u044b \u0438 \u0441\u043a\u043e\u0431\u043a\u0438 \u0432\u00a0\u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445 \u0432\u043e\u0448\u043b\u0438 \u0432\u00a0\u043f\u0440\u0438\u0432\u044b\u0447\u043a\u0443 \u043f\u043e\u0441\u043b\u0435 TypeScript&#8217;\u0430.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/874850\/\"> https:\/\/habr.com\/ru\/articles\/874850\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>&#171;\u041c\u043e\u0434\u0443\u043b\u044c\u043d\u043e\u0441\u0442\u044c&#187; \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 SA:MP<\/h2>\n<p>\u042d\u0442\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u043f\u0435\u0440\u0432\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0434\u043b\u044f GTA:SA \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0437\u0431\u0438\u0442 \u043d\u0430 \u043c\u043e\u0434\u0443\u043b\u0438. \u0421\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u044f \u0434\u0430\u0436\u0435 \u043f\u0438\u0441\u0430\u043b \u0441\u0432\u043e\u0439 \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u043b\u0443\u0430 \u0431\u0430\u043d\u0434\u043b\u0435\u0440 &#8212; LuBu (<a href=\"https:\/\/github.com\/chaposcripts\/lubu\" rel=\"noopener noreferrer nofollow\">GitHub<\/a>). \u0412\u0430\u043c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0447\u0442\u043e \u044d\u0442\u043e \u043a\u0430\u043a\u043e\u0439 \u0442\u043e \u0431\u0440\u0435\u0434, \u043d\u043e \u0432 \u043d\u0435 \u0441\u0442\u043e\u043b\u044c \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435 lua-\u0441\u043a\u0440\u0438\u043f\u0442\u0435\u0440\u043e\u0432 GTA:SA \u043f\u043e\u0447\u0435\u043c\u0443-\u0442\u043e \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u044b\u043b\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u0435\u0441\u044c \u043a\u043e\u0434 \u0432 \u043e\u0434\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043e\u043d \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0442\u044b\u0441\u044f\u0447\u0438 \u0438\u043b\u0438 \u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u0442\u044b\u0441\u044f\u0447 \u0441\u0442\u0440\u043e\u043a. \u0412\u0435\u0440\u043e\u044f\u0442\u043d\u043e, \u044d\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043e \u0441 \u0430\u0443\u0434\u0438\u0442\u043e\u0440\u0438\u0435\u0439 \u044d\u0442\u043e\u0439 \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e\u0439 \u0438\u0433\u0440\u044b, \u0432\u0435\u0434\u044c \u043a\u043e\u0433\u0434\u0430 \u0434\u0432\u0435\u043d\u0430\u0434\u0446\u0430\u0442\u0438\u043b\u0435\u0442\u043d\u0438\u0439 \u0412\u043e\u0432\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043c\u0435\u0433\u0430-\u0441\u0443\u043f\u0435\u0440-\u043f\u0443\u043f\u0435\u0440 \u0447\u0438\u0442, \u0442\u043e \u0435\u0433\u043e \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u043d\u0435 \u0432\u043e\u043b\u043d\u0443\u0435\u0442 \u0447\u0438\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438 \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u043e \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430. <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0435 \u0436\u0430\u043b\u043a\u043e \u0432\u0430\u0448\u0443 \u043f\u0441\u0438\u0445\u0438\u043a\u0443, \u0442\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0443\u0436\u0430\u0441\u043d\u044b\u0445, \u0438, \u0432 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 &#8212; <a href=\"https:\/\/www.blast.hk\/threads\/89343\/\" rel=\"noopener noreferrer nofollow\">Mono Tools<\/a> (\u043a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0430\u0432\u0442\u043e\u0440 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0440\u0435\u0448\u0438\u043b \u0437\u0430\u0431\u0440\u043e\u0441\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442\u0438\u043d\u0433). \u0421\u043a\u0440\u0438\u043f\u0442 \u0432\u0435\u0441\u0438\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u043e\u043b\u0443\u0442\u043e\u0440\u0430 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442\u0430, \u0442\u0430\u043a \u0447\u0442\u043e \u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0441\u0442\u0430\u0432\u043b\u044e \u0437\u0434\u0435\u0441\u044c \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430 \u043a\u043e\u0434\u0430<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u0435\u043a\u0441\u0442<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418\u0442\u0430\u043a, \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043a &#171;\u0438\u0433\u0440\u0430\u043c&#187;.<\/p>\n<h2>Defense Of The Ghetto<\/h2>\n<p><a href=\"https:\/\/github.com\/chaposcripts\/Defense-Of-The-Ghetto\" rel=\"noopener noreferrer nofollow\">\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 (\u0441\u0442\u0430\u0440\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f)<\/a> (\u043f\u0440\u043e\u0448\u0443 \u043e\u0442\u043d\u0435\u0441\u0442\u0438\u0441\u044c \u043a \u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0437\u043e\u0440\u0443 \u0441 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435\u043c)<\/p>\n<p>\u041e\u043a\u043e\u043b\u043e \u0434\u0432\u0443\u0445 \u043b\u0435\u0442 \u043d\u0430\u0437\u0430\u0434, \u0448\u0443\u0442\u043a\u0438 \u0440\u0430\u0434\u0438, \u044f \u043d\u0430\u0447\u0430\u043b \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c Defense Of The Ghetto \u043d\u0430 \u0431\u0430\u0437\u0435 GTA:SA \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e MoonLoader, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b\u043b \u043f\u0430\u0440\u043e\u0434\u0438\u0435\u0439 \u043d\u0430 \u043e\u0434\u043d\u0443 \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0438\u0433\u0440 &#8212; Defense Of The Ancients 2 (Dota2). \u0417\u0430 \u043d\u0435\u0434\u0435\u043b\u044e \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u043a\u043e\u0440\u044f\u0432\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f, \u0432 \u043d\u0435\u043c \u0431\u044b\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b: \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0438 \u0438 \u0438\u0445 \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u0438, \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u044b, \u043a\u0440\u0438\u043f\u044b, \u0431\u0430\u0448\u043d\u0438, \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0430\u0442\u0430\u043a\u0438, \u043d\u0430\u043d\u0435\u0441\u0435\u043d\u0438\u0435 \u0443\u0440\u043e\u043d\u0430 \u0438 \u043f\u0440\u043e\u0447\u0435\u0435. \u0418\u0437-\u0437\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u0431\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u0441\u0442\u0432 \u044f \u0431\u044b\u043b \u0432\u044b\u043d\u0443\u0436\u0434\u0435\u043d \u0437\u0430\u0431\u0440\u043e\u0441\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0432\u0440\u0435\u043c\u044f. \u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u0435\u043a\u0442 \u044f \u043f\u043e\u043d\u044f\u043b \u0447\u0442\u043e \u0441\u0442\u0430\u0440\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u0436\u0430\u0441\u0435\u043d \u0438 \u043d\u0435\u0443\u0434\u043e\u0431\u0435\u043d, \u0438\u0437-\u0437\u0430 \u0447\u0435\u0433\u043e \u044f \u043d\u0430\u0447\u0430\u043b \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0441 \u043d\u0443\u043b\u044f. <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0441\u0442\u0430\u0440\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0431\u044b\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0431\u044b\u043b\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 .lua \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0438 \u0437\u0430\u043a\u0438\u043d\u0443\u0442\u044c \u0435\u0433\u043e \u0432 \u043f\u0430\u043f\u043a\u0443 <code>DOTA\\heroes<\/code> , \u0432\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 Shadow Fiend:<\/p>\n<pre><code class=\"lua\">local AbilityType = require('dota.types').AbilityType; local Map = require('dota.map');  local function coil(range)     clearCharTasksImmediately(PLAYER_PED);     if not hasAnimationLoaded('carry') then         requestAnimation('carry');     end     clearCharTasksImmediately(PLAYER_PED)     taskPlayAnim(PLAYER_PED, 'putdwn105', 'carry', 0, false, true, true, true, 10000)      local x, y, z = Map.getPosFromCharVector(range);     local smoke = createObject(18686, x, y, z - 1);     Map.dealDamageToPoint(Vector3D(x, y, z));     wait(3000);     deleteObject(smoke); end  local abilities = {} for i = 3, 9, 3 do     table.insert(abilities, {         name = ('Coil (%d)'):format(i),         manaRequired = 50,         cooldown = 10,         useThread = true,         type = AbilityType.INSTANT,         onUse = function()             coil(i);         end     }); end table.insert(abilities, {     name = 'ULT',     manaRequired = 50,     cooldown = 10,     useThread = true,     type = AbilityType.INSTANT,     onUse = function()         local start = os.clock()         local ultimate_objects = {}                  for i = 0, 360, 30 do             local angle = math.rad(i) + math.pi \/ 2             local posX, posY, posZ = getCharCoordinates(PLAYER_PED)              local start = Vector3D(1 * math.cos(angle) + posX, 1 * math.sin(angle) + posY, posZ - 1)             local stop = Vector3D(20 * math.cos(angle) + posX, 20 * math.sin(angle) + posY, posZ - 1)             local handle = createObject(18686, start.x, start.y, start.z)             ultimate_objects[handle] = {                 start = start,                 stop = stop             }                      end          -- create object         while start + 4 - os.clock() &gt; 0 do             wait(0)             for handle, data in pairs(ultimate_objects) do                 if doesObjectExist(handle) then                     slideObject(handle, data.stop.x, data.stop.y, data.stop.z, 0.5, 0.5, 0.5, false)                     local result, x, y, z = getObjectCoordinates(handle);                     if result then                         Map.dealDamageToPoint(Vector3D(x, y, z), 55);                     end                 end             end         end         for handle, data in pairs(ultimate_objects) do             if doesObjectExist(handle) then                 deleteObject(handle)                 ultimate_objects[handle] = nil             end         end     end });  ---@type Hero local shadow_fiend = {     type = require('dota.types').HeroType,     name = 'Shadow Fiend',     model = 5,     abilities = abilities,     stats = {         maxHealth = 1300,         maxMana = 200,         healthRegen = 2,         manaRegen = 3,         damage = 10,         attackSpeed = 10,         speed = 0,         attackRange = 1,     } };  return shadow_fiend;<\/code><\/pre>\n<p>\u041f\u043e\u0434\u0433\u0440\u0443\u0437\u043a\u0430 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439 \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u0430 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"lua\">---@meta local Utils = require('dota.utils'); local mimgui = require('mimgui'); local ffi = require('ffi');  local PLACEHOLDER_IMAGE = ''; local Heroes = {     basePath = getWorkingDirectory() .. '\\\\dota\\\\heroes',     list = {} };  --- Load heroes images (avatars) and abilities icons --- CALL IN mimgui.OnInitialize function Heroes.loadImages()     for codename, data in pairs(Heroes.list) do         local imageBase85 = data.imageBase85 or PLACEHOLDER_IMAGE;         Heroes.list[codename].image = imgui.CreateTextureFromFileInMemory(imgui.new('const char*', imageBase85), #imageBase85);          --\/\/ abilities         for abilityCodename, ability in pairs(data.abilities) do             local imageBase85 = data.imageBase85 or PLACEHOLDER_IMAGE;             Heroes.list[codename].abilities[abilityCodename] = imgui.CreateTextureFromFileInMemory(imgui.new('const char*', imageBase85), #imageBase85);         end     end end  --- Load heroes list in &lt;HEROES&gt;.list function Heroes.init()     for _, fileName in pairs(Utils.getFilesInPath(Heroes.basePath, '*.lua')) do         if (fileName ~= 'init.lua') then             print(fileName);             local codeName = fileName:gsub('.lua', '');             Heroes.list[codeName] = require('dota.heroes.' .. codeName);             print('hero loaded', codeName);         end     end end  return Heroes;<\/code><\/pre>\n<p>\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e (\u0438\u043b\u0438 \u043a \u0441\u0447\u0430\u0441\u0442\u044c\u044e), \u043f\u0440\u043e\u0435\u043a\u0442 \u0431\u044b\u043b \u0437\u0430\u0431\u0440\u043e\u0448\u0435\u043d \u0432 \u0441\u0432\u044f\u0437\u0438 \u0441 \u043e\u0441\u0435\u043d\u043d\u0438\u043c \u043f\u0440\u0438\u0437\u044b\u0432\u043e\u043c, \u0430 \u0441\u043f\u0443\u0441\u0442\u044f \u0433\u043e\u0434 \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u044d\u0442\u043e\u0439 \u0438\u0434\u0435\u0435. \u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0431\u044b\u043b \u0443\u0442\u0435\u0440\u044f\u043d.<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/678944e8bfebf17680855696\" data-style=\"\" id=\"678944e8bfebf17680855696\" width=\"\"><\/div>\n<h2>Plants Vs Zombies<\/h2>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 GitHub: <a href=\"https:\/\/github.com\/chaposcripts\/gta-sa-plants-vs-zombies\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/chaposcripts\/gta-sa-plants-vs-zombies<\/a>.<\/p>\n<h3>\u041a\u0440\u0430\u0442\u043a\u0430\u044f \u043f\u0440\u0435\u0434\u044b\u0441\u0442\u043e\u0440\u0438\u044f<\/h3>\n<p>\u0412\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0441\u0440\u043e\u0447\u043a\u0438, \u043f\u0440\u0435\u0440\u0432\u0430\u0432\u0448\u0435\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 DOTG \u0443 \u043c\u0435\u043d\u044f \u0431\u044b\u043b\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043f\u043e\u0434\u0443\u043c\u0430\u0442\u044c, \u0442\u0430\u043a \u0438 \u043f\u0440\u0438\u0448\u043b\u0430 \u0432 \u0433\u043e\u043b\u043e\u0432\u0443 \u0438\u0434\u0435\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u043e\u0435 &#171;\u0447\u0443\u0434\u043e&#187;. \u0418\u043c\u0435\u044f \u043f\u0440\u0438 \u0441\u0435\u0431\u0435 \u0431\u043b\u043e\u043a\u043d\u043e\u0442 \u0438 \u043a\u0430\u0440\u0430\u043d\u0434\u0430\u0448 \u044f \u0443\u0436\u0435 \u0442\u043e\u0433\u0434\u0430 \u043d\u0430\u0447\u0430\u043b \u043d\u0430\u043a\u0438\u0434\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u043a \u0441\u043b\u043e\u0432\u0443, \u043d\u0438 \u043e\u0434\u043d\u0430 \u0438\u0437 \u043d\u0438\u0445 \u043d\u0435 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u043b\u0430\u0441\u044c. <\/p>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0434\u0430\u043d\u043d\u0443\u044e \u0438\u0434\u0435\u044e \u044f \u0431\u0435\u0440\u0435\u0433 \u043d\u0430 \u043a\u043e\u043d\u043a\u0443\u0440\u0441, \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u043c \u0444\u043e\u0440\u0443\u043c\u0435 \u0432 \u0441\u0444\u0435\u0440\u0435 SA:MP, \u043e\u0434\u043d\u0430\u043a\u043e \u0438\u0437-\u0437\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u0431\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u0441\u0442\u0432 \u043a\u043e\u043d\u043a\u0443\u0440\u0441 \u0432 2024 \u0433\u043e\u0434\u0443 \u0431\u044b\u043b \u043e\u0442\u043c\u0435\u043d\u0435\u043d. \u0412\u0430\u043c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0447\u0442\u043e \u044d\u0442\u0430 \u0438\u0434\u0435\u044f \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u043b\u0430\u0431\u0430 \u0434\u043b\u044f \u0443\u0447\u0430\u0441\u0442\u0438\u044f \u0432 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u043a\u043e\u043d\u043a\u0443\u0440\u0441\u0430\u0445, \u043e\u0434\u043d\u0430\u043a\u043e \u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0446\u0438\u044f \u0442\u0430\u043c \u043d\u0435 \u0432\u0435\u043b\u0438\u043a\u0430, \u0441\u0443\u043c\u043c\u0430 \u043f\u0440\u0438\u0437\u043e\u0432\u044b\u0445 \u0432 2023 \u0433\u043e\u0434\u0443 \u0434\u043e\u0441\u0442\u0438\u0433\u043b\u0430 \u0431\u043e\u043b\u0435\u0435 500.000 \u0440\u0443\u0431\u043b\u0435\u0439, \u0430 \u0432 2022 \u0433\u043e\u0434\u0443 \u044f \u0437\u0430\u043d\u044f\u043b \u043f\u0440\u0438\u0437\u043e\u0432\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u0432 <a href=\"https:\/\/www.blast.hk\/threads\/154592\/\" rel=\"noopener noreferrer nofollow\">Subway-CJ<\/a> &#8212; \u043f\u0430\u0440\u043e\u0434\u0438\u044e \u043d\u0430 \u0438\u0433\u0440\u0443 Subway Surfers \u0432 GTA:SA.<\/p>\n<h3>\u041a\u043b\u0430\u0441\u0441\u044b \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439<\/h3>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a MoonLoader API \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u043d\u0435 \u0434\u0440\u0443\u0436\u0438\u0442 \u0441 \u041e\u041e\u041f, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043d\u0430\u0447\u0430\u0442\u044c \u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0441\u0435\u0432\u0434\u043e\u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 \u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430\u043c\u0438. \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u0438 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"lua\">Object object = createObject(Model modelId, float atX, float atY, float atZ)  -- 0107 setObjectHeading(Object object, float angle)  -- 0177 setObjectRotation(Object object, float rotationX, float rotationY, float rotationZ)  -- 0453 setObjectPathSpeed(int int1, int int2)  -- 049E setObjectPathPosition(int int1, float float2)  -- 049F setObjectScale(Object object, float scale)  -- 08D2 bool result = setObjectCoordinates(Object object, float atX, float atY, float atZ)  -- 01BC setObjectVelocity(Object object, float velocityInDirectionX, float velocityInDirectionY, float velocityInDirectionZ)  -- 0381 setObjectCollision(Object object, bool collision)  -- 0382<\/code><\/pre>\n<p>\u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u0430\u0442\u0430\u0431\u043b\u0438\u0446 \u044f \u0441\u043e\u0437\u0434\u0430\u043b &#171;\u043a\u043b\u0430\u0441\u0441&#187; Object, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u043d\u0435 \u0441\u0442\u0430\u043b\u043e \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u043f\u0440\u043e\u0449\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438<\/p>\n<details class=\"spoiler\">\n<summary>object.lua<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"lua\">local Vector3D = require('vector3d'); local Object = {}; local pool = {};  addEventHandler('onScriptTerminate', function(scr)     if (scr == thisScript()) then         for k, v in ipairs(pool) do             v:destroy();         end     end end);  ---@class Object ---@field handle number ---@field tag string ---@field setCollision fun(self: Object, collision: boolean) ---@field destroy fun(self: Object) ---@field setScale fun(self: Object, scale: number) ---@field setRotation fun(self: Object, rotation: Vector3D) ---@field setPosition fun(self: Object, position: Vector3D)  setmetatable(Object, {__call = function(t, ...)     return t:new(...) end});  function Object:setCollision(bool)     self.collision = bool;     setObjectCollision(self.handle, bool); end  function Object:setRotation(rotation)     self.rotation = rotation;     setObjectRotation(self.handle, rotation.x, rotation.y, rotation.z); end  function Object:setPosition(pos)     self.pos = pos;     setObjectCoordinates(self.handle, pos.x, pos.y, pos.z); end  function Object:destroy()     deleteObject(self.handle);     print('Object:destroy(), handle =', self.handle);     for index, handle in ipairs(pool) do         if (handle == self.handle) then             table.remove(pool, index);         end     end end  function Object:setScale(scale)     self.scale = scale;     setObjectScale(self.handle, scale); end  function Object:new(model, pos, rotation, collision, scale, tag)     local handle = createObject(model, pos.x, pos.y, pos.z)     assert(doesObjectExist(handle), 'Error creating object.');     if (rotation) then         setObjectRotation(handle, rotation.x, rotation.y, rotation.z);     end     setObjectCollision(handle,<\/code><\/pre>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-445527","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/445527","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=445527"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/445527\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=445527"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=445527"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=445527"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}