func (state *npcScriptState) SendSelection(msg string) {
	state.conn.Send(packetNpcChatSelection(state.npcID, msg))
}
SendSelection packet to player
package channel
import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"
	"github.com/Hucaru/Valhalla/mnet"
	"github.com/dop251/goja"
	"github.com/fsnotify/fsnotify"
)
type scriptStore struct {
	folder   string
	scripts  map[string]*goja.Program
	dispatch chan func()
}
func createScriptStore(folder string, dispatch chan func()) *scriptStore {
	return &scriptStore{folder: folder, dispatch: dispatch, scripts: make(map[string]*goja.Program)}
}
func (s scriptStore) String() string {
	return fmt.Sprintf("%v", s.scripts)
}
func (s *scriptStore) get(name string) (*goja.Program, bool) {
	program, ok := s.scripts[name]
	return program, ok
}
func (s *scriptStore) loadScripts() error {
	err := filepath.Walk(s.folder, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			return nil
		}
		name, program, err := createScriptProgramFromFilename(path)
		if err == nil {
			s.scripts[name] = program
		} else {
			log.Println("Script compiling:", err)
		}
		return nil
	})
	return err
}
func (s *scriptStore) monitor(task func(name string, program *goja.Program)) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Println(err)
	}
	defer watcher.Close()
	err = watcher.Add(s.folder)
	if err != nil {
		log.Println(err)
	}
	for {
		select {
		case event, ok := <-watcher.Events:
			if !ok {
				return
			}
			if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create {
				s.dispatch <- func() {
					log.Println("Script:", event.Name, "modified/created")
					name, program, err := createScriptProgramFromFilename(event.Name)
					if err == nil {
						s.scripts[name] = program
						task(name, program)
					} else {
						log.Println("Script compiling:", err)
					}
				}
			} else if event.Op&fsnotify.Remove == fsnotify.Remove {
				s.dispatch <- func() {
					name := filepath.Base(event.Name)
					name = strings.TrimSuffix(name, filepath.Ext(name))
					if _, ok := s.scripts[name]; ok {
						log.Println("Script:", event.Name, "removed")
						task(name, nil)
						delete(s.scripts, name)
					} else {
						log.Println("Script: could not find:", name, "to delete")
					}
				}
			}
		case err, ok := <-watcher.Errors:
			if !ok {
				return
			}
			log.Println(err)
		}
	}
}
func createScriptProgramFromFilename(filename string) (string, *goja.Program, error) {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return "", nil, err
	}
	program, err := goja.Compile(filename, string(data), false)
	if err != nil {
		return "", nil, err
	}
	filename = filepath.Base(filename)
	name := strings.TrimSuffix(filename, filepath.Ext(filename))
	return name, program, nil
}
type warpFn func(plr *player, dstField *field, dstPortal portal) error
type npcScriptState struct {
	npcID       int32
	conn        mnet.Client
	terminate   bool
	selection   int32
	inputString string
	inputNumber int32
	yes, no, next, back bool  
	goods [][]int32
	warpFunc warpFn
	fields   map[int32]*field
}
func (state *npcScriptState) Id() int32 {
	return state.npcID
}
func (state *npcScriptState) SendBackNext(msg string, back, next bool) {
	state.conn.Send(packetNpcChatBackNext(state.npcID, msg, next, back))
}
func (state *npcScriptState) SendOK(msg string) {
	state.conn.Send(packetNpcChatOk(state.npcID, msg))
}
func (state *npcScriptState) SendYesNo(msg string) {
	state.conn.Send(packetNpcChatYesNo(state.npcID, msg))
}
func (state *npcScriptState) SendInputText(msg, defaultInput string, minLength, maxLength int16) {
	state.conn.Send(packetNpcChatUserString(state.npcID, msg, defaultInput, minLength, maxLength))
}
func (state *npcScriptState) SendInputNumber(msg string, defaultInput, minLength, maxLength int32) {
	state.conn.Send(packetNpcChatUserNumber(state.npcID, msg, defaultInput, minLength, maxLength))
}