Beispiel #1
0
func main() {
	rand.Seed(time.Now().Unix())
	logfile, err := os.Create("roguelike.log")
	if err != nil {
		panic(err)
	}
	log.SetOutput(logfile)

	initCurses()
	defer endCurses()

	currentLevel = level.New(level.Test)
	player = entity.NewPlayer()
	currentLevel.Put(player, 40, 13)

	drawCurrentLevel()
	drawInfoBar()

	for !quit {
		var a entity.Action

		switch ch := C.getch(); ch {
		case C.KEY_UP, 'k', '8':
			a = entity.MoveAction{direction.North}
		case C.KEY_DOWN, 'j', '2':
			a = entity.MoveAction{direction.South}
		case C.KEY_RIGHT, 'l', '6':
			a = entity.MoveAction{direction.East}
		case C.KEY_LEFT, 'h', '4':
			a = entity.MoveAction{direction.West}
		case 'y', '7':
			a = entity.MoveAction{direction.NorthWest}
		case 'u', '9':
			a = entity.MoveAction{direction.NorthEast}
		case 'm', '3':
			a = entity.MoveAction{direction.SouthEast}
		case 'n', '1':
			a = entity.MoveAction{direction.SouthWest}
		case 'i':
			updateInventory()
			displayInventory()
			C.getch()
		case ',':
			items := displayPickUpChoice()
			a = entity.PickUpAction{items}
		case 'q':
			quit = true
		}

		player.SetAction(a)
		currentLevel.Run()
		drawCurrentLevel()
		drawInfoBar()
	}

}
Beispiel #2
0
func consume(expects ...rune) bool {
	for _, r := range expects {
		if int(C.getch()) != int(r) {
			return false
		}
	}
	return true
}
func Hello(s string) {
	C.initscr()

	p := C.CString(fmt.Sprintf("Hello, %s", s))
	C.Printw(p)
	C.free(unsafe.Pointer(p))

	C.refresh()
	C.getch()
	C.endwin()
}
Beispiel #4
0
func Init(theme *ColorTheme, black bool, mouse bool) {
	C.setlocale(C.LC_ALL, C.CString(""))
	tty := C.c_tty()
	if tty == nil {
		fmt.Println("Failed to open /dev/tty")
		os.Exit(2)
	}
	_screen = C.c_newterm(tty)
	if _screen == nil {
		fmt.Println("Invalid $TERM: " + os.Getenv("TERM"))
		os.Exit(2)
	}
	C.set_term(_screen)
	if mouse {
		C.mousemask(C.ALL_MOUSE_EVENTS, nil)
		C.mouseinterval(0)
	}
	C.noecho()
	C.raw() // stty dsusp undef
	C.nonl()
	C.keypad(C.stdscr, true)

	delay := 50
	delayEnv := os.Getenv("ESCDELAY")
	if len(delayEnv) > 0 {
		num, err := strconv.Atoi(delayEnv)
		if err == nil && num >= 0 {
			delay = num
		}
	}
	C.set_escdelay(C.int(delay))

	_color = theme != nil
	if _color {
		C.start_color()
		InitTheme(theme, black)
		initPairs(theme)
		C.bkgd(C.chtype(C.COLOR_PAIR(C.int(ColNormal))))
		_colorFn = attrColored
	} else {
		_colorFn = attrMono
	}

	C.nodelay(C.stdscr, true)
	ch := C.getch()
	if ch != C.ERR {
		C.ungetch(ch)
	}
	C.nodelay(C.stdscr, false)
}
Beispiel #5
0
func escSequence() Event {
	C.nodelay(C.stdscr, true)
	defer func() {
		C.nodelay(C.stdscr, false)
	}()
	c := C.getch()
	switch c {
	case C.ERR:
		return Event{ESC, 0, nil}
	case CtrlM:
		return Event{AltEnter, 0, nil}
	case '/':
		return Event{AltSlash, 0, nil}
	case ' ':
		return Event{AltSpace, 0, nil}
	case 127, C.KEY_BACKSPACE:
		return Event{AltBS, 0, nil}
	case '[':
		// Bracketed paste mode (printf "\e[?2004h")
		// \e[200~ TEXT \e[201~
		if consume('2', '0', '0', '~') {
			return Event{Invalid, 0, nil}
		}
	}
	if c >= 'a' && c <= 'z' {
		return Event{AltA + int(c) - 'a', 0, nil}
	}

	if c >= '0' && c <= '9' {
		return Event{Alt0 + int(c) - '0', 0, nil}
	}

	// Don't care. Ignore the rest.
	for ; c != C.ERR; c = C.getch() {
	}
	return Event{Invalid, 0, nil}
}
Beispiel #6
0
func displayPickUpChoice() []entity.ID {
	var str *C.char
	C.clear()
	C.move(0, 0)
	str = C.CString("Pick up what?\n")
	C.addstr(str)
	C.free(unsafe.Pointer(str))

	px, py := currentLevel.EntityLocation(player.EntityID())
	itemsAvailable := currentLevel.ItemsAt(px, py)
	for i, eid := range itemsAvailable {
		C.addch(C.chtype(inventoryChar(byte(i))))
		str = C.CString(" - ")
		C.addstr(str)
		C.free(unsafe.Pointer(str))
		str = C.CString(currentLevel.EntityByID(eid).EntityName())
		C.addstr(str)
		C.free(unsafe.Pointer(str))
	}

	itemsChosen := make([]bool, len(itemsAvailable))
	for {
		ch := C.getch()
		if ch == C.KEY_ENTER || ch == ' ' || ch == '\n' {
			break
		}
		if ch > C.int(255) {
			continue
		}
		if i := inventoryIndex(byte(ch)); (int(i) < len(itemsChosen)) &&
			(i != 255) {
			if itemsChosen[i] {
				itemsChosen[i] = false
				C.mvaddch(C.int(i+1), 2, C.chtype('-'))
			} else {
				itemsChosen[i] = true
				C.mvaddch(C.int(i+1), 2, C.chtype('+'))
			}
		}
	}

	result := make([]entity.ID, 0, len(itemsAvailable))
	for i, v := range itemsChosen {
		if v {
			result = append(result, itemsAvailable[i])
		}
	}
	return result
}
Beispiel #7
0
func (r *FullscreenRenderer) Init() {
	C.setlocale(C.LC_ALL, C.CString(""))
	tty := C.c_tty()
	if tty == nil {
		errorExit("Failed to open /dev/tty")
	}
	_screen = C.c_newterm(tty)
	if _screen == nil {
		errorExit("Invalid $TERM: " + os.Getenv("TERM"))
	}
	C.set_term(_screen)
	if r.mouse {
		C.mousemask(C.ALL_MOUSE_EVENTS, nil)
		C.mouseinterval(0)
	}
	C.noecho()
	C.raw() // stty dsusp undef
	C.nonl()
	C.keypad(C.stdscr, true)

	delay := 50
	delayEnv := os.Getenv("ESCDELAY")
	if len(delayEnv) > 0 {
		num, err := strconv.Atoi(delayEnv)
		if err == nil && num >= 0 {
			delay = num
		}
	}
	C.set_escdelay(C.int(delay))

	if r.theme != nil {
		C.start_color()
		initTheme(r.theme, r.defaultTheme(), r.forceBlack)
		initPairs(r.theme)
		C.bkgd(C.chtype(C.COLOR_PAIR(C.int(ColNormal.index()))))
		_colorFn = attrColored
	} else {
		initTheme(r.theme, nil, r.forceBlack)
		_colorFn = attrMono
	}

	C.nodelay(C.stdscr, true)
	ch := C.getch()
	if ch != C.ERR {
		C.ungetch(ch)
	}
	C.nodelay(C.stdscr, false)
}
Beispiel #8
0
func Getch() int {
	return int(C.getch())
}
Beispiel #9
0
func getch(termDescriptor int) byte {
	return byte(C.getch(C.int(termDescriptor)))
}
Beispiel #10
0
func (r *FullscreenRenderer) GetChar() Event {
	c := C.getch()
	switch c {
	case C.ERR:
		// Unexpected error from blocking read
		r.Close()
		errorExit("Failed to read /dev/tty")
	case C.KEY_UP:
		return Event{Up, 0, nil}
	case C.KEY_DOWN:
		return Event{Down, 0, nil}
	case C.KEY_LEFT:
		return Event{Left, 0, nil}
	case C.KEY_RIGHT:
		return Event{Right, 0, nil}
	case C.KEY_HOME:
		return Event{Home, 0, nil}
	case C.KEY_END:
		return Event{End, 0, nil}
	case C.KEY_BACKSPACE:
		return Event{BSpace, 0, nil}
	case C.KEY_F0 + 1:
		return Event{F1, 0, nil}
	case C.KEY_F0 + 2:
		return Event{F2, 0, nil}
	case C.KEY_F0 + 3:
		return Event{F3, 0, nil}
	case C.KEY_F0 + 4:
		return Event{F4, 0, nil}
	case C.KEY_F0 + 5:
		return Event{F5, 0, nil}
	case C.KEY_F0 + 6:
		return Event{F6, 0, nil}
	case C.KEY_F0 + 7:
		return Event{F7, 0, nil}
	case C.KEY_F0 + 8:
		return Event{F8, 0, nil}
	case C.KEY_F0 + 9:
		return Event{F9, 0, nil}
	case C.KEY_F0 + 10:
		return Event{F10, 0, nil}
	case C.KEY_F0 + 11:
		return Event{F11, 0, nil}
	case C.KEY_F0 + 12:
		return Event{F12, 0, nil}
	case C.KEY_DC:
		return Event{Del, 0, nil}
	case C.KEY_PPAGE:
		return Event{PgUp, 0, nil}
	case C.KEY_NPAGE:
		return Event{PgDn, 0, nil}
	case C.KEY_BTAB:
		return Event{BTab, 0, nil}
	case C.KEY_ENTER:
		return Event{CtrlM, 0, nil}
	case C.KEY_SLEFT:
		return Event{SLeft, 0, nil}
	case C.KEY_SRIGHT:
		return Event{SRight, 0, nil}
	case C.KEY_MOUSE:
		var me C.MEVENT
		if C.getmouse(&me) != C.ERR {
			mod := ((me.bstate & C.BUTTON_SHIFT) | (me.bstate & C.BUTTON_CTRL) | (me.bstate & C.BUTTON_ALT)) > 0
			x := int(me.x)
			y := int(me.y)
			/* Cannot use BUTTON1_DOUBLE_CLICKED due to mouseinterval(0) */
			if (me.bstate & C.BUTTON1_PRESSED) > 0 {
				now := time.Now()
				if now.Sub(r.prevDownTime) < doubleClickDuration {
					r.clickY = append(r.clickY, y)
				} else {
					r.clickY = []int{y}
					r.prevDownTime = now
				}
				return Event{Mouse, 0, &MouseEvent{y, x, 0, true, false, mod}}
			} else if (me.bstate & C.BUTTON1_RELEASED) > 0 {
				double := false
				if len(r.clickY) > 1 && r.clickY[0] == r.clickY[1] &&
					time.Now().Sub(r.prevDownTime) < doubleClickDuration {
					double = true
				}
				return Event{Mouse, 0, &MouseEvent{y, x, 0, false, double, mod}}
			} else if (me.bstate&0x8000000) > 0 || (me.bstate&0x80) > 0 {
				return Event{Mouse, 0, &MouseEvent{y, x, -1, false, false, mod}}
			} else if (me.bstate & C.BUTTON4_PRESSED) > 0 {
				return Event{Mouse, 0, &MouseEvent{y, x, 1, false, false, mod}}
			}
		}
		return Event{Invalid, 0, nil}
	case C.KEY_RESIZE:
		return Event{Resize, 0, nil}
	case ESC:
		return escSequence()
	case 127:
		return Event{BSpace, 0, nil}
	}
	// CTRL-A ~ CTRL-Z
	if c >= CtrlA && c <= CtrlZ {
		return Event{int(c), 0, nil}
	}

	// Multi-byte character
	buffer := []byte{byte(c)}
	for {
		r, _ := utf8.DecodeRune(buffer)
		if r != utf8.RuneError {
			return Event{Rune, r, nil}
		}

		c := C.getch()
		if c == C.ERR {
			break
		}
		if c >= C.KEY_CODE_YES {
			C.ungetch(c)
			break
		}
		buffer = append(buffer, byte(c))
	}
	return Event{Invalid, 0, nil}
}
Beispiel #11
0
func getch() byte {
	return byte(C.getch())
}