Spoiler 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
dofile("sys/lua/wrapper.lua")
CREATURE = {
    ALIVE = {},
    LIST = {
        {
            NAME = "Zombie",
            HITPOINT = 100,
            MOVESPEED = 6,
            VISION = 400,
            IMAGE = "gfx/npc/vortigaunt.bmp",
            SOUND = {},
            HIT_MODE = 103,
            HIT_ZONE = 22,
            ATTACK = { DAMAGE = 0, RANGE = 32, SPEED = 0, TYPE = 0 },
            SPAWN = { RATE = 100, TILE = {}, LIMIT = 5, POSITION = {{0, 0}, {100, 100}} }
        }
    }
}
hook("startround", function() CREATURE.ALIVE = {} end)
hook("ms100", function()
    if #CREATURE.ALIVE < 5 then
        local creature, tile_x, tile_y = deepcopy(CREATURE.LIST[1])
        repeat tile_x, tile_y = math.random(creature.SPAWN.POSITION[1][1], creature.SPAWN.POSITION[2][1]), math.random(creature.SPAWN.POSITION[1][2], creature.SPAWN.POSITION[2][2])
        until tile(tile_x, tile_y, "walkable")
        creature.POSITION_X, creature.POSITION_Y = math.floor(tile_x * 32 + 16), math.floor(tile_y * 32 + 16)
        CREATURE:insert(creature)
    end
    for _, creature in pairs(CREATURE.ALIVE) do creature:update() end
end)
hook("hitzone", function(z, x, c, v, b, n, m)
    for _, creature in pairs(CREATURE.ALIVE) do
        msg("aaa")
        if z == creature.IMAGE then
            creature.HITPOINT = creature.HITPOINT - m
            if creature.HITPOINT <= 0 then creature:remove() end
        end
        return true
    end
end)
hook("hit", function(player_id, source, weapon_id, hit_damage)
    if type(source) == "table" then
        local health = player(player_id, "health") - hit_damage
        if health > 0 then
            parse("sethealth "..player_id.." "..health)
        else
            parse("customkill "..source.NAME.." \"kill\" "..player_id)
        end
        return 1
    end
end)
function CREATURE:update()
    local target
    for _, player_id in pairs(shuffle(player(0, "table"))) do
        if player(player_id, "health") <= 0 then return end
        local distance = math.sqrt((player(player_id, "x") - self.POSITION_X) ^ 2 + (player(player_id, "y") - self.POSITION_Y) ^ 2)
        if distance > self.VISION then return end
        if not target or distance < target[2] then target = { player_id, distance } self.TARGET_ID = target[1] end
    end
    if self.TARGET_ID then
        if player(self.TARGET_ID, "health") > 0 then
            local distance_x, distance_y = player(self.TARGET_ID, "x") - self.POSITION_X, player(self.TARGET_ID, "y") - self.POSITION_Y
            local distance = math.sqrt(distance_x ^ 2 + distance_y ^ 2)
            if distance <= self.VISION then
                self.MOVE_ROTATION = math.atan2(distance_y, distance_x) - math.pi / 2 + math.random(-1, 1) / 2
                self.LOOK_ROTATION = math.deg(math.atan2(distance_y, distance_x)) + 90
                if distance <= self.ATTACK.RANGE then msg("hit") end
            else self.TARGET_ID = nil end
        else self.TARGET_ID = nil end
    else self:rotate(math.random(-1, 1) / 2) end
    if not self:setpos(self:rotate(), self.HITPOINT > 0 and 1 or -1) then repeat until self:setpos(math.rad(math.random(360)), 1) end
end
function CREATURE:insert(creature)
    creature.IMAGE = image(creature.IMAGE, creature.POSITION_X, creature.POSITION_Y, 0)
    imagehitzone(creature.IMAGE, creature.HIT_MODE, -creature.HIT_ZONE / 2, -creature.HIT_ZONE / 2, creature.HIT_ZONE, creature.HIT_ZONE)
    setmetatable(creature, self) self.__index = self
    creature.INDEX = #CREATURE.ALIVE
    table.insert(CREATURE.ALIVE, creature)
end
function CREATURE:remove()
    freeimage(self.IMAGE)
    table.remove(CREATURE.ALIVE, self.INDEX)
    for index, creature in pairs(CREATURE.ALIVE) do creature.INDEX = index end
end
function CREATURE:setpos(rotation_angle, distance_factor)
    local position_x, position_y = self.POSITION_X + -math.sin(rotation_angle) * distance_factor * self.MOVESPEED, self.POSITION_Y + math.cos(rotation_angle) * distance_factor * self.MOVESPEED
    local tile_x, tile_y = math.floor(position_x / 32), math.floor(position_y / 32)
    if tile(tile_x, tile_y, "walkable") and tile(tile_x, tile_y, "frame") ~= 251 then
        if not self.TARGET_ID then self.LOOK_ROTATION = -math.deg(math.atan2((self.POSITION_X - position_x), (self.POSITION_Y - position_y))) end
        self.POSITION_X, self.POSITION_Y = position_x, position_y
        tween_move(self.IMAGE, 100, self.POSITION_X, self.POSITION_Y, self.LOOK_ROTATION)
        return true
    else
        self:rotate(math.random(-1, 1) * 2 / math.pi)
        return false
    end
end
function CREATURE:rotate(rotation)
    if not rotation then return self.MOVE_ROTATION else self.MOVE_ROTATION = (self.MOVE_ROTATION + rotation) % (2 * math.pi) end
end
script is work fine, it just horde of zombies will merge into one tile when chasing the player, and the player will die in a single attack
 
  CS2D
 CS2D  image collision
 image collision 
  1
 1 
 Offline
 Offline
 
  Masea
 Masea