summaryrefslogtreecommitdiff
path: root/asciifarm
diff options
context:
space:
mode:
Diffstat (limited to 'asciifarm')
-rw-r--r--asciifarm/client/commandhandler.py16
-rw-r--r--asciifarm/client/display/display.py26
-rw-r--r--asciifarm/client/display/switcher.py26
-rw-r--r--asciifarm/client/gameclient.py51
-rw-r--r--asciifarm/client/inputhandler.py33
-rw-r--r--asciifarm/client/listselector.py49
-rw-r--r--asciifarm/client/main.py61
-rw-r--r--asciifarm/client/newdisplay/__init__.py0
-rw-r--r--asciifarm/client/newdisplay/display.py174
-rw-r--r--asciifarm/client/newdisplay/layout.xml30
-rw-r--r--asciifarm/client/switchselector.py33
11 files changed, 419 insertions, 80 deletions
diff --git a/asciifarm/client/commandhandler.py b/asciifarm/client/commandhandler.py
index ca72b68..e55fb65 100644
--- a/asciifarm/client/commandhandler.py
+++ b/asciifarm/client/commandhandler.py
@@ -28,7 +28,7 @@ class CommandHandler:
"runinput": self.runInput,
"selectwidget": self.selectWidget,
"selectitem": self.selectItem,
- "inputwithselected": self.actWithSelected,
+ #"inputwithselected": self.actWithSelected,
"use": self.useSelected,
"unuse": self.unUseSelected,
"take": self.takeSelected,
@@ -95,16 +95,16 @@ class CommandHandler:
self.client.inputHandler.startTyping(startText)
def selectWidget(self, value, relative=False, modular=False):
- self.client.display.getWidget("switch").select(value, relative, modular)
+ self.client.switch.select(value, relative, modular)
def selectItem(self, value, relative=False, modular=False):
- self.client.display.getWidget("switch").getSelectedItem().getImpl().select(value, relative, modular)
+ self.client.switch.getSelectedItem()[0].select(value, relative, modular)
- def actWithSelected(self, action, widget):
- self.input([action, self.client.display.getWidget(widget).getSelected()])
+ #def actWithSelected(self, action, widget):
+ #self.input([action, self.client.display.getWidget(widget).getSelected()])
def useSelected(self):
- widget = self.client.display.getWidget("switch").getSelectedItem()
+ widget = self.client.switch.getSelectedItem()
selected = widget.getImpl().getSelected()
if widget.name in ("inventory", "equipment"):
action = "use"
@@ -115,7 +115,7 @@ class CommandHandler:
self.input([action, selected])
def unUseSelected(self):
- widget = self.client.display.getWidget("switch").getSelectedItem()
+ menu = self.client.switch.getSelectedItem()[0]
selected = widget.getImpl().getSelected()
if widget.name == "inventory":
action = "drop"
@@ -126,7 +126,7 @@ class CommandHandler:
self.input([action, selected])
def takeSelected(self):
- widget = self.client.display.getWidget("switch").getSelectedItem()
+ widget = self.client.switch.getSelectedItem()[0]
selected = widget.getImpl().getSelected()
if widget.name == "ground":
action = "take"
diff --git a/asciifarm/client/display/display.py b/asciifarm/client/display/display.py
index edc3f95..80850b3 100644
--- a/asciifarm/client/display/display.py
+++ b/asciifarm/client/display/display.py
@@ -65,8 +65,8 @@ class Display:
self.addWidget(Inventory("Equipment"), "equipment")
- switcher = Switcher([self.widgets["ground"], self.widgets["inventory"], self.widgets["equipment"]], 1)
- self.addWidget(switcher, "switch")
+ #switcher = Switcher([self.widgets["ground"], self.widgets["inventory"], self.widgets["equipment"]], 1)
+ self.addWidget(Inventory(""), "switch")
self.addWidget(Messages(charMap.get("msgcolours", {})), "msg")
self.addWidget(TextInput(), "textinput")
@@ -110,20 +110,20 @@ class Display:
self.getWidget("info").showString(infostring)
- def setInventory(self, items):
- self.getWidget("inventory").setInventory(items)
+ #def setInventory(self, items):
+ #self.getWidget("inventory").setInventory(items)
- def setEquipment(self, slots):
- self.getWidget("equipment").setInventory(
- sorted([
- slot + ": " + (item if item else "")
- for slot, item in slots.items()
- ])
- )
+ #def setEquipment(self, slots):
+ #self.getWidget("equipment").setInventory(
+ #sorted([
+ #slot + ": " + (item if item else "")
+ #for slot, item in slots.items()
+ #])
+ #)
- def setGround(self, items):
- self.getWidget("ground").setInventory(items)
+ #def setGround(self, items):
+ #self.getWidget("ground").setInventory(items)
def addMessage(self, message, type):
diff --git a/asciifarm/client/display/switcher.py b/asciifarm/client/display/switcher.py
index 035aea3..6e64fd0 100644
--- a/asciifarm/client/display/switcher.py
+++ b/asciifarm/client/display/switcher.py
@@ -7,22 +7,22 @@ class Switcher(Inventory):
There is a function to switch between the displayed widgets.
"""
- def __init__(self, widgets, initial=0):
- Inventory.__init__(self, "", "", "=")
- self.setInventory(widgets)
+ #def __init__(self, widgets, initial=0):
+ #Inventory.__init__(self, "", "", "=")
+ #self.setInventory(widgets)
- for wid in widgets:
- wid.hidden = True
+ #for wid in widgets:
+ #wid.hidden = True
- self.select(initial)
+ #self.select(initial)
- def doSelect(self, value):
- self.getSelectedItem().hidden = True
- self.selector = value
- self.change()
- newWid = self.getSelectedItem()
- newWid.hidden = False
- newWid.change()
+ #def doSelect(self, value):
+ #self.getSelectedItem().hidden = True
+ #self.selector = value
+ #self.change()
+ #newWid = self.getSelectedItem()
+ #newWid.hidden = False
+ #newWid.change()
def itemName(self, item):
return item.getImpl().title
diff --git a/asciifarm/client/gameclient.py b/asciifarm/client/gameclient.py
index 2bd5420..46c8553 100644
--- a/asciifarm/client/gameclient.py
+++ b/asciifarm/client/gameclient.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python3
+
import os
import sys
@@ -10,13 +10,16 @@ import argparse
import string
from queue import Queue
+import ratuil.inputs
from .inputhandler import InputHandler
+from .listselector import ListSelector
+from .switchselector import SwitchSelector
class Client:
- def __init__(self, stdscr, display, name, connection, keybindings, logFile=None):
- self.stdscr = stdscr
+ def __init__(self, display, name, connection, keybindings, logFile=None):
+ #self.stdscr = stdscr
self.display = display
self.name = name
self.keepalive = True
@@ -24,6 +27,17 @@ class Client:
self.logFile = logFile
self.closeMessage = None
+ # temporary, until these have a better place
+ self.inventory = ListSelector(self.display.getWidget("inventory"))
+ self.equipment = ListSelector(self.display.getWidget("equipment"))
+ self.ground = ListSelector(self.display.getWidget("ground"))
+ self.switch = SwitchSelector(self.display.getWidget("switch"))
+ #self.switch.setItems([
+ #(self.inventory, None, "Inventory"),
+ #(self.equipment, None, "Equipment"),
+ #(self.ground, None, "Ground")
+ #])
+
self.inputHandler = InputHandler(self, keybindings["actions"])
self.controlsString = keybindings.get("help", "")
@@ -53,9 +67,13 @@ class Client:
self.queue.put(("error", error))
def getInput(self):
+ #try:
while True:
- key = self.stdscr.getch()
+ key = ratuil.inputs.get_key()
+ #key = self.stdscr.getch()
self.queue.put(("input", key))
+ #except Exception as e:
+ #self.queue.put(("error", e))
def close(self, msg=None):
self.keepalive = False
@@ -107,11 +125,23 @@ class Client:
if maxHealth is None:
self.log("You have died. Restart the client to respawn")
if msgType == "inventory":
- self.display.setInventory(msg[1])
+ self.inventory.setItems(msg[1])
+ #invbox = self.display.getWidget("inventory")
+ #invbox.setInventory(self.inventory.items)
+ #invbox.select(self.inventory.selector)
+ #self.display.setInventory(msg[1])
if msgType == "equipment":
- self.display.setEquipment(msg[1])
+ #self.display.setEquipment(msg[1])
+ self.equipment.setItems(msg[1])
+ #eqbox = self.display.getWidget("equipment")
+ #eqbox.setInventory(self.inventory.items)
+ #eqbox.select(self.equipment.selector)
if msgType == "ground":
- self.display.setGround(msg[1])
+ #self.display.setGround(msg[1])
+ self.ground.setItems(msg[1])
+ #grbox = self.display.getWidget("ground")
+ #grbox.setInventory(self.ground.items)
+ #grbox.select(self.ground.selector)
if msgType == "message":
self.log(*msg[1:])
if msgType == "options":
@@ -138,12 +168,19 @@ class Client:
if action[0] == "message":
self.update(action[1])
elif action[0] == "input":
+ if action[1] == "^C":
+ raise KeyboardInterrupt
self.inputHandler.onInput(action[1])
elif action[0] == "error":
raise action[1]
+ elif action[0] == "sigwinch":
+ self.display.update_size()
else:
raise Exception("invalid action in queue")
+ def onSigwinch(self, signum, frame):
+ self.queue.put(("sigwinch", (signum, frame)))
+
diff --git a/asciifarm/client/inputhandler.py b/asciifarm/client/inputhandler.py
index 2d038d2..de420c0 100644
--- a/asciifarm/client/inputhandler.py
+++ b/asciifarm/client/inputhandler.py
@@ -1,9 +1,12 @@
-import curses
-import curses.ascii
+#import curses
+#import curses.ascii
+import string
from .commandhandler import CommandHandler, InvalidCommandException
-from .keynames import nameFromKey
+#from .keynames import nameFromKey
+
+import ratuil.inputs as inp
class InputHandler:
@@ -20,7 +23,7 @@ class InputHandler:
def onInput(self, key):
if not self.typing:
- keyName = nameFromKey(key)
+ keyName = key#nameFromKey(key)
if keyName in self.keybindings:
self.commandHandler.execute(self.keybindings[keyName])
else:
@@ -58,36 +61,36 @@ class InputHandler:
self.client.display.setInputString(self.string, self.cursor if self.typing else -1)
def addKey(self, key):
- if curses.ascii.isprint(key):
- self.string = self.string[:self.cursor] + chr(key) + self.string[self.cursor:]
+ if key in string.printable:#curses.ascii.isprint(key):
+ self.string = self.string[:self.cursor] + key + self.string[self.cursor:]
self.cursor += 1
- elif key == curses.KEY_BACKSPACE or key == curses.ascii.BS or key == curses.ascii.DEL:
+ elif key == inp.BACKSPACE: #== curses.KEY_BACKSPACE or key == curses.ascii.BS or key == curses.ascii.DEL:
self.string = self.string[:self.cursor-1] + self.string[self.cursor:]
self.cursor = max(self.cursor - 1, 0)
- elif key == curses.KEY_RIGHT:
+ elif key == inp.RIGHT:#curses.KEY_RIGHT:
self.cursor = min(self.cursor + 1, len(self.string))
- elif key == curses.KEY_LEFT:
+ elif key == inp.LEFT:#curses.KEY_LEFT:
self.cursor = max(self.cursor - 1, 0)
- elif key == curses.KEY_DC:
+ elif key == inp.DELETE:#curses.KEY_DC:
self.string = self.string[:self.cursor] + self.string[self.cursor+1:]
- elif key == curses.KEY_HOME:
+ elif key == inp.HOME:#curses.KEY_HOME:
self.cursor = 0
- elif key == curses.KEY_END:
+ elif key == inp.END:#curses.KEY_END:
self.cursor = len(self.string)
- elif key == curses.ascii.ESC or key == curses.KEY_DL:
+ elif key == inp.ESCAPE:#curses.ascii.ESC or key == curses.KEY_DL:
# throw away entered string and go back to game
self.typing = False
self.string = ""
self.cursor = 0
- elif key == curses.ascii.LF or key == curses.ascii.CR:
+ elif key == inp.ENTER:#curses.ascii.LF or key == curses.ascii.CR:
# process entered string and reset it
message = self.string
self.string = ""
self.cursor = 0
self.typing = False
self.processString(message)
- elif key == curses.ascii.TAB:
+ elif key == "^I":#curses.ascii.TAB:
# return to game but keep entered string
self.typing = False
diff --git a/asciifarm/client/listselector.py b/asciifarm/client/listselector.py
new file mode 100644
index 0000000..b88b967
--- /dev/null
+++ b/asciifarm/client/listselector.py
@@ -0,0 +1,49 @@
+
+from asciifarm.common import utils
+
+
+class ListSelector:
+
+ def __init__(self, widget):
+ self.widget = widget
+ self.items = []
+ self.selector = 0
+
+ def getSelected(self):
+ return self.selector
+
+ def select(self, value, relative=False, modular=False):
+ invLen = len(self.items)
+ if relative:
+ value += self.selector
+ if modular and invLen:
+ value %= invLen
+ if value < 0:
+ value = 0
+ if value >= invLen:
+ value = invLen-1
+ if value in range(invLen):
+ self.doSelect(value)
+
+ def doSelect(self, value):
+ self.selector = value
+ self.widget.select(value)
+
+ def setItems(self, items):
+ self.items = items
+ self.selector = utils.clamp(self.selector, 0, len(items)-1)
+ self.widget.set_items([self.itemName(item) for item in self.items])
+ self.widget.select(self.selector)
+
+ def getItem(self, num):
+ return self.items[num]
+
+ def getSelectedItem(self):
+ return self.getItem(self.getSelected())
+
+ def getNumItems(self):
+ return len(self.items)
+
+ def itemName(self, item):
+ return item
+
diff --git a/asciifarm/client/main.py b/asciifarm/client/main.py
index c00b592..b16d252 100644
--- a/asciifarm/client/main.py
+++ b/asciifarm/client/main.py
@@ -1,13 +1,17 @@
#! /usr/bin/python3
-import curses
+
import json
-import os
-import getpass
+
import sys
+import termios
+import tty
+import signal
+
from .connection import Connection
from .gameclient import Client
-from .display.display import Display
+from .newdisplay.display import Display
from .parseargs import parse_args
+from ratuil.screen import Screen
def main(argv=None):
@@ -24,33 +28,40 @@ def main(argv=None):
error = None
closeMessage = None
- os.environ.setdefault("ESCDELAY", "25")
+ #os.environ.setdefault("ESCDELAY", "25")
+
+ fd = sys.stdin.fileno()
+ oldterm = termios.tcgetattr(fd)
try:
# Initialize curses
- stdscr = curses.initscr()
+ #stdscr = curses.initscr()
# Turn off echoing of keys, and enter cbreak mode,
# where no buffering is performed on keyboard input
- curses.noecho()
- curses.cbreak()
+ #curses.noecho()
+ #curses.cbreak()
- # In keypad mode, escape sequences for special keys
- # (like the cursor keys) will be interpreted and
- # a special value like curses.KEY_LEFT will be returned
- stdscr.keypad(1)
+ ## In keypad mode, escape sequences for special keys
+ ## (like the cursor keys) will be interpreted and
+ ## a special value like curses.KEY_LEFT will be returned
+ #stdscr.keypad(1)
# Start color, too. Harmless if the terminal doesn't have
# color; user can test with has_color() later on. The try/catch
# works around a minor bit of over-conscientiousness in the curses
# module -- the error return from C start_color() is ignorable.
- try:
- curses.start_color()
- except:
- pass
+ #try:
+ #curses.start_color()
+ #except:
+ #pass
+
+ tty.setraw(sys.stdin)
+ Screen.default.hide_cursor()
- display = Display(stdscr, characters, colours)
- client = Client(stdscr, display, name, connection, keybindings, logfile)
+ display = Display(characters)
+ client = Client(display, name, connection, keybindings, logfile)
+ signal.signal(signal.SIGWINCH, client.onSigwinch)
try:
client.start()
except KeyboardInterrupt:
@@ -61,12 +72,14 @@ def main(argv=None):
error = e
closeMessage = client.closeMessage
finally:
- # Set everything back to normal
- if 'stdscr' in locals():
- stdscr.keypad(0)
- curses.echo()
- curses.nocbreak()
- curses.endwin()
+ ## Set everything back to normal
+ #if 'stdscr' in locals():
+ #stdscr.keypad(0)
+ #curses.echo()
+ #curses.nocbreak()
+ #curses.endwin()
+ termios.tcsetattr(fd, termios.TCSADRAIN, oldterm)
+ Screen.default.finalize()
if error is not None:
diff --git a/asciifarm/client/newdisplay/__init__.py b/asciifarm/client/newdisplay/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/asciifarm/client/newdisplay/__init__.py
diff --git a/asciifarm/client/newdisplay/display.py b/asciifarm/client/newdisplay/display.py
new file mode 100644
index 0000000..66f89ca
--- /dev/null
+++ b/asciifarm/client/newdisplay/display.py
@@ -0,0 +1,174 @@
+
+
+
+import os
+from ratuil.layout import Layout
+from ratuil.bufferedscreen import BufferedScreen as Screen
+#from ratuil.screen import Screen
+from ratuil.textstyle import TextStyle
+from asciifarm.common.utils import get
+
+
+SIDEWIDTH = 20
+
+ALPHABET = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
+
+class Display:
+
+ def __init__(self, charMap):
+
+ self.characters = {}
+
+ def parseSprite(sprite):
+ if isinstance(sprite, str):
+ return (sprite, None, None)
+ char = get(sprite, 0, " ")
+ fg = get(sprite, 1)
+ bg = get(sprite, 2)
+ return (char, fg, bg)
+ for name, sprite in charMap["mapping"].items():
+ vals = parseSprite(sprite)
+ if vals:
+ self.characters[name] = vals
+
+ for name, colours in charMap.get("writable", {}).items():
+ fg = get(colours, 0)
+ bg = get(colours, 1)
+ for i in range(min(len(ALPHABET), len(charMap.get("alphabet", [])))):
+ self.characters[name + '-' + ALPHABET[i]] = (charMap["alphabet"][i], fg, bg)
+
+ self.defaultChar = parseSprite(charMap.get("default", "?"))
+
+ self.messageColours = charMap.get("msgcolours", {})
+
+ fname = os.path.join(os.path.dirname(__file__), "layout.xml")
+ with open(fname) as f:
+ layouttext = f.read()
+
+ self.layout = Layout(layouttext)
+ self.layout.get("field").set_char_size(charMap.get("charwidth", 1))
+
+ self.screen = Screen()
+ self.screen.clear()
+
+ self.layout.set_target(self.screen)
+ self.layout.update()
+
+
+ #screen = Screen(self, stdscr, self.colours)
+ #self.screen = screen
+
+ #self.widgets = {}
+
+ #self.addWidget(Field((1, 1), charMap.get("charwidth", 1), self.colours), "field")
+ #self.addWidget(Info(), "info")
+ #self.addWidget(Health(
+ #charMap.get("healthfull", ("@",7, 2)),
+ #charMap.get("healthempty", ("-",7, 1))
+ #),
+ #"health")
+ #self.addWidget(Inventory("Inventory"), "inventory")
+ #self.addWidget(Inventory("Ground"), "ground")
+ #self.addWidget(Inventory("Equipment"), "equipment")
+
+
+ ##switcher = Switcher([self.widgets["ground"], self.widgets["inventory"], self.widgets["equipment"]], 1)
+ #self.addWidget(Inventory(""), "switch")
+ #self.addWidget(Messages(charMap.get("msgcolours", {})), "msg")
+ #self.addWidget(TextInput(), "textinput")
+
+ #self.forced = False
+
+ #def addWidget(self, w, name, winname=None):
+ #if not winname:
+ #winname = name
+ #widget = Widget(w, name)
+ #self.widgets[name] = widget
+ #widget.setWin(winname, self.screen)
+
+ def getWidget(self, name):
+ return self.layout.get(name)
+ #if name in self.widgets:
+ #return self.widgets[name].getImpl()
+ #else:
+ #return None
+
+ def resizeField(self, size):
+ self.getWidget("field").set_size(*size)
+ #self.forced = True
+
+ def drawFieldCells(self, cells):
+ field = self.getWidget("field")
+ for cell in cells:
+ (x, y), spriteNames = cell
+ if not len(spriteNames):
+ char, fg, bg = self.getChar(0)
+ else:
+ char, fg, bg = self.getChar(spriteNames[0])
+ for spriteName in spriteNames[1:]:
+ if bg is not None:
+ break
+ _char, _fg, bg = self.getChar(spriteName)
+ field.change_cell(x, y, char, TextStyle(fg, bg))
+
+
+ def setFieldCenter(self, pos):
+ self.getWidget("field").set_center(*pos)
+
+ def setHealth(self, health, maxHealth):
+ self.getWidget("health").set_total(maxHealth)
+ self.getWidget("health").set_filled(health)
+
+
+ def showInfo(self, infostring):
+ pass
+ #self.getWidget("info").showString(infostring)
+
+
+ #def setInventory(self, items):
+ #self.getWidget("inventory").setInventory(items)
+
+
+ #def setEquipment(self, slots):
+ #self.getWidget("equipment").setInventory(
+ #sorted([
+ #slot + ": " + (item if item else "")
+ #for slot, item in slots.items()
+ #])
+ #)
+
+ #def setGround(self, items):
+ #self.getWidget("ground").setInventory(items)
+
+
+ def addMessage(self, message, type):
+ self.getWidget("msg").add_message(message, TextStyle(*self.messageColours.get(type, (7,0))))
+
+ def scrollBack(self, amount, relative=True):
+ self.getWidget("msg").scroll(amount, relative)
+
+ def setInputString(self, string, cursor):
+ self.getWidget("textinput").set_text(string, cursor)
+
+ def update(self):
+ self.layout.update()
+ self.screen.update()
+ #changed = False
+ #for widget in self.widgets.values():
+ #if self.forced or widget.isChanged():
+ #widget.update()
+ #changed = True
+ #if changed:
+ #self.screen.update()
+ #self.forced = False
+
+ #def forceUpdate(self):
+ #self.forced = True
+
+ def getChar(self, sprite):
+ """This returns the character belonging to some spritename. This does not read a character"""
+ return self.characters.get(sprite, self.defaultChar)
+
+ def update_size(self):
+ self.screen.reset()
+
diff --git a/asciifarm/client/newdisplay/layout.xml b/asciifarm/client/newdisplay/layout.xml
new file mode 100644
index 0000000..c7e274c
--- /dev/null
+++ b/asciifarm/client/newdisplay/layout.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<hbox>
+ <vbox width="20" align="right">
+ <bar id="health" height="2" full-char="+" empty-char="-" full-style="fg:1; bg:2" empty-style="fg:2; bg: 1;"></bar>
+ <switchbox id="switch">
+ <listing id="inventory">
+ milk
+ eggs
+ bread
+ </listing>
+ <listing id="equipment">
+ cotton underwear
+ cotton shirt
+ jeans
+ friendship bracelet
+ </listing>
+ <listing id="ground">
+ concrete
+ </listing>
+ </switchbox>
+ <textbox id="info"></textbox>
+ </vbox>
+ <vbox>
+ <textinput id="textinput" align="bottom" height="1">hello</textinput>
+ <log id="msg" align="bottom" height="20%%">
+ Welcome to asciifarm
+ </log>
+ <field id="field" char-size="1"></field>
+ </vbox>
+</hbox>
diff --git a/asciifarm/client/switchselector.py b/asciifarm/client/switchselector.py
new file mode 100644
index 0000000..dfc18a7
--- /dev/null
+++ b/asciifarm/client/switchselector.py
@@ -0,0 +1,33 @@
+
+
+from .listselector import ListSelector
+
+class SwitchSelector(ListSelector):
+
+
+
+ def setItems(self, items):
+ super().setItems(items)
+ self.updateVisibility()
+
+ def updateVisibility(self):
+ pass
+ #for i, (_menu, widget, _title) in enumerate(self.items):
+ #if i == self.selector:
+ #widget.hidden = False
+ #widget.change()
+ #else:
+ #widget.hidden = True
+
+ def doSelect(self, value):
+
+ #self.getSelectedItem().widget.hidden = True
+ super().doSelect(value)
+ self.updateVisibility()
+ #self.getSelectedItem().widimp.change()
+ #newWid.hidden = False
+ #newWid.change()
+
+ def itemName(self, item):
+ _menu, _widget, title = item
+ return title