# 서버 스크립트

## 서버 스크립트 <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**](https://docs.punkland.io/punkland/punkland-studio/script/undefined-1/scriptclan)   | 유저가 속한 클랜을 가져온다.                 |
| [**ScriptColor**](https://docs.punkland.io/punkland/punkland-studio/script/undefined-1/scriptcolor) | 색상 정보를 가져온다.                     |

* 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 %}
