# 서버 스크립트

## 서버 스크립트 <a href="#undefined" id="undefined"></a>

* 서버 스크립트는 프로젝트 폴더 혹은 Scripts에 Hello.lua와 같은 파일 이름으로 존재해야 읽힙니다.

| 스크립트                                                                           | 설명                               |
| ------------------------------------------------------------------------------ | -------------------------------- |
| **Server.onJoinPlayer(unit)**                                                  | 새로운 플레이어가 접속                     |
| **Server.onLeavePlayer(unit)**                                                 | 특정 유저가 게임 퇴장                     |
| **Server.SendCenterLabel(text)**                                               | 가운데 라벨 표시                        |
| **Server.SendSay(text, color)**                                                | 채팅 창에 메시지 표시                     |
| **ScriptEventPublisher Server.GetTopic(topic)**                                | 클라이언트와 메시지를 주고받기 위해 특정 주제를 등록한다. |
| **Server.FireEvent(topic, args…)**                                             | 클라이언트에게 특정 topic으로 메시지를 전송한다.    |
| **Server.players**                                                             | 플레이어 목록을 가져온다.                   |
| **Server.fields**                                                              | 전체 맵 목록을 가져온다.                   |
| **Server.CreateEventUnit(name, imageID)**                                      | 이벤트 유닛을 만든다.                     |
| **Server.GetField(dataID)**                                                    | 특정 아이디의 맵을 가져온다.                 |
| **ScriptUnit**                                                                 | 몬스터나 플레이어와 같은 객체다.               |
| **Server.playerLeavePartyCallback(scriptRoomPlayer,scriptParty)**              | 플레이어가 파티를 떠날 때 호출됩니다.            |
| **Server.playerJoinPartyCallback(scriptRoomPlayer,scriptParty)**               | 플레이어가 파티에 들어갈 때 호출됩니다.           |
| **Server.onAddItem(scriptUnit,titem)**                                         | 유저가 아이템을 획득할 때 호출됩니다.            |
| **Server.onRemoveItem(scriptUnit,titem)**                                      | 유저의 아이템을 제거 및 사용할 때 호출됩니다.       |
| [**ScriptClan**](/punkland/punkland-studio/script/undefined-1/scriptclan.md)   | 유저가 속한 클랜을 가져온다.                 |
| [**ScriptColor**](/punkland/punkland-studio/script/undefined-1/scriptcolor.md) | 색상 정보를 가져온다.                     |

* unit.type = 유닛의 타입 (0=플레이어, 1=이벤트, 2=몬스터)

**예) 서버 스크립트 - 플레이어 레벨업 시 메시지 출력 및 특정 레벨 달성 시 아이템 지급**

{% code title="Scripts/Servers/Hello.lua" overflow="wrap" lineNumbers="true" %}

```lua
function onUnitLevelUp(target, level)
    if target.level == 50 then --타겟이 레벨 50 달성 시 서버 전체에 알림을 띄우고 1번 아이템을 지급한다.
        Server.SendCenterLabel(target.name .. '님이 ' .. level .. '이 되었습니다!')
        target.AddItem(1) 
    elseif target.level == 55 then  --타겟이 레벨 55 달성 시 5번 스킬과 5,000게임 머니를 지급한다. 
        target.AddSkill(5)
        target.AddGameMoney(5000)
    end
end
 
Server.onUnitLevelUp.Add(onUnitLevelUp)
```

{% endcode %}

**예제) 서버 스크립트 - PVP로 플레이어 처치 시 서버 전체 메시지 출력 및 보상 지급**

{% code title="Scripts/Servers/Hello.lua" overflow="wrap" lineNumbers="true" %}

```lua
function onUnitDead(target, attacker) --target은 죽 은자, attacker는 공격 자
    if (target.type==0 and attacker.type==0) then --PlayerUnit일 경우
        Server.SendCenterLabel(target.name..'을(를) \n'..attacker.name..'이(가) 죽였다.')
        attacker.AddGameMoney(100) --공격자에게 100골드을 준다.
        if rand(1, 100) <= 50 then
            attacker.AddItem(100) --공격자에게 50% 확률로 1번 아이템을 준다.
        end
    end
end
Server.onUnitDead.Add(onUnitDead) -- Server.onUnitDead에 onUnitDead 함수를 추가한다.
```

{% endcode %}

**onJoinField 활용 방법 - 특정 맵에 입장 시 이름 출력 및 서버 전체 메시지 보내기**

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

