# Monster AI

* Monster AI scripts must be saved in the project folder/ServerScripts with a file name like Hello.lua to be read.

<table><thead><tr><th width="211">script</th><th>explanation</th></tr></thead><tbody><tr><td><strong>enemy</strong></td><td>Represents the ScriptUnit of a monster.</td></tr><tr><td><strong>ai</strong></td><td>Represents an AI behavior to be executed in ScriptEnemyUnitAI.</td></tr><tr><td><strong>event</strong></td><td>Check the logic to be executed.</td></tr><tr><td><strong>AI_INIT(-1)</strong></td><td>First run when registering monster AI</td></tr><tr><td><strong>AI_UPDATE(0)</strong></td><td>Keep running every 2 seconds</td></tr><tr><td><strong>AI_ATTACKED(1)</strong></td><td>Runs once per attack</td></tr><tr><td><strong>AI_DEAD(2)</strong></td><td>Runs once on death</td></tr><tr><td><strong>data</strong></td><td>It can only be used when attacking, and when (event == 1), you can check damage, skill ID, and whether it is critical (true, false) information.</td></tr></tbody></table>

Example) Server script - Setting monster AI

{% code overflow="wrap" lineNumbers="true" %}

```lua
 Server.SetMonsterAI(
        22, --Index of monsters to which AI will be applied
        function(enemy,ai,event,data)
        -- Runs when registering the first monster AI
        if(event == AI_INIT) then
                 ai.customData.test = 1;
        end
        if (event == AI_UPDATE) then
                --Returns the units that meet the condition among the units in the current field.
                --Example) Bring when there is an enemy with unit HP less than 100.
                --ai.SetTargetUnit(
                --        enemy.field.FindUnit(enemy.x, enemy.y, 200,
                --       function(u)
                --                return u.hp <= 100
                --        end
                --, 0,enemy))
                
                --Returns the unit that satisfies the smallest condition among the units in the current field.
                --Example) Bring the enemy with the lowest HP among the player units.
                --ai.SetTargetUnit(
                --        enemy.field.FindMinimumUnit(enemy.x, enemy.y, 200,
                --        function(u)
                --                return u.hp
                --        end
                --, 0,enemy))

                --Returns the unit that meets the largest condition among the units in the current field.
                --Example) Bring the enemy with the most HP among the player units.
                --ai.SetTargetUnit(
               --        enemy.field.FindMaximumUnit(enemy.x, enemy.y, 200,
                --        function(u)
                --               return u.hp
                --        end
                --, 0,enemy))
                
               --If no target is set, the closest player is targeted.
                if( ai.GetTargetUnit() == nil) then
                        ai.SetNearTarget(0,200)
                end
                
                --Set to null if there are no players on the map.
                if( enemy.field.playerCount <=0) then
                        ai.SetTargetUnit(nil)
                        
                --If the targeted player leaves the map, retarget.
                elseif(enemy.field.GetUnit(ai.GetTargetUnitID()) == nil) then
                        ai.SetNearTarget(0,200)
                end
                
                --If there is a target, attack in the direction of the target.
                ai.UseSkill(22);

                --Left attack
                ai.UseSkill(22,Point(-1,0))

                --Right attack
                ai.UseSkill(22,Point(1,0))

                --Attack from above
                ai.UseSkill(22,Point(0,1))

                --Downward attack
                ai.UseSkill(22,Point(0,-1))

                --Attack the location
                ai.UseSkillToPosition(24,Point(150,-150))
                
                --Exception handling when target is not found
                if(ai.GetTargetUnit() == nil) then
                        return
                end
                
                --Enable/disable tracking based on target's HP
                if(ai.GetTargetUnit().hp <=150) then
                        ai.SetFollowTarget(false)
                else
                        ai.SetFollowTarget(true)
               end
                
        end

       if (event == AI_ATTACKED) then
                enemy.Say('I was attacked. \nDamage: ' .. data.damage 
                .. '\nSkillID: '..data.skillDataID
                .. '\nWhether it is critical or not: '..(data.critical and 'true' or 'false'))
                
                --Exception handling when there is no unit attacking
                if(ai.GetAttackedUnit() == nil) then
                        return
               end
                 --Check the HP of the attacked enemy and change target if it is less than 100.
                if(ai.GetAttackedUnit().hp <= 100) then
                        ai.SetTargetUnit(ai.GetAttackedUnit()) 
                end

        end

        if (event == AI_DEAD) then
                Server.SendSay('dying')
                --Resurrect at a specific location after death
                enemy.RespawnAt(150,-150)
        end

end)
```

{% endcode %}

Example) Server script - Monster AI preemptive attack monster

{% code overflow="wrap" lineNumbers="true" %}

```
function firstAttack(enemy,ai,event,data)
    if (event == 0) then -- Event that runs every 2 seconds
    
        --Set to null if there are no players on the map.
        if enemy.field.playerCount <=0 then
            ai.SetTargetUnit(nil)
            
        -- If there is no target, or the existing target unit leaves the map, or the absolute value of the difference in x or y values ​​exceeds 300.
        -- Initialize target to nil and set target within 200 range
        elseif (ai.GetTargetUnit()==nil)
               or (enemy.field.GetUnit(ai.GetTargetUnitID())==nil)
               or (math.abs(enemy.x-enemy.field.GetUnit(ai.GetTargetUnitID()).x) >= 300) 
               or (math.abs(enemy.y-enemy.field.GetUnit(ai.GetTargetUnitID()).y) >= 300) then
            
            if ai.GetTargetUnit() ~= nil then
                enemy.say('The target is gone...')
            end
            
            ai.SetFollowTarget(false) --Disable tracking when target disappears
            ai.SetTargetUnit(nil)
            ai.SetNearTarget(0,200)

            -- When a target is found after searching the surroundings (if it is not nil), enable tracking (true) and output a message.
            if ai.GetTargetUnit() ~= nil then 
                ai.SetFollowTarget(true) 
                enemy.say('Target' detected! \nTracking begins!')
            end
        end
        
        --When a target exists, fire the skill 10 times toward the target.
        if ai.GetTargetUnit() ~= nil then
            ai.UseSkill(10)
        end
        
        --Exception handling when target is absent
        if ai.GetTargetUnit() == nil then
            return
        end
        
    end
    
    if (event == 1) then -- An event that runs whenever a monster is attacked.
        --Exception handling when there is no unit attacking
        if ai.GetAttackedUnit() == nil then
            return
        else
            --If the existing target unit and attacking unit are not the same, target or change the attacking unit and track it.
            if ai.GetTargetUnit() ~= ai.GetAttackedUnit() then 
                ai.SetTargetUnit(ai.GetAttackedUnit())
                ai.SetFollowTarget(true)
                enemy.say('Tracking a new attacker...')
            end
            
            -- When a monster is hit, there is a 10% chance that it will cast a special attack skill 5 times and then output a message to the entire server.
            if math.random(0,99) <= 9 then
                ai.UseSkill(5)
                Server.SendCenterLabel('<color=#FF0000>Crooked!!</color>\nStupid boss Badun cries!')
            end
        end
    end
        
end

Server.SetMonsterAI(1, firstAttack) -- Apply firstAttack to monster 1
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.punkland.io/punkland-studio/script/script/monster-ai.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
