Code: Alles auswählen
#!/usr/bin/env python
import Tkinter
from Tkconstants import *
import tkMessageBox
import sys
class Main:
def __init__(self):
self.dung = Dungeon(self)
self.mainwin = MainWindow(self)
self.dung.getFields()
self.evhdl = EventHandler(self)
a = ("<Left>", "<Down>", "<Right>", "<Up>", "<o>", "<c>", "<Escape>")
for i in a:
self.evhdl.bindKey(self.mainwin.mw, i)
del a
self.party = Party(self)
self.arrow = Arrow(self)
self.party.doLook()
self.party.checkBeen()
self.mainwin.runMainLoop()
class MainWindow:
def __init__(self, main):
self.main = main
self.clearjob = None
self.hlinel = 50
self.vlinel = self.hlinel * 3 / 4
self.hborder = 200
self.vborder = 150
# self.winwidth = self.main.dung.dungrow * self.hlinel + 2 * self.hborder
self.winwidth = 450
self.winheight = self.winwidth * 3 / 4
self.xscroll = 25
self.yscroll = int(self.xscroll * 3 / 4)
self.scrollincrement = 2
self.mw = Tkinter.Tk()
self.mw.title("Dungeon")
# self.mw.option_add("*font", "Arial 15 normal")
self.mw.geometry("+250+200")
self.cv = Tkinter.Canvas(self.mw,
bg = "white",
width = self.winwidth,
height = self.winheight,
xscrollincrement = self.scrollincrement,
yscrollincrement = self.scrollincrement)
self.cv.pack()
self.sbar = StatusBar(self.mw)
self.sbar.pack(side = BOTTOM, fill = BOTH)
def scrollCanvas(self, movedir):
if movedir == 0:
self.cv.xview_scroll(-self.xscroll, what = "units")
if movedir == 1:
self.cv.yview_scroll(-self.yscroll, what = "units")
if movedir == 2:
self.cv.xview_scroll(self.xscroll, what = "units")
if movedir == 3:
self.cv.yview_scroll(self.yscroll, what = "units")
def runMainLoop(self):
self.mw.after(50, self.showInstructions)
self.mw.mainloop()
def showInstructions(self):
a = 'Welcome to the dungeon.\n\nUse the cursor-keys to turn around and walk.\n\nPress "o" to open a door and "c" to close it again.\n\nYou can use "Esc" to exit.\n'
tkMessageBox.showinfo("Instructions", a)
def show(self, text):
try:
self.mw.after_cancle(self.clearjob)
except:
pass
self.sbar.set(text)
self.clearjob = self.mw.after(ms = 1500, func = self.sbar.clear)
class EventHandler:
def __init__(self, main):
self.main = main
def bindKey(self, widget, key):
widget.bind(sequence = key, func = self.bindFunc)
def bindFunc(self, a):
key = a.keysym
if key == "Left":
self.main.party.turnLeft()
if key == "Right":
self.main.party.turnRight()
if key == "Down":
self.main.party.turnAround()
if key == "Up":
self.main.party.moveForward()
if key == "o":
self.main.party.manipulateDoor(3)
if key == "c":
self.main.party.manipulateDoor(2)
if key == "Escape":
self.main.mainwin.mw.destroy()
class Arrow:
def __init__(self, main):
self.main = main
self.arrowdir = self.getArrowDirection()
self.arrow = self.drawArrow()
def updateArrow(self):
if self.arrow:
self.main.mainwin.cv.delete(self.arrow)
self.arrowdir = self.getArrowDirection()
self.arrow = self.drawArrow()
def drawArrow(self):
coords = self.getArrowCoordinates()
if self.main.party.dir == 0 or self.main.party.dir == 2:
nr = 0
else:
nr = 1
arrow = self.main.mainwin.cv.create_line(coords[nr][0], coords[nr][1], coords[nr][2], coords[nr][3], arrow = self.arrowdir)
return arrow
def getArrowCoordinates(self):
# x and y are the coordinates of the down-left-corner of a field.
x = self.main.party.partyfield.nr % self.main.dung.dungrow * self.main.mainwin.hlinel + self.main.mainwin.hborder
y = self.main.mainwin.winheight - self.main.mainwin.vborder - self.main.party.partyfield.nr // self.main.dung.dungrow * self.main.mainwin.vlinel
coords = ((x + self.main.mainwin.hlinel / 4, y - self.main.mainwin.vlinel / 2, x + self.main.mainwin.hlinel * 3 / 4, y - self.main.mainwin.vlinel / 2), (x + self.main.mainwin.hlinel / 2, y - self.main.mainwin.vlinel / 4, x + self.main.mainwin.hlinel / 2, y - self.main.mainwin.vlinel * 3 / 4))
return coords
def getArrowDirection(self):
if self.main.party.dir == 1 or self.main.party.dir == 2:
arrowdir = LAST
else:
arrowdir = FIRST
return arrowdir
class Dungeon:
def __init__(self, main):
self.main = main
self.dungrow = 5
self.dungdesc = ["1101", "0101", "0001", "0101", "0011",
"1001", "0211", "1010", "1011", "1110",
"1010", "1112", "1010", "1120", "2011",
"1000", "0101", "0000", "0101", "0010",
"1100", "0111", "1110", "1121", "2110"]
self.fields = []
def getFields(self):
for i in range(len(self.dungdesc)):
self.fields.append(Field(self, self.main, i, self.dungdesc[i]))
class Field:
def __init__(self, dung, main, nr, description):
self.main = main
self.nr = nr
self.description = description
# x and y are the coordinates of the down-left-corner of a field.
self.x = self.nr % dung.dungrow * self.main.mainwin.hlinel + self.main.mainwin.hborder
self.y = self.main.mainwin.winheight - self.main.mainwin.vborder - self.nr // dung.dungrow * self.main.mainwin.vlinel
self.drawings = []
self.grey = self.hideField()
def drawField(self):
coords = ((self.x, self.y, self.x, self.y - self.main.mainwin.vlinel),
(self.x, self.y - self.main.mainwin.vlinel, self.x + self.main.mainwin.hlinel, self.y - self.main.mainwin.vlinel),
(self.x + self.main.mainwin.hlinel, self.y, self.x + self.main.mainwin.hlinel, self.y - self.main.mainwin.vlinel),
(self.x, self.y, self.x + self.main.mainwin.hlinel, self.y))
opts = (('black', None),
('red', None),
('green', 'gray50'))
for u in range(3):
for i in range(4):
if self.description[i] == str(u + 1):
self.drawings.append(self.main.mainwin.cv.create_line(coords[i][0], coords[i][1], coords[i][2], coords[i][3], fill = opts[u][0], stipple = opts[u][1]))
def hideField(self):
a = self.main.mainwin.cv.create_rectangle(self.x, self.y, self.x + self.main.mainwin.hlinel, self.y - self.main.mainwin.vlinel, outline = 'grey', fill = 'grey')
return a
def revealField(self):
self.main.mainwin.cv.delete(self.grey)
self.drawField()
self.grey = None
def clearField(self):
if len(self.drawings) > 0:
for i in self.drawings:
self.main.mainwin.cv.delete(i)
self.drawings = []
def changeDescription(self, pos, to):
a = []
for i in self.description:
a.append(i)
a[pos] = to
self.description = "".join(a)
class Party:
def __init__(self, main):
self.main = main
self.pos = 0
self.dir = 2
self.sight = 1
self.partyfield = self.main.dung.fields[self.pos]
self.been = []
self.hastreasure = False
self.stepsfound = False
def turnLeft(self):
self.dir -= 1
if self.dir < 0:
self.dir = 3
self.updatePosition()
def turnRight(self):
self.dir += 1
if self.dir > 3:
self.dir = 0
self.updatePosition()
def turnAround(self):
self.dir = self.counterDirection()
self.updatePosition()
def moveForward(self):
fieldside = int(self.partyfield.description[self.dir])
if fieldside == 0 or fieldside == 3:
self.pos = self.fieldAhead()
self.partyfield = self.main.dung.fields[self.pos]
self.main.mainwin.scrollCanvas(self.dir)
if fieldside == 1:
self.main.mainwin.show("Ouch: Wall.")
if fieldside == 2:
self.main.mainwin.show("Ouch: Locked Door.")
self.updatePosition()
def doLook(self):
for i in range(self.sight):
if self.fieldAhead(i) == -1:
break
fieldside = self.main.dung.fields[self.fieldAhead(i)].description[self.dir]
fieldside = int(fieldside)
if self.main.dung.fields[self.fieldAhead(i)].grey:
self.main.dung.fields[self.fieldAhead(i)].revealField()
if fieldside == 1 or fieldside == 2:
break
def manipulateDoor(self, a):
fieldside = int(self.partyfield.description[self.dir])
if a == 3 and fieldside != 2:
return
if a == 2 and fieldside != 3:
return
self.partyfield.changeDescription(self.dir, str(a))
self.main.dung.fields[self.fieldAhead()].changeDescription(self.counterDirection(), str(a))
self.partyfield.clearField()
self.partyfield.drawField()
self.main.dung.fields[self.fieldAhead()].clearField()
self.main.dung.fields[self.fieldAhead()].drawField()
if a == 3:
self.main.mainwin.show("Door opened !")
if a == 2:
self.main.mainwin.show("Door closed again.")
def updatePosition(self):
self.doLook()
self.main.arrow.updateArrow()
# print self.pos
if self.pos == 8 and not self.hastreasure:
tkMessageBox.showinfo("Treasure !", "You found a valuable treasure !\n")
self.hastreasure = True
if self.pos == 11 and not self.stepsfound:
tkMessageBox.showinfo("Stairs", "\nThere are stairs here leading down.\n\nBut, alas, the way is blocked.\n\n")
self.stepsfound = True
self.checkBeen()
def checkBeen(self):
if self.pos not in self.been:
self.been.append(self.pos)
if len(self.been) == len(self.main.dung.fields):
if tkMessageBox.askyesno(title = 'Dungeon explored', message = "Congratulations !\n\nYou've explored the whole dungeon !\n\nDo you want to quit now ?\n"):
self.main.mainwin.mw.destroy()
sys.exit()
else:
self.been = []
def fieldAhead(self, step = 1):
# Returns the fieldnumber of fields in the neighbourhood,
# in the given direction or -1 if the field is out of range.
a = (self.pos - step,
self.pos + self.main.dung.dungrow * step,
self.pos + step,
self.pos - self.main.dung.dungrow * step)
for i in range(4):
if self.dir == i:
if i < 2 and a[i] < 0:
return -1
if i > 1 and a[i] >= self.main.dung.dungrow ** 2:
return -1
return a[i]
def counterDirection(self):
if self.dir < 2:
return self.dir + 2
if self.dir > 1:
return self.dir - 2
class StatusBar(Tkinter.Frame):
def __init__(self, master):
Tkinter.Frame.__init__(self, master)
self.sbartext = Tkinter.Variable()
self.label = Tkinter.Label(self,
bd = 1,
anchor = W,
textvariable = self.sbartext)
self.label.pack(side = LEFT, fill = BOTH)
self.button = Tkinter.Button(self,
text = "Exit",
command = master.destroy)
self.button.pack(side = RIGHT)
self.button.focus()
def set(self, format):
self.sbartext.set(format)
def clear(self):
self.sbartext.set("")
if __name__ == "__main__":
app = Main()