```lua
function onJoinField()
    function onJoinField_1(Field,unit)
        unit.SendCenterLabel(Field.name) -- 유닛에게 잠시 필드 이름을 표시한다.
        if #Field.playerUnits > 10 then -- #은 테이블의 길이를 의미한다.
            Server.SendSay(Field.name.."에 11명 이상의 플레이어가 모였습니다!")
        end
    end
        local map = Server.GetField(1)
        if map ~= nil then
                map.onJoinField.Add(onJoinField_1)--1번 필드에 입장 시 onJoinField_1 함수를 호출한다. 
        end
end
Server.RunLater(onJoinField,1) -- 1초 후 onJoinField 함수를 실행한다.
-- 1초 후 실행하는 이유는 서버 실행 후 맵이 생성되지 않았을 수 있기 떄문에 nil을 참조하는 것을 방지하기 위함입니다.
```

{% endcode %}

**onLeaveField -특정 맵 퇴장 시 처리**

> 인자 map - ScriptField
>
> 인자 unit - ScriptUnit

파일: 해당 맵에서 스크립트로 작성 사용 예시) 맵 퇴장 시 월드 변수의 값이 1 감소한다.

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

```lua
function onLeaveField(map,unit)
  print('떠난다: ' .. map.name .. ' ' ..unit.name)
  Server.SetWorldVar(10, Server.GetWorldVar(10)-1)
end

Server.GetField(5).onLeaveField.Add(onLeaveField)
```

{% endcode %}

**예) 아이템 사용(onUseItem), 구매(onBuyGameMoneyItem), 판매(onSellGameMoneyItem)시 발생하는 이벤트**

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

```lua
Server.onUseItem.Add(
function(unit,item)
    print(unit.name)
    print(item.dataID)
  end)
  
Server.onBuyGameMoneyItem.Add(
  function(unit,itemID,count)
    print(string.format("%s ,%s ,%s",unit.name,itemID,count))
  end)
  
Server.onSellGameMoneyItem.Add(
  function(unit,itemID,count)
    print(string.format("%s,%s,%s",unit.name,itemID,count))
  end)
```

{% endcode %}

**예) 아이템 옵션 추가, 제거, 변경(ScriptUtility 참고)**

* 코드에 적용된 주석(--)을지워가면서 테스트 해보시길 바랍니다. 밑의 스크립트는 터치 시 이벤트 - 스크립트로 실행했습니다.

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

```lua
-- 인벤토리에서 첫번째 아이템의 정보를 가져옵니다.
local item = unit.player.GetItems()[1]
local option1 = item.options[1]
--Utility.SetItemOption(option1,option1.type,option1.statID,option1.value+1)
--Server.SendItemUpdated(item)
Utility.AddItemOption(unit.player.GetItems()[1],1,3,5)
--unit.player.RemoveItemOption(item,1)
unit.player.SendItemUpdated(item)
```

{% endcode %}

**예) 파티 입장 시 발생하는 이벤트(playerJoinPartyCallback)**

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

```lua
Server.playerJoinPartyCallback =
function(scriptRoomPlayer,scriptParty) 
        print(scriptRoomPlayer.unit.name)
        print(scriptParty.maxPlayer)
        -- return 을 true 로해야 파티가 생성됩니다. 조건에 따라서 return true,false를 지정하면 됩니다.
        return true
end
```

{% endcode %}

**예) 파티 퇴장 시 발생하는 이벤트(playerLeavePartyCallback)**

```lua
Server.playerLeavePartyCallback = 
function(scriptRoomPlayer,scriptParty) 
        print(scriptRoomPlayer.unit.name)
        print(scriptParty.maxPlayer)
end
```

**예) 아이템 획득 시 이벤트(onAddItem)**

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

```lua
Server.onAddItem.Add(
function(scriptUnit,titem) 
        print(scriptUnit.name)
        print(titem.dataID)        
end)
```

{% endcode %}

**예) 아이템 제거 시 이벤트(onRemoveItem)**

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

```lua
Server.onRemoveItem.Add(
function(scriptUnit,titem) 
        print(scriptUnit.name)
        print(titem.id)
        print(titem.dataID)        
end)
```

{% endcode %}

**예) 피해 적용 시 발생하는 이벤트(damageCallback)**

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

```lua
-- 피해량이 0일 경우 피해량 출력 안 됨
-- a,b ScriptUnit
Server.damageCallback = function(a, b, damage, skillDataID, critical, visible)
        damage = a.atk - b.def
        if damage <= 0  then
                visible = false
        end
        return damage, critical, visible;
end
```

{% endcode %}

**예) 거래 완료 시 발생하는 이벤트(onTradeDone)**

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

```lua
function Trade(sender,receiver,senderItems,receiverItems)
print("sender: ")
print(sender.unit.name)
print("receiver: ")
print(receiver.unit.name)
print("senderItems: ")
print(senderItems)
for i=1 , #senderItems do
        print(i..": ")
        print(Server.GetItem(senderItems[i].dataID).name)
end
print("receiverItems: ")
print(receiverItems)
for j=1 , #receiverItems do
        print(j..": ")
        print(Server.GetItem(receiverItems[j].dataID).name)
end
end

Server.onTradeDone.Add(Trade)
```

{% 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/punkland-studio/script/undefined-1.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.